Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH] iio: stm32-dac: Replace indio_dev->mlock with own device lock
From: Jonathan Cameron @ 2020-05-16 15:35 UTC (permalink / raw)
  To: Sergiu Cuciurean
  Cc: Lars-Peter Clausen, Peter Meerwald-Stadler, linux-iio,
	linux-kernel, Maxime Coquelin, Hartmut Knaack, Fabrice Gasnier,
	linux-stm32, linux-arm-kernel, Alexandre Torgue
In-Reply-To: <20200514085018.79948-1-sergiu.cuciurean@analog.com>

On Thu, 14 May 2020 11:50:12 +0300
Sergiu Cuciurean <sergiu.cuciurean@analog.com> wrote:

> As part of the general cleanup of indio_dev->mlock, this change replaces
> it with a local lock on the device's state structure.
> 
> Signed-off-by: Sergiu Cuciurean <sergiu.cuciurean@analog.com>
> ---
>  drivers/iio/dac/stm32-dac.c | 12 ++++++++----
>  1 file changed, 8 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iio/dac/stm32-dac.c b/drivers/iio/dac/stm32-dac.c
> index f22c1d9129b2..74b9474c8590 100644
> --- a/drivers/iio/dac/stm32-dac.c
> +++ b/drivers/iio/dac/stm32-dac.c
> @@ -26,9 +26,11 @@
>  /**
>   * struct stm32_dac - private data of DAC driver
>   * @common:		reference to DAC common data
> + * @lock: lock to protect the data buffer during regmap ops

In this particular case I'm not sure that's what mlock was being used for.
I think it's about avoiding races around checking if powered down and
actually doing it.


>   */
>  struct stm32_dac {
>  	struct stm32_dac_common *common;
> +	struct mutex		lock;
>  };
>  
>  static int stm32_dac_is_enabled(struct iio_dev *indio_dev, int channel)
> @@ -58,10 +60,10 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
>  	int ret;
>  
>  	/* already enabled / disabled ? */
> -	mutex_lock(&indio_dev->mlock);
> +	mutex_lock(&dac->lock);
>  	ret = stm32_dac_is_enabled(indio_dev, ch);
>  	if (ret < 0 || enable == !!ret) {
> -		mutex_unlock(&indio_dev->mlock);
> +		mutex_unlock(&dac->lock);
>  		return ret < 0 ? ret : 0;
>  	}
>  
> @@ -69,13 +71,13 @@ static int stm32_dac_set_enable_state(struct iio_dev *indio_dev, int ch,
>  		ret = pm_runtime_get_sync(dev);
>  		if (ret < 0) {
>  			pm_runtime_put_noidle(dev);
> -			mutex_unlock(&indio_dev->mlock);
> +			mutex_unlock(&dac->lock);
>  			return ret;
>  		}
>  	}
>  
>  	ret = regmap_update_bits(dac->common->regmap, STM32_DAC_CR, msk, en);
> -	mutex_unlock(&indio_dev->mlock);
> +	mutex_unlock(&dac->lock);
>  	if (ret < 0) {
>  		dev_err(&indio_dev->dev, "%s failed\n", en ?
>  			"Enable" : "Disable");
> @@ -328,6 +330,8 @@ static int stm32_dac_probe(struct platform_device *pdev)
>  	indio_dev->info = &stm32_dac_iio_info;
>  	indio_dev->modes = INDIO_DIRECT_MODE;
>  
> +	mutex_init(&dac->lock);
> +
>  	ret = stm32_dac_chan_of_init(indio_dev);
>  	if (ret < 0)
>  		return ret;


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

^ permalink raw reply

* Re: [RESEND,v2,1/1] arm: dts: mediatek: add mt7629 pwm support
From: Matthias Brugger @ 2020-05-16 15:37 UTC (permalink / raw)
  To: Sam Shih, Rob Herring, Mark Rutland
  Cc: devicetree, linux-mediatek, linux-kernel, linux-arm-kernel
In-Reply-To: <1581474926-28633-2-git-send-email-sam.shih@mediatek.com>



On 12/02/2020 03:35, Sam Shih wrote:
> This adds pwm support for MT7629.
> Used:
> https://patchwork.kernel.org/patch/11160851/
> 
> Change since v1:
> remove unused property num-pwm
> 
> Signed-off-by: Sam Shih <sam.shih@mediatek.com>

Applied now to v5.7-next/dts32

Thanks!

> ---
>  arch/arm/boot/dts/mt7629.dtsi | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/mt7629.dtsi b/arch/arm/boot/dts/mt7629.dtsi
> index 867b88103b9d..ce2a30a24017 100644
> --- a/arch/arm/boot/dts/mt7629.dtsi
> +++ b/arch/arm/boot/dts/mt7629.dtsi
> @@ -241,6 +241,20 @@
>  			status = "disabled";
>  		};
>  
> +		pwm: pwm@11006000 {
> +			compatible = "mediatek,mt7629-pwm";
> +			reg = <0x11006000 0x1000>;
> +			interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_LOW>;
> +			clocks = <&topckgen CLK_TOP_PWM_SEL>,
> +				 <&pericfg CLK_PERI_PWM_PD>,
> +				 <&pericfg CLK_PERI_PWM1_PD>;
> +			clock-names = "top", "main", "pwm1";
> +			assigned-clocks = <&topckgen CLK_TOP_PWM_SEL>;
> +			assigned-clock-parents =
> +					<&topckgen CLK_TOP_UNIVPLL2_D4>;
> +			status = "disabled";
> +		};
> +
>  		i2c: i2c@11007000 {
>  			compatible = "mediatek,mt7629-i2c",
>  				     "mediatek,mt2712-i2c";
> 

_______________________________________________
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/13] mailbox: cmdq: support mt6779 gce platform definition
From: Matthias Brugger @ 2020-05-16 16:10 UTC (permalink / raw)
  To: Dennis YC Hsieh, Rob Herring, Mark Rutland, Jassi Brar,
	Philipp Zabel, David Airlie, Daniel Vetter
  Cc: devicetree, wsd_upstream, linux-kernel, dri-devel, HS Liao,
	linux-mediatek, Houlong Wei, Bibby Hsieh, CK Hu, linux-arm-kernel
In-Reply-To: <1583664775-19382-4-git-send-email-dennis-yc.hsieh@mediatek.com>



On 08/03/2020 11:52, Dennis YC Hsieh wrote:
> Add gce v4 hardware support with different thread number and shift.
> 
> Signed-off-by: Dennis YC Hsieh <dennis-yc.hsieh@mediatek.com>
> Reviewed-by: CK Hu <ck.hu@mediatek.com>

Reviewed-by: Matthias Brugger <matthias.bgg@gmail.com>

> ---
>  drivers/mailbox/mtk-cmdq-mailbox.c | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
> index 4dbee9258127..9994ac9426d6 100644
> --- a/drivers/mailbox/mtk-cmdq-mailbox.c
> +++ b/drivers/mailbox/mtk-cmdq-mailbox.c
> @@ -572,10 +572,12 @@ static const struct dev_pm_ops cmdq_pm_ops = {
>  
>  static const struct gce_plat gce_plat_v2 = {.thread_nr = 16};
>  static const struct gce_plat gce_plat_v3 = {.thread_nr = 24};
> +static const struct gce_plat gce_plat_v4 = {.thread_nr = 24, .shift = 3};
>  
>  static const struct of_device_id cmdq_of_ids[] = {
>  	{.compatible = "mediatek,mt8173-gce", .data = (void *)&gce_plat_v2},
>  	{.compatible = "mediatek,mt8183-gce", .data = (void *)&gce_plat_v3},
> +	{.compatible = "mediatek,mt6779-gce", .data = (void *)&gce_plat_v4},
>  	{}
>  };
>  
> 

_______________________________________________
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/4] arm64: Extract kprobes_save_local_irqflag() and kprobes_restore_local_irqflag()
From: Doug Anderson @ 2020-05-16 16:17 UTC (permalink / raw)
  To: liwei (GF)
  Cc: Mark Rutland, Daniel Thompson, Catalin Marinas, Marc Zyngier,
	LKML, liwei1412, Masami Hiramatsu, Jason Wessel, Will Deacon,
	David Miller, Linux ARM
In-Reply-To: <d5bb9ccf-6047-13d9-45b3-18421629e83f@huawei.com>

Hi,

On Sat, May 16, 2020 at 1:47 AM liwei (GF) <liwei391@huawei.com> wrote:
>
> >> -               kprobes_save_local_irqflag(kcb, regs);
> >> +               kernel_prepare_single_step(&kcb->saved_irqflag, regs);
> >
> > Is there some reason to have two functions?  It seems like every time
> > you call kernel_enable_single_step() you'd want to call
> > kernel_prepare_single_step().  ...and every time you call
> > kernel_disable_single_step() you'd want to call
> > kernel_cleanup_single_step().
> >
> > Maybe you can just add the flags parameter to
> > kernel_enable_single_step() / kernel_disable_single_step() and put the
> > code in there?
> >
>
> As kernel_enable_single_step() / kernel_disable_single_step() are also called in
> breakpoint_handler() and watchpoint_handler(), i am not sure it's a right thing
> to put the daif flag prepare/cleanup into them, especially we don't have a context
> to save the flags.

I think you misunderstood what I was suggesting.  Maybe better with
examples?  I was suggesting doing this:

kcb->saved_irqflag = kernel_enable_single_step(regs);
...
kernel_disable_single_step(kcb->saved_irqflag, regs);

To me that seems better than what you have now:

kcb->saved_irqflag = kernel_prepare_single_step(regs);
kernel_enable_single_step(regs);
...
kernel_cleanup_single_step(kcb->saved_irqflag, regs);
kernel_disable_single_step();

...or am I confused?

-Doug

_______________________________________________
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/2] arm: dts: mt7623: add Mali-450 device node
From: Matthias Brugger @ 2020-05-16 16:22 UTC (permalink / raw)
  To: ryder.lee, Rob Herring
  Cc: devicetree, Ryder Lee, Sean Wang, Weijie Gao, linux-kernel,
	linux-mediatek, linux-arm-kernel
In-Reply-To: <af7b5a2e00eb3a4b6262807c378e43afd5f74779.1563867856.git.ryder.lee@mediatek.com>



On 24/07/2019 11:00, ryder.lee@kernel.org wrote:
> From: Ryder Lee <ryder.lee@mediatek.com>
> 
> Add a node for Mali-450.
> 
> Signed-off-by: Sean Wang <sean.wang@mediatek.com>
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>

Applied to v5.7-next/dts32

> ---
> kmscube as well as X11 EGL tests work fine (use Lima driver).
> ---
>  arch/arm/boot/dts/mt7623.dtsi | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/mt7623.dtsi b/arch/arm/boot/dts/mt7623.dtsi
> index a79f0b6c3429..6a9c5afb9a36 100644
> --- a/arch/arm/boot/dts/mt7623.dtsi
> +++ b/arch/arm/boot/dts/mt7623.dtsi
> @@ -3,6 +3,7 @@
>   * Copyright (c) 2017-2018 MediaTek Inc.
>   * Author: John Crispin <john@phrozen.org>
>   *	   Sean Wang <sean.wang@mediatek.com>
> + *	   Ryder Lee <ryder.lee@mediatek.com>
>   *
>   */
>  
> @@ -733,6 +734,30 @@
>  		#reset-cells = <1>;
>  	};
>  
> +	mali: gpu@13040000 {
> +		compatible = "mediatek,mt7623-mali", "arm,mali-450";
> +		reg = <0 0x13040000 0 0x30000>;
> +		interrupts = <GIC_SPI 170 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 171 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 172 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 173 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 174 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 175 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 176 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 177 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 178 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 179 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 180 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-names = "gp", "gpmmu", "pp0", "ppmmu0", "pp1",
> +				  "ppmmu1", "pp2", "ppmmu2", "pp3", "ppmmu3",
> +				  "pp";
> +		clocks = <&topckgen CLK_TOP_MMPLL>,
> +			 <&g3dsys CLK_G3DSYS_CORE>;
> +		clock-names = "bus", "core";
> +		power-domains = <&scpsys MT2701_POWER_DOMAIN_MFG>;
> +		resets = <&g3dsys MT2701_G3DSYS_CORE_RST>;
> +	};
> +
>  	mmsys: syscon@14000000 {
>  		compatible = "mediatek,mt7623-mmsys",
>  			     "mediatek,mt2701-mmsys",
> 

_______________________________________________
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] dt-bindings: gpu: mali-utgard: add mediatek, mt7623-mali compatible
From: Matthias Brugger @ 2020-05-16 16:22 UTC (permalink / raw)
  To: ryder.lee, Rob Herring
  Cc: devicetree, Ryder Lee, Sean Wang, Weijie Gao, linux-kernel,
	linux-mediatek, linux-arm-kernel
In-Reply-To: <efeadefe3895bcadf1d2e9847b82206dd8c7ec35.1563867856.git.ryder.lee@mediatek.com>



On 24/07/2019 11:01, ryder.lee@kernel.org wrote:
> From: Sean Wang <sean.wang@mediatek.com>
> 
> The MediaTek MT7623 SoC contains a Mali-450, so add a compatible for it
> and define its own vendor-specific properties.
> 
> Signed-off-by: Sean Wang <sean.wang@mediatek.com>
> Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
> Reviewed-by: Rob Herring <robh@kernel.org>

I ported the changes to the new yaml file and applied them to v5.7-next/dts32

Thanks

> ---
>  Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
> index ae63f09fda7d..73021e2dda25 100644
> --- a/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
> +++ b/Documentation/devicetree/bindings/gpu/arm,mali-utgard.txt
> @@ -17,6 +17,7 @@ Required properties:
>        + amlogic,meson8b-mali
>        + amlogic,meson-gxbb-mali
>        + amlogic,meson-gxl-mali
> +      + mediatek,mt7623-mali
>        + rockchip,rk3036-mali
>        + rockchip,rk3066-mali
>        + rockchip,rk3188-mali
> @@ -88,6 +89,10 @@ to specify one more vendor-specific compatible, among:
>      Required properties:
>        * resets: phandle to the reset line for the GPU
>  
> +  - mediatek,mt7623-mali
> +     Required properties:
> +      * resets: phandle to the reset line for the GPU
> +
>    - Rockchip variants:
>      Required properties:
>        * resets: phandle to the reset line for the GPU
> 

_______________________________________________
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] iio: adc: exynos: Simplify Exynos7-specific init
From: Jonathan Cameron @ 2020-05-16 16:37 UTC (permalink / raw)
  To: Alim Akhtar
  Cc: 'Lars-Peter Clausen', linux-iio, linux-kernel,
	'Krzysztof Kozlowski', linux-samsung-soc,
	'Kukjin Kim', 'Peter Meerwald-Stadler',
	'Hartmut Knaack', linux-arm-kernel
In-Reply-To: <037501d627b8$56f06870$04d13950$@samsung.com>

On Mon, 11 May 2020 22:49:28 +0530
"Alim Akhtar" <alim.akhtar@samsung.com> wrote:

> Hello Krzysztof,
> Thanks for the patch.
> 
> > -----Original Message-----
> > From: Krzysztof Kozlowski <krzk@kernel.org>
> > Sent: 11 May 2020 14:04
> > To: Jonathan Cameron <jic23@kernel.org>; Hartmut Knaack
> > <knaack.h@gmx.de>; Lars-Peter Clausen <lars@metafoo.de>; Peter Meerwald-
> > Stadler <pmeerw@pmeerw.net>; Kukjin Kim <kgene@kernel.org>; Krzysztof
> > Kozlowski <krzk@kernel.org>; linux-iio@vger.kernel.org; linux-arm-
> > kernel@lists.infradead.org; linux-samsung-soc@vger.kernel.org; linux-
> > kernel@vger.kernel.org
> > Cc: Alim Akhtar <alim.akhtar@samsung.com>
> > Subject: [PATCH] iio: adc: exynos: Simplify Exynos7-specific init
> > 
> > The Exynos7-specific code bits in ADC driver do not play with PHY:
> > the field exynos_adc_data.needs_adc_phy is not set in exynos7_adc_data
> > instance.  Therefore the initialization code does not have to check if it  
> is true.
> > 
> > Signed-off-by: Krzysztof Kozlowski <krzk@kernel.org>
> >   
> Reviewed-by: Alim Akhtar <alim.akhtar@samsung.com>
> Tested on exynos7-espresso board so,
> Tested-by:  Alim Akhtar <alim.akhtar@samsung.com>

Applied to the togreg branch of iio.git and pushed out as testing for
the autobuilders to play with it.

Thanks,

Jonathan

> 
> > ---
> > 
> > Only build tested.
> > ---
> >  drivers/iio/adc/exynos_adc.c | 3 ---
> >  1 file changed, 3 deletions(-)
> > 
> > diff --git a/drivers/iio/adc/exynos_adc.c b/drivers/iio/adc/exynos_adc.c  
> index
> > 22131a677445..219c8eb32d16 100644
> > --- a/drivers/iio/adc/exynos_adc.c
> > +++ b/drivers/iio/adc/exynos_adc.c
> > @@ -449,9 +449,6 @@ static void exynos_adc_exynos7_init_hw(struct
> > exynos_adc *info)  {
> >  	u32 con1, con2;
> > 
> > -	if (info->data->needs_adc_phy)
> > -		regmap_write(info->pmu_map, info->data->phy_offset, 1);
> > -
> >  	con1 = ADC_V2_CON1_SOFT_RESET;
> >  	writel(con1, ADC_V2_CON1(info->regs));
> > 
> > --
> > 2.17.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 v13 1/2] arm: dts: mt2712: add uart APDMA to device tree
From: Matthias Brugger @ 2020-05-16 16:52 UTC (permalink / raw)
  To: Long Cheng, Vinod Koul, Randy Dunlap, Rob Herring, Mark Rutland,
	Ryder Lee, Sean Wang, Nicolas Boichat
  Cc: Zhenbao Liu, devicetree, srv_heupstream, Greg Kroah-Hartman,
	Sean Wang, linux-kernel, YT Shen, linux-mediatek, linux-serial,
	Jiri Slaby, dmaengine, Yingjoe Chen, Dan Williams,
	linux-arm-kernel
In-Reply-To: <1558596909-14084-2-git-send-email-long.cheng@mediatek.com>



On 23/05/2019 09:35, Long Cheng wrote:
> 1. add uart APDMA controller device node
> 2. add uart 0/1/2/3/4/5 DMA function

Due to the fact that 2/2 is not yet applied, please rephrase the commit message
and rebase on current mainline kernel.

Thanks
Matthias

> 
> Signed-off-by: Long Cheng <long.cheng@mediatek.com>
> ---
>  arch/arm64/boot/dts/mediatek/mt2712e.dtsi |   51 +++++++++++++++++++++++++++++
>  1 file changed, 51 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
> index 43307ba..a7a7362 100644
> --- a/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
> +++ b/arch/arm64/boot/dts/mediatek/mt2712e.dtsi
> @@ -300,6 +300,9 @@
>  		interrupts = <GIC_SPI 127 IRQ_TYPE_LEVEL_LOW>;
>  		clocks = <&baud_clk>, <&sys_clk>;
>  		clock-names = "baud", "bus";
> +		dmas = <&apdma 10
> +			&apdma 11>;
> +		dma-names = "tx", "rx";
>  		status = "disabled";
>  	};
>  
> @@ -369,6 +372,39 @@
>  			 (GIC_CPU_MASK_RAW(0x13) | IRQ_TYPE_LEVEL_HIGH)>;
>  	};
>  
> +	apdma: dma-controller@11000400 {
> +		compatible = "mediatek,mt2712-uart-dma",
> +			     "mediatek,mt6577-uart-dma";
> +		reg = <0 0x11000400 0 0x80>,
> +		      <0 0x11000480 0 0x80>,
> +		      <0 0x11000500 0 0x80>,
> +		      <0 0x11000580 0 0x80>,
> +		      <0 0x11000600 0 0x80>,
> +		      <0 0x11000680 0 0x80>,
> +		      <0 0x11000700 0 0x80>,
> +		      <0 0x11000780 0 0x80>,
> +		      <0 0x11000800 0 0x80>,
> +		      <0 0x11000880 0 0x80>,
> +		      <0 0x11000900 0 0x80>,
> +		      <0 0x11000980 0 0x80>;
> +		interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 104 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 105 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 106 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 107 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 108 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 109 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 110 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 111 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 112 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 113 IRQ_TYPE_LEVEL_LOW>,
> +			     <GIC_SPI 114 IRQ_TYPE_LEVEL_LOW>;
> +		dma-requests = <12>;
> +		clocks = <&pericfg CLK_PERI_AP_DMA>;
> +		clock-names = "apdma";
> +		#dma-cells = <1>;
> +	};
> +
>  	auxadc: adc@11001000 {
>  		compatible = "mediatek,mt2712-auxadc";
>  		reg = <0 0x11001000 0 0x1000>;
> @@ -385,6 +421,9 @@
>  		interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_LOW>;
>  		clocks = <&baud_clk>, <&sys_clk>;
>  		clock-names = "baud", "bus";
> +		dmas = <&apdma 0
> +			&apdma 1>;
> +		dma-names = "tx", "rx";
>  		status = "disabled";
>  	};
>  
> @@ -395,6 +434,9 @@
>  		interrupts = <GIC_SPI 92 IRQ_TYPE_LEVEL_LOW>;
>  		clocks = <&baud_clk>, <&sys_clk>;
>  		clock-names = "baud", "bus";
> +		dmas = <&apdma 2
> +			&apdma 3>;
> +		dma-names = "tx", "rx";
>  		status = "disabled";
>  	};
>  
> @@ -405,6 +447,9 @@
>  		interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_LOW>;
>  		clocks = <&baud_clk>, <&sys_clk>;
>  		clock-names = "baud", "bus";
> +		dmas = <&apdma 4
> +			&apdma 5>;
> +		dma-names = "tx", "rx";
>  		status = "disabled";
>  	};
>  
> @@ -415,6 +460,9 @@
>  		interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_LOW>;
>  		clocks = <&baud_clk>, <&sys_clk>;
>  		clock-names = "baud", "bus";
> +		dmas = <&apdma 6
> +			&apdma 7>;
> +		dma-names = "tx", "rx";
>  		status = "disabled";
>  	};
>  
> @@ -629,6 +677,9 @@
>  		interrupts = <GIC_SPI 126 IRQ_TYPE_LEVEL_LOW>;
>  		clocks = <&baud_clk>, <&sys_clk>;
>  		clock-names = "baud", "bus";
> +		dmas = <&apdma 8
> +			&apdma 9>;
> +		dma-names = "tx", "rx";
>  		status = "disabled";
>  	};
>  
> 

_______________________________________________
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] iio: adc: stm32-adc: fix a wrong error message when probing interrupts
From: Jonathan Cameron @ 2020-05-16 17:01 UTC (permalink / raw)
  To: Fabrice Gasnier
  Cc: olivier.moysan, alexandre.torgue, linux-iio, linux-kernel,
	mcoquelin.stm32, linux-stm32, linux-arm-kernel
In-Reply-To: <1589290025-23857-1-git-send-email-fabrice.gasnier@st.com>

On Tue, 12 May 2020 15:27:05 +0200
Fabrice Gasnier <fabrice.gasnier@st.com> wrote:

> A wrong error message is printed out currently, like on STM32MP15:
> - stm32-adc-core 48003000.adc: IRQ index 2 not found.
> 
> This is seen since commit 7723f4c5ecdb ("driver core: platform: Add an
> error message to platform_get_irq*()").
> The STM32 ADC core driver wrongly requests up to 3 interrupt lines. It
> should request only the necessary IRQs, based on the compatible:
> - stm32f4/h7 ADCs share a common interrupt
> - stm32mp1, has one interrupt line per ADC.
> So add the number of required interrupts to the compatible data.
> 
> Fixes: d58c67d1d851 ("iio: adc: stm32-adc: add support for STM32MP1")
> 
> Signed-off-by: Fabrice Gasnier <fabrice.gasnier@st.com>
Applied to the fixes-togreg branch of iio.git and marked for stable.
Whilst it's only an incorrect error message it is likely to make
people think something is broken, hence the stable marking.

Thanks,

Jonathan

> ---
>  drivers/iio/adc/stm32-adc-core.c | 34 ++++++++++++++--------------------
>  1 file changed, 14 insertions(+), 20 deletions(-)
> 
> diff --git a/drivers/iio/adc/stm32-adc-core.c b/drivers/iio/adc/stm32-adc-core.c
> index ebe5dbc..3586369 100644
> --- a/drivers/iio/adc/stm32-adc-core.c
> +++ b/drivers/iio/adc/stm32-adc-core.c
> @@ -65,12 +65,14 @@ struct stm32_adc_priv;
>   * @clk_sel:	clock selection routine
>   * @max_clk_rate_hz: maximum analog clock rate (Hz, from datasheet)
>   * @has_syscfg: SYSCFG capability flags
> + * @num_irqs:	number of interrupt lines
>   */
>  struct stm32_adc_priv_cfg {
>  	const struct stm32_adc_common_regs *regs;
>  	int (*clk_sel)(struct platform_device *, struct stm32_adc_priv *);
>  	u32 max_clk_rate_hz;
>  	unsigned int has_syscfg;
> +	unsigned int num_irqs;
>  };
>  
>  /**
> @@ -375,21 +377,15 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
>  	struct device_node *np = pdev->dev.of_node;
>  	unsigned int i;
>  
> -	for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
> +	/*
> +	 * Interrupt(s) must be provided, depending on the compatible:
> +	 * - stm32f4/h7 shares a common interrupt line.
> +	 * - stm32mp1, has one line per ADC
> +	 */
> +	for (i = 0; i < priv->cfg->num_irqs; i++) {
>  		priv->irq[i] = platform_get_irq(pdev, i);
> -		if (priv->irq[i] < 0) {
> -			/*
> -			 * At least one interrupt must be provided, make others
> -			 * optional:
> -			 * - stm32f4/h7 shares a common interrupt.
> -			 * - stm32mp1, has one line per ADC (either for ADC1,
> -			 *   ADC2 or both).
> -			 */
> -			if (i && priv->irq[i] == -ENXIO)
> -				continue;
> -
> +		if (priv->irq[i] < 0)
>  			return priv->irq[i];
> -		}
>  	}
>  
>  	priv->domain = irq_domain_add_simple(np, STM32_ADC_MAX_ADCS, 0,
> @@ -400,9 +396,7 @@ static int stm32_adc_irq_probe(struct platform_device *pdev,
>  		return -ENOMEM;
>  	}
>  
> -	for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
> -		if (priv->irq[i] < 0)
> -			continue;
> +	for (i = 0; i < priv->cfg->num_irqs; i++) {
>  		irq_set_chained_handler(priv->irq[i], stm32_adc_irq_handler);
>  		irq_set_handler_data(priv->irq[i], priv);
>  	}
> @@ -420,11 +414,8 @@ static void stm32_adc_irq_remove(struct platform_device *pdev,
>  		irq_dispose_mapping(irq_find_mapping(priv->domain, hwirq));
>  	irq_domain_remove(priv->domain);
>  
> -	for (i = 0; i < STM32_ADC_MAX_ADCS; i++) {
> -		if (priv->irq[i] < 0)
> -			continue;
> +	for (i = 0; i < priv->cfg->num_irqs; i++)
>  		irq_set_chained_handler(priv->irq[i], NULL);
> -	}
>  }
>  
>  static int stm32_adc_core_switches_supply_en(struct stm32_adc_priv *priv,
> @@ -824,6 +815,7 @@ static const struct stm32_adc_priv_cfg stm32f4_adc_priv_cfg = {
>  	.regs = &stm32f4_adc_common_regs,
>  	.clk_sel = stm32f4_adc_clk_sel,
>  	.max_clk_rate_hz = 36000000,
> +	.num_irqs = 1,
>  };
>  
>  static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
> @@ -831,6 +823,7 @@ static const struct stm32_adc_priv_cfg stm32h7_adc_priv_cfg = {
>  	.clk_sel = stm32h7_adc_clk_sel,
>  	.max_clk_rate_hz = 36000000,
>  	.has_syscfg = HAS_VBOOSTER,
> +	.num_irqs = 1,
>  };
>  
>  static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
> @@ -838,6 +831,7 @@ static const struct stm32_adc_priv_cfg stm32mp1_adc_priv_cfg = {
>  	.clk_sel = stm32h7_adc_clk_sel,
>  	.max_clk_rate_hz = 40000000,
>  	.has_syscfg = HAS_VBOOSTER | HAS_ANASWVDD,
> +	.num_irqs = 2,
>  };
>  
>  static const struct of_device_id stm32_adc_of_match[] = {


_______________________________________________
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 v2 1/8] iio: proximity: ping: pass reference to IIO device via call-stack
From: Jonathan Cameron @ 2020-05-16 17:12 UTC (permalink / raw)
  To: Alexandru Ardelean
  Cc: alexandre.belloni, alexandre.torgue, linux-iio, linux-kernel,
	ludovic.desroches, ak, mcoquelin.stm32, eugen.hristev,
	linux-stm32, linux-arm-kernel
In-Reply-To: <20200514131710.84201-2-alexandru.ardelean@analog.com>

On Thu, 14 May 2020 16:17:03 +0300
Alexandru Ardelean <alexandru.ardelean@analog.com> wrote:

> Since there will be some changes to how iio_priv_to_dev() is implemented,
> it could be that the helper becomes a bit slower, as it will be hidden away
> in the IIO core.
> 
> For this driver, the IIO device can be passed directly as a parameter to
> the ping_read() function, thus making it immune to the change of
> iio_priv_to_dev().
> 
> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>

Patch makes sense and I should have spotted this one during original
review :( Going backwards and forwards is never a good idea even without
the rework you have.

But... (you knew that was coming :), there is no need to pass
data to the the read function.  It is the structure returned by
iio_priv() and not used anywhere else in the read_raw callback.
So might as well just pass the iio_dev and get the data structure
with in the read function via iio_priv(indio_dev)

Thanks,

J

> ---
>  drivers/iio/proximity/ping.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/proximity/ping.c b/drivers/iio/proximity/ping.c
> index 12b893c5b0ee..ddc43a5a2ef8 100644
> --- a/drivers/iio/proximity/ping.c
> +++ b/drivers/iio/proximity/ping.c
> @@ -89,14 +89,13 @@ static irqreturn_t ping_handle_irq(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> -static int ping_read(struct ping_data *data)
> +static int ping_read(struct iio_dev *indio_dev, struct ping_data *data)
>  {
>  	int ret;
>  	ktime_t ktime_dt;
>  	s64 dt_ns;
>  	u32 time_ns, distance_mm;
>  	struct platform_device *pdev = to_platform_device(data->dev);
> -	struct iio_dev *indio_dev = iio_priv_to_dev(data);
>  
>  	/*
>  	 * just one read-echo-cycle can take place at a time
> @@ -236,7 +235,7 @@ static int ping_read_raw(struct iio_dev *indio_dev,
>  
>  	switch (info) {
>  	case IIO_CHAN_INFO_RAW:
> -		ret = ping_read(data);
> +		ret = ping_read(indio_dev, data);
>  		if (ret < 0)
>  			return ret;
>  		*val = ret;


_______________________________________________
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 v2 2/8] iio: at91-sama5d2_adc: pass ref to IIO device via param for int function
From: Jonathan Cameron @ 2020-05-16 17:15 UTC (permalink / raw)
  To: Alexandru Ardelean
  Cc: alexandre.belloni, alexandre.torgue, linux-iio, linux-kernel,
	ludovic.desroches, ak, mcoquelin.stm32, eugen.hristev,
	linux-stm32, linux-arm-kernel
In-Reply-To: <20200514131710.84201-3-alexandru.ardelean@analog.com>

On Thu, 14 May 2020 16:17:04 +0300
Alexandru Ardelean <alexandru.ardelean@analog.com> wrote:

> Since there will be some changes to how iio_priv_to_dev() is implemented,
> it could be that the helper becomes a bit slower, as it will be hidden away
> in the IIO core.
> 
> For this driver, the IIO device can be passed directly as a parameter to
> the at91_adc_no_pen_detect_interrupt() function, thus making it immune to
> the change of iio_priv_to_dev().
> The function gets called in an interrupt context.
> 
> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>

Looks sensible to me.   We could get the state structure from the 
iio_dev inside that function, but then it would be different from the
pen version, so I think what you have here is probably best option.

Jonathan

> ---
>  drivers/iio/adc/at91-sama5d2_adc.c | 7 +++----
>  1 file changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/iio/adc/at91-sama5d2_adc.c b/drivers/iio/adc/at91-sama5d2_adc.c
> index 9abbbdcc7420..822b8782acba 100644
> --- a/drivers/iio/adc/at91-sama5d2_adc.c
> +++ b/drivers/iio/adc/at91-sama5d2_adc.c
> @@ -1275,10 +1275,9 @@ static void at91_adc_pen_detect_interrupt(struct at91_adc_state *st)
>  	st->touch_st.touching = true;
>  }
>  
> -static void at91_adc_no_pen_detect_interrupt(struct at91_adc_state *st)
> +static void at91_adc_no_pen_detect_interrupt(struct iio_dev *indio_dev,
> +					     struct at91_adc_state *st)
>  {
> -	struct iio_dev *indio_dev = iio_priv_to_dev(st);
> -
>  	at91_adc_writel(st, AT91_SAMA5D2_TRGR,
>  			AT91_SAMA5D2_TRGR_TRGMOD_NO_TRIGGER);
>  	at91_adc_writel(st, AT91_SAMA5D2_IDR, AT91_SAMA5D2_IER_NOPEN |
> @@ -1318,7 +1317,7 @@ static irqreturn_t at91_adc_interrupt(int irq, void *private)
>  		at91_adc_pen_detect_interrupt(st);
>  	} else if ((status & AT91_SAMA5D2_IER_NOPEN)) {
>  		/* nopen detected IRQ */
> -		at91_adc_no_pen_detect_interrupt(st);
> +		at91_adc_no_pen_detect_interrupt(indio, st);
>  	} else if ((status & AT91_SAMA5D2_ISR_PENS) &&
>  		   ((status & rdy_mask) == rdy_mask)) {
>  		/* periodic trigger IRQ - during pen sense */


_______________________________________________
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 v2 3/8] iio: at91_adc: pass ref to IIO device via param for int function
From: Jonathan Cameron @ 2020-05-16 17:17 UTC (permalink / raw)
  To: Alexandru Ardelean
  Cc: alexandre.belloni, alexandre.torgue, linux-iio, linux-kernel,
	ludovic.desroches, ak, mcoquelin.stm32, eugen.hristev,
	linux-stm32, linux-arm-kernel
In-Reply-To: <20200514131710.84201-4-alexandru.ardelean@analog.com>

On Thu, 14 May 2020 16:17:05 +0300
Alexandru Ardelean <alexandru.ardelean@analog.com> wrote:

> Since there will be some changes to how iio_priv_to_dev() is implemented,
> it could be that the helper becomes a bit slower, as it will be hidden away
> in the IIO core.
> 
> For this driver, the IIO device can be passed directly as a parameter to
> the at91_ts_sample() function, thus making it immune to the change of
> iio_priv_to_dev().
> The function gets called in an interrupt context.
> 
> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
I wonder. Should we just pass the struct device?  It's only used for
error printing I think, so we could make that explicit.

I'm not that bothered either way though.

Jonathan

> ---
>  drivers/iio/adc/at91_adc.c | 5 ++---
>  1 file changed, 2 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/adc/at91_adc.c b/drivers/iio/adc/at91_adc.c
> index 0368b6dc6d60..5999defe47cd 100644
> --- a/drivers/iio/adc/at91_adc.c
> +++ b/drivers/iio/adc/at91_adc.c
> @@ -287,13 +287,12 @@ static void handle_adc_eoc_trigger(int irq, struct iio_dev *idev)
>  	}
>  }
>  
> -static int at91_ts_sample(struct at91_adc_state *st)
> +static int at91_ts_sample(struct iio_dev *idev, struct at91_adc_state *st)
>  {
>  	unsigned int xscale, yscale, reg, z1, z2;
>  	unsigned int x, y, pres, xpos, ypos;
>  	unsigned int rxp = 1;
>  	unsigned int factor = 1000;
> -	struct iio_dev *idev = iio_priv_to_dev(st);
>  
>  	unsigned int xyz_mask_bits = st->res;
>  	unsigned int xyz_mask = (1 << xyz_mask_bits) - 1;
> @@ -449,7 +448,7 @@ static irqreturn_t at91_adc_9x5_interrupt(int irq, void *private)
>  
>  		if (status & AT91_ADC_ISR_PENS) {
>  			/* validate data by pen contact */
> -			at91_ts_sample(st);
> +			at91_ts_sample(idev, st);
>  		} else {
>  			/* triggered by event that is no pen contact, just read
>  			 * them to clean the interrupt and discard all.


_______________________________________________
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 03/14] arm64: add support for folded p4d page tables
From: Mike Rapoport @ 2020-05-16 17:20 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Rich Felker, linux-ia64, Geert Uytterhoeven, linux-sh,
	Benjamin Herrenschmidt, linux-mm, Paul Mackerras, linux-hexagon,
	Will Deacon, kvmarm, Jonas Bonn, linux-arch, Brian Cain,
	Marc Zyngier, Russell King, Ley Foon Tan, Mike Rapoport,
	Catalin Marinas, Julien Thierry, uclinux-h8-devel, Fenghua Yu,
	Arnd Bergmann, Suzuki K Poulose, kvm-ppc, Stefan Kristiansson,
	openrisc, Stafford Horne, Guan Xuetao, linux-arm-kernel,
	Christophe Leroy, Tony Luck, Yoshinori Sato, linux-kernel,
	James Morse, Michael Ellerman, nios2-dev, linuxppc-dev
In-Reply-To: <20200515114012.49f45aa01efb7d8b918bc0f5@linux-foundation.org>

On Fri, May 15, 2020 at 11:40:12AM -0700, Andrew Morton wrote:
> On Tue, 14 Apr 2020 18:34:44 +0300 Mike Rapoport <rppt@kernel.org> wrote:
> 
> > Implement primitives necessary for the 4th level folding, add walks of p4d
> > level where appropriate, replace 5level-fixup.h with pgtable-nop4d.h and
> > remove __ARCH_USE_5LEVEL_HACK.
> 
> This needed some rework due to arm changes in linux-next.  Please check
> my handiwork and test it once I've merged this into linux-next?

Looks ok to me. It passed defconfig and a couple of randconfig builds
and qemu-system-aarch64 boots find with this.

> Rejects were
> 
> --- arch/arm64/include/asm/pgtable.h~arm64-add-support-for-folded-p4d-page-tables
> +++ arch/arm64/include/asm/pgtable.h
> @@ -596,49 +604,50 @@ static inline phys_addr_t pud_page_paddr
>  
>  #define pud_ERROR(pud)		__pud_error(__FILE__, __LINE__, pud_val(pud))
>  
> -#define pgd_none(pgd)		(!pgd_val(pgd))
> -#define pgd_bad(pgd)		(!(pgd_val(pgd) & 2))
> -#define pgd_present(pgd)	(pgd_val(pgd))
> +#define p4d_none(p4d)		(!p4d_val(p4d))
> +#define p4d_bad(p4d)		(!(p4d_val(p4d) & 2))
> +#define p4d_present(p4d)	(p4d_val(p4d))
>  
> -static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
> +static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
>  {
> -	if (in_swapper_pgdir(pgdp)) {
> -		set_swapper_pgd(pgdp, pgd);
> +	if (in_swapper_pgdir(p4dp)) {
> +		set_swapper_pgd((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
>  		return;
>  	}
>  
> -	WRITE_ONCE(*pgdp, pgd);
> +	WRITE_ONCE(*p4dp, p4d);
>  	dsb(ishst);
>  	isb();
>  }
>  
> -static inline void pgd_clear(pgd_t *pgdp)
> +static inline void p4d_clear(p4d_t *p4dp)
>  {
> -	set_pgd(pgdp, __pgd(0));
> +	set_p4d(p4dp, __p4d(0));
>  }
>  
> -static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
> +static inline phys_addr_t p4d_page_paddr(p4d_t p4d)
>  {
> -	return __pgd_to_phys(pgd);
> +	return __p4d_to_phys(p4d);
>  }
>  
>  /* Find an entry in the frst-level page table. */
>  #define pud_index(addr)		(((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
>  
> -#define pud_offset_phys(dir, addr)	(pgd_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
> +#define pud_offset_phys(dir, addr)	(p4d_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
>  #define pud_offset(dir, addr)		((pud_t *)__va(pud_offset_phys((dir), (addr))))
>  
>  #define pud_set_fixmap(addr)		((pud_t *)set_fixmap_offset(FIX_PUD, addr))
> -#define pud_set_fixmap_offset(pgd, addr)	pud_set_fixmap(pud_offset_phys(pgd, addr))
> +#define pud_set_fixmap_offset(p4d, addr)	pud_set_fixmap(pud_offset_phys(p4d, addr))
>  #define pud_clear_fixmap()		clear_fixmap(FIX_PUD)
>  
> -#define pgd_page(pgd)		pfn_to_page(__phys_to_pfn(__pgd_to_phys(pgd)))
> +#define p4d_page(p4d)		pfn_to_page(__phys_to_pfn(__p4d_to_phys(p4d)))
>  
>  /* use ONLY for statically allocated translation tables */
>  #define pud_offset_kimg(dir,addr)	((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
>  
>  #else
>  
> +#define p4d_page_paddr(p4d)	({ BUILD_BUG(); 0;})
>  #define pgd_page_paddr(pgd)	({ BUILD_BUG(); 0;})
>  
>  /* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */
> 
> 
> 
> and
> 
> --- arch/arm64/kvm/mmu.c~arm64-add-support-for-folded-p4d-page-tables
> +++ arch/arm64/kvm/mmu.c
> @@ -469,7 +517,7 @@ static void stage2_flush_memslot(struct
>  	do {
>  		next = stage2_pgd_addr_end(kvm, addr, end);
>  		if (!stage2_pgd_none(kvm, *pgd))
> -			stage2_flush_puds(kvm, pgd, addr, next);
> +			stage2_flush_p4ds(kvm, pgd, addr, next);
>  	} while (pgd++, addr = next, addr != end);
>  }
>  
> 
> 
> Result:
> 
> From: Mike Rapoport <rppt@linux.ibm.com>
> Subject: arm64: add support for folded p4d page tables
> 
> Implement primitives necessary for the 4th level folding, add walks of p4d
> level where appropriate, replace 5level-fixup.h with pgtable-nop4d.h and
> remove __ARCH_USE_5LEVEL_HACK.
> 
> Link: http://lkml.kernel.org/r/20200414153455.21744-4-rppt@kernel.org
> Signed-off-by: Mike Rapoport <rppt@linux.ibm.com>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
> Cc: Brian Cain <bcain@codeaurora.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Christophe Leroy <christophe.leroy@c-s.fr>
> Cc: Fenghua Yu <fenghua.yu@intel.com>
> Cc: Geert Uytterhoeven <geert+renesas@glider.be>
> Cc: Guan Xuetao <gxt@pku.edu.cn>
> Cc: James Morse <james.morse@arm.com>
> Cc: Jonas Bonn <jonas@southpole.se>
> Cc: Julien Thierry <julien.thierry.kdev@gmail.com>
> Cc: Ley Foon Tan <ley.foon.tan@intel.com>
> Cc: Marc Zyngier <maz@kernel.org>
> Cc: Michael Ellerman <mpe@ellerman.id.au>
> Cc: Paul Mackerras <paulus@samba.org>
> Cc: Rich Felker <dalias@libc.org>
> Cc: Russell King <linux@armlinux.org.uk>
> Cc: Stafford Horne <shorne@gmail.com>
> Cc: Stefan Kristiansson <stefan.kristiansson@saunalahti.fi>
> Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
> Cc: Tony Luck <tony.luck@intel.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: Yoshinori Sato <ysato@users.sourceforge.jp>
> Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
> ---
> 
>  arch/arm64/include/asm/kvm_mmu.h        |   10 -
>  arch/arm64/include/asm/pgalloc.h        |   10 -
>  arch/arm64/include/asm/pgtable-types.h  |    5 
>  arch/arm64/include/asm/pgtable.h        |   37 ++-
>  arch/arm64/include/asm/stage2_pgtable.h |   48 +++--
>  arch/arm64/kernel/hibernate.c           |   44 +++-
>  arch/arm64/kvm/mmu.c                    |  209 ++++++++++++++++++----
>  arch/arm64/mm/fault.c                   |    9 
>  arch/arm64/mm/hugetlbpage.c             |   15 +
>  arch/arm64/mm/kasan_init.c              |   26 ++
>  arch/arm64/mm/mmu.c                     |   52 +++--
>  arch/arm64/mm/pageattr.c                |    7 
>  12 files changed, 368 insertions(+), 104 deletions(-)
> 
> --- a/arch/arm64/include/asm/kvm_mmu.h~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/include/asm/kvm_mmu.h
> @@ -172,8 +172,8 @@ void kvm_clear_hyp_idmap(void);
>  	__pmd(__phys_to_pmd_val(__pa(ptep)) | PMD_TYPE_TABLE)
>  #define kvm_mk_pud(pmdp)					\
>  	__pud(__phys_to_pud_val(__pa(pmdp)) | PMD_TYPE_TABLE)
> -#define kvm_mk_pgd(pudp)					\
> -	__pgd(__phys_to_pgd_val(__pa(pudp)) | PUD_TYPE_TABLE)
> +#define kvm_mk_p4d(pmdp)					\
> +	__p4d(__phys_to_p4d_val(__pa(pmdp)) | PUD_TYPE_TABLE)
>  
>  #define kvm_set_pud(pudp, pud)		set_pud(pudp, pud)
>  
> @@ -299,6 +299,12 @@ static inline bool kvm_s2pud_young(pud_t
>  #define hyp_pud_table_empty(pudp) kvm_page_empty(pudp)
>  #endif
>  
> +#ifdef __PAGETABLE_P4D_FOLDED
> +#define hyp_p4d_table_empty(p4dp) (0)
> +#else
> +#define hyp_p4d_table_empty(p4dp) kvm_page_empty(p4dp)
> +#endif
> +
>  struct kvm;
>  
>  #define kvm_flush_dcache_to_poc(a,l)	__flush_dcache_area((a), (l))
> --- a/arch/arm64/include/asm/pgalloc.h~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/include/asm/pgalloc.h
> @@ -73,17 +73,17 @@ static inline void pud_free(struct mm_st
>  	free_page((unsigned long)pudp);
>  }
>  
> -static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot)
> +static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
>  {
> -	set_pgd(pgdp, __pgd(__phys_to_pgd_val(pudp) | prot));
> +	set_p4d(p4dp, __p4d(__phys_to_p4d_val(pudp) | prot));
>  }
>  
> -static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgdp, pud_t *pudp)
> +static inline void p4d_populate(struct mm_struct *mm, p4d_t *p4dp, pud_t *pudp)
>  {
> -	__pgd_populate(pgdp, __pa(pudp), PUD_TYPE_TABLE);
> +	__p4d_populate(p4dp, __pa(pudp), PUD_TYPE_TABLE);
>  }
>  #else
> -static inline void __pgd_populate(pgd_t *pgdp, phys_addr_t pudp, pgdval_t prot)
> +static inline void __p4d_populate(p4d_t *p4dp, phys_addr_t pudp, p4dval_t prot)
>  {
>  	BUILD_BUG();
>  }
> --- a/arch/arm64/include/asm/pgtable.h~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/include/asm/pgtable.h
> @@ -298,6 +298,11 @@ static inline pte_t pgd_pte(pgd_t pgd)
>  	return __pte(pgd_val(pgd));
>  }
>  
> +static inline pte_t p4d_pte(p4d_t p4d)
> +{
> +	return __pte(p4d_val(p4d));
> +}
> +
>  static inline pte_t pud_pte(pud_t pud)
>  {
>  	return __pte(pud_val(pud));
> @@ -401,6 +406,9 @@ static inline pmd_t pmd_mkdevmap(pmd_t p
>  
>  #define set_pmd_at(mm, addr, pmdp, pmd)	set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd))
>  
> +#define __p4d_to_phys(p4d)	__pte_to_phys(p4d_pte(p4d))
> +#define __phys_to_p4d_val(phys)	__phys_to_pte_val(phys)
> +
>  #define __pgd_to_phys(pgd)	__pte_to_phys(pgd_pte(pgd))
>  #define __phys_to_pgd_val(phys)	__phys_to_pte_val(phys)
>  
> @@ -592,49 +600,50 @@ static inline phys_addr_t pud_page_paddr
>  
>  #define pud_ERROR(pud)		__pud_error(__FILE__, __LINE__, pud_val(pud))
>  
> -#define pgd_none(pgd)		(!pgd_val(pgd))
> -#define pgd_bad(pgd)		(!(pgd_val(pgd) & 2))
> -#define pgd_present(pgd)	(pgd_val(pgd))
> +#define p4d_none(p4d)		(!p4d_val(p4d))
> +#define p4d_bad(p4d)		(!(p4d_val(p4d) & 2))
> +#define p4d_present(p4d)	(p4d_val(p4d))
>  
> -static inline void set_pgd(pgd_t *pgdp, pgd_t pgd)
> +static inline void set_p4d(p4d_t *p4dp, p4d_t p4d)
>  {
> -	if (in_swapper_pgdir(pgdp)) {
> -		set_swapper_pgd(pgdp, pgd);
> +	if (in_swapper_pgdir(p4dp)) {
> +		set_swapper_pgd((pgd_t *)p4dp, __pgd(p4d_val(p4d)));
>  		return;
>  	}
>  
> -	WRITE_ONCE(*pgdp, pgd);
> +	WRITE_ONCE(*p4dp, p4d);
>  	dsb(ishst);
>  	isb();
>  }
>  
> -static inline void pgd_clear(pgd_t *pgdp)
> +static inline void p4d_clear(p4d_t *p4dp)
>  {
> -	set_pgd(pgdp, __pgd(0));
> +	set_p4d(p4dp, __p4d(0));
>  }
>  
> -static inline phys_addr_t pgd_page_paddr(pgd_t pgd)
> +static inline phys_addr_t p4d_page_paddr(p4d_t p4d)
>  {
> -	return __pgd_to_phys(pgd);
> +	return __p4d_to_phys(p4d);
>  }
>  
>  /* Find an entry in the frst-level page table. */
>  #define pud_index(addr)		(((addr) >> PUD_SHIFT) & (PTRS_PER_PUD - 1))
>  
> -#define pud_offset_phys(dir, addr)	(pgd_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
> +#define pud_offset_phys(dir, addr)	(p4d_page_paddr(READ_ONCE(*(dir))) + pud_index(addr) * sizeof(pud_t))
>  #define pud_offset(dir, addr)		((pud_t *)__va(pud_offset_phys((dir), (addr))))
>  
>  #define pud_set_fixmap(addr)		((pud_t *)set_fixmap_offset(FIX_PUD, addr))
> -#define pud_set_fixmap_offset(pgd, addr)	pud_set_fixmap(pud_offset_phys(pgd, addr))
> +#define pud_set_fixmap_offset(p4d, addr)	pud_set_fixmap(pud_offset_phys(p4d, addr))
>  #define pud_clear_fixmap()		clear_fixmap(FIX_PUD)
>  
> -#define pgd_page(pgd)			phys_to_page(__pgd_to_phys(pgd))
> +#define p4d_page(p4d)		pfn_to_page(__phys_to_pfn(__p4d_to_phys(p4d)))
>  
>  /* use ONLY for statically allocated translation tables */
>  #define pud_offset_kimg(dir,addr)	((pud_t *)__phys_to_kimg(pud_offset_phys((dir), (addr))))
>  
>  #else
>  
> +#define p4d_page_paddr(p4d)	({ BUILD_BUG(); 0;})
>  #define pgd_page_paddr(pgd)	({ BUILD_BUG(); 0;})
>  
>  /* Match pud_offset folding in <asm/generic/pgtable-nopud.h> */
> --- a/arch/arm64/include/asm/pgtable-types.h~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/include/asm/pgtable-types.h
> @@ -14,6 +14,7 @@
>  typedef u64 pteval_t;
>  typedef u64 pmdval_t;
>  typedef u64 pudval_t;
> +typedef u64 p4dval_t;
>  typedef u64 pgdval_t;
>  
>  /*
> @@ -44,13 +45,11 @@ typedef struct { pteval_t pgprot; } pgpr
>  #define __pgprot(x)	((pgprot_t) { (x) } )
>  
>  #if CONFIG_PGTABLE_LEVELS == 2
> -#define __ARCH_USE_5LEVEL_HACK
>  #include <asm-generic/pgtable-nopmd.h>
>  #elif CONFIG_PGTABLE_LEVELS == 3
> -#define __ARCH_USE_5LEVEL_HACK
>  #include <asm-generic/pgtable-nopud.h>
>  #elif CONFIG_PGTABLE_LEVELS == 4
> -#include <asm-generic/5level-fixup.h>
> +#include <asm-generic/pgtable-nop4d.h>
>  #endif
>  
>  #endif	/* __ASM_PGTABLE_TYPES_H */
> --- a/arch/arm64/include/asm/stage2_pgtable.h~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/include/asm/stage2_pgtable.h
> @@ -68,41 +68,67 @@ static inline bool kvm_stage2_has_pud(st
>  #define S2_PUD_SIZE			(1UL << S2_PUD_SHIFT)
>  #define S2_PUD_MASK			(~(S2_PUD_SIZE - 1))
>  
> -static inline bool stage2_pgd_none(struct kvm *kvm, pgd_t pgd)
> +#define stage2_pgd_none(kvm, pgd)		pgd_none(pgd)
> +#define stage2_pgd_clear(kvm, pgd)		pgd_clear(pgd)
> +#define stage2_pgd_present(kvm, pgd)		pgd_present(pgd)
> +#define stage2_pgd_populate(kvm, pgd, p4d)	pgd_populate(NULL, pgd, p4d)
> +
> +static inline p4d_t *stage2_p4d_offset(struct kvm *kvm,
> +				       pgd_t *pgd, unsigned long address)
> +{
> +	return p4d_offset(pgd, address);
> +}
> +
> +static inline void stage2_p4d_free(struct kvm *kvm, p4d_t *p4d)
> +{
> +}
> +
> +static inline bool stage2_p4d_table_empty(struct kvm *kvm, p4d_t *p4dp)
> +{
> +	return false;
> +}
> +
> +static inline phys_addr_t stage2_p4d_addr_end(struct kvm *kvm,
> +					      phys_addr_t addr, phys_addr_t end)
> +{
> +	return end;
> +}
> +
> +static inline bool stage2_p4d_none(struct kvm *kvm, p4d_t p4d)
>  {
>  	if (kvm_stage2_has_pud(kvm))
> -		return pgd_none(pgd);
> +		return p4d_none(p4d);
>  	else
>  		return 0;
>  }
>  
> -static inline void stage2_pgd_clear(struct kvm *kvm, pgd_t *pgdp)
> +static inline void stage2_p4d_clear(struct kvm *kvm, p4d_t *p4dp)
>  {
>  	if (kvm_stage2_has_pud(kvm))
> -		pgd_clear(pgdp);
> +		p4d_clear(p4dp);
>  }
>  
> -static inline bool stage2_pgd_present(struct kvm *kvm, pgd_t pgd)
> +static inline bool stage2_p4d_present(struct kvm *kvm, p4d_t p4d)
>  {
>  	if (kvm_stage2_has_pud(kvm))
> -		return pgd_present(pgd);
> +		return p4d_present(p4d);
>  	else
>  		return 1;
>  }
>  
> -static inline void stage2_pgd_populate(struct kvm *kvm, pgd_t *pgd, pud_t *pud)
> +static inline void stage2_p4d_populate(struct kvm *kvm, p4d_t *p4d, pud_t *pud)
>  {
>  	if (kvm_stage2_has_pud(kvm))
> -		pgd_populate(NULL, pgd, pud);
> +		p4d_populate(NULL, p4d, pud);
>  }
>  
>  static inline pud_t *stage2_pud_offset(struct kvm *kvm,
> -				       pgd_t *pgd, unsigned long address)
> +				       p4d_t *p4d, unsigned long address)
>  {
>  	if (kvm_stage2_has_pud(kvm))
> -		return pud_offset(pgd, address);
> +		return pud_offset(p4d, address);
>  	else
> -		return (pud_t *)pgd;
> +		return (pud_t *)p4d;
>  }
>  
>  static inline void stage2_pud_free(struct kvm *kvm, pud_t *pud)
> --- a/arch/arm64/kernel/hibernate.c~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/kernel/hibernate.c
> @@ -184,6 +184,7 @@ static int trans_pgd_map_page(pgd_t *tra
>  		       pgprot_t pgprot)
>  {
>  	pgd_t *pgdp;
> +	p4d_t *p4dp;
>  	pud_t *pudp;
>  	pmd_t *pmdp;
>  	pte_t *ptep;
> @@ -196,7 +197,15 @@ static int trans_pgd_map_page(pgd_t *tra
>  		pgd_populate(&init_mm, pgdp, pudp);
>  	}
>  
> -	pudp = pud_offset(pgdp, dst_addr);
> +	p4dp = p4d_offset(pgdp, dst_addr);
> +	if (p4d_none(READ_ONCE(*p4dp))) {
> +		pudp = (void *)get_safe_page(GFP_ATOMIC);
> +		if (!pudp)
> +			return -ENOMEM;
> +		p4d_populate(&init_mm, p4dp, pudp);
> +	}
> +
> +	pudp = pud_offset(p4dp, dst_addr);
>  	if (pud_none(READ_ONCE(*pudp))) {
>  		pmdp = (void *)get_safe_page(GFP_ATOMIC);
>  		if (!pmdp)
> @@ -419,7 +428,7 @@ static int copy_pmd(pud_t *dst_pudp, pud
>  	return 0;
>  }
>  
> -static int copy_pud(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start,
> +static int copy_pud(p4d_t *dst_p4dp, p4d_t *src_p4dp, unsigned long start,
>  		    unsigned long end)
>  {
>  	pud_t *dst_pudp;
> @@ -427,15 +436,15 @@ static int copy_pud(pgd_t *dst_pgdp, pgd
>  	unsigned long next;
>  	unsigned long addr = start;
>  
> -	if (pgd_none(READ_ONCE(*dst_pgdp))) {
> +	if (p4d_none(READ_ONCE(*dst_p4dp))) {
>  		dst_pudp = (pud_t *)get_safe_page(GFP_ATOMIC);
>  		if (!dst_pudp)
>  			return -ENOMEM;
> -		pgd_populate(&init_mm, dst_pgdp, dst_pudp);
> +		p4d_populate(&init_mm, dst_p4dp, dst_pudp);
>  	}
> -	dst_pudp = pud_offset(dst_pgdp, start);
> +	dst_pudp = pud_offset(dst_p4dp, start);
>  
> -	src_pudp = pud_offset(src_pgdp, start);
> +	src_pudp = pud_offset(src_p4dp, start);
>  	do {
>  		pud_t pud = READ_ONCE(*src_pudp);
>  
> @@ -454,6 +463,27 @@ static int copy_pud(pgd_t *dst_pgdp, pgd
>  	return 0;
>  }
>  
> +static int copy_p4d(pgd_t *dst_pgdp, pgd_t *src_pgdp, unsigned long start,
> +		    unsigned long end)
> +{
> +	p4d_t *dst_p4dp;
> +	p4d_t *src_p4dp;
> +	unsigned long next;
> +	unsigned long addr = start;
> +
> +	dst_p4dp = p4d_offset(dst_pgdp, start);
> +	src_p4dp = p4d_offset(src_pgdp, start);
> +	do {
> +		next = p4d_addr_end(addr, end);
> +		if (p4d_none(READ_ONCE(*src_p4dp)))
> +			continue;
> +		if (copy_pud(dst_p4dp, src_p4dp, addr, next))
> +			return -ENOMEM;
> +	} while (dst_p4dp++, src_p4dp++, addr = next, addr != end);
> +
> +	return 0;
> +}
> +
>  static int copy_page_tables(pgd_t *dst_pgdp, unsigned long start,
>  			    unsigned long end)
>  {
> @@ -466,7 +496,7 @@ static int copy_page_tables(pgd_t *dst_p
>  		next = pgd_addr_end(addr, end);
>  		if (pgd_none(READ_ONCE(*src_pgdp)))
>  			continue;
> -		if (copy_pud(dst_pgdp, src_pgdp, addr, next))
> +		if (copy_p4d(dst_pgdp, src_pgdp, addr, next))
>  			return -ENOMEM;
>  	} while (dst_pgdp++, src_pgdp++, addr = next, addr != end);
>  
> --- a/arch/arm64/kvm/mmu.c~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/kvm/mmu.c
> @@ -158,13 +158,22 @@ static void *mmu_memory_cache_alloc(stru
>  
>  static void clear_stage2_pgd_entry(struct kvm *kvm, pgd_t *pgd, phys_addr_t addr)
>  {
> -	pud_t *pud_table __maybe_unused = stage2_pud_offset(kvm, pgd, 0UL);
> +	p4d_t *p4d_table __maybe_unused = stage2_p4d_offset(kvm, pgd, 0UL);
>  	stage2_pgd_clear(kvm, pgd);
>  	kvm_tlb_flush_vmid_ipa(kvm, addr);
> -	stage2_pud_free(kvm, pud_table);
> +	stage2_p4d_free(kvm, p4d_table);
>  	put_page(virt_to_page(pgd));
>  }
>  
> +static void clear_stage2_p4d_entry(struct kvm *kvm, p4d_t *p4d, phys_addr_t addr)
> +{
> +	pud_t *pud_table __maybe_unused = stage2_pud_offset(kvm, p4d, 0);
> +	stage2_p4d_clear(kvm, p4d);
> +	kvm_tlb_flush_vmid_ipa(kvm, addr);
> +	stage2_pud_free(kvm, pud_table);
> +	put_page(virt_to_page(p4d));
> +}
> +
>  static void clear_stage2_pud_entry(struct kvm *kvm, pud_t *pud, phys_addr_t addr)
>  {
>  	pmd_t *pmd_table __maybe_unused = stage2_pmd_offset(kvm, pud, 0);
> @@ -208,12 +217,20 @@ static inline void kvm_pud_populate(pud_
>  	dsb(ishst);
>  }
>  
> -static inline void kvm_pgd_populate(pgd_t *pgdp, pud_t *pudp)
> +static inline void kvm_p4d_populate(p4d_t *p4dp, pud_t *pudp)
>  {
> -	WRITE_ONCE(*pgdp, kvm_mk_pgd(pudp));
> +	WRITE_ONCE(*p4dp, kvm_mk_p4d(pudp));
>  	dsb(ishst);
>  }
>  
> +static inline void kvm_pgd_populate(pgd_t *pgdp, p4d_t *p4dp)
> +{
> +#ifndef __PAGETABLE_P4D_FOLDED
> +	WRITE_ONCE(*pgdp, kvm_mk_pgd(p4dp));
> +	dsb(ishst);
> +#endif
> +}
> +
>  /*
>   * Unmapping vs dcache management:
>   *
> @@ -293,13 +310,13 @@ static void unmap_stage2_pmds(struct kvm
>  		clear_stage2_pud_entry(kvm, pud, start_addr);
>  }
>  
> -static void unmap_stage2_puds(struct kvm *kvm, pgd_t *pgd,
> +static void unmap_stage2_puds(struct kvm *kvm, p4d_t *p4d,
>  		       phys_addr_t addr, phys_addr_t end)
>  {
>  	phys_addr_t next, start_addr = addr;
>  	pud_t *pud, *start_pud;
>  
> -	start_pud = pud = stage2_pud_offset(kvm, pgd, addr);
> +	start_pud = pud = stage2_pud_offset(kvm, p4d, addr);
>  	do {
>  		next = stage2_pud_addr_end(kvm, addr, end);
>  		if (!stage2_pud_none(kvm, *pud)) {
> @@ -317,6 +334,23 @@ static void unmap_stage2_puds(struct kvm
>  	} while (pud++, addr = next, addr != end);
>  
>  	if (stage2_pud_table_empty(kvm, start_pud))
> +		clear_stage2_p4d_entry(kvm, p4d, start_addr);
> +}
> +
> +static void unmap_stage2_p4ds(struct kvm *kvm, pgd_t *pgd,
> +		       phys_addr_t addr, phys_addr_t end)
> +{
> +	phys_addr_t next, start_addr = addr;
> +	p4d_t *p4d, *start_p4d;
> +
> +	start_p4d = p4d = stage2_p4d_offset(kvm, pgd, addr);
> +	do {
> +		next = stage2_p4d_addr_end(kvm, addr, end);
> +		if (!stage2_p4d_none(kvm, *p4d))
> +			unmap_stage2_puds(kvm, p4d, addr, next);
> +	} while (p4d++, addr = next, addr != end);
> +
> +	if (stage2_p4d_table_empty(kvm, start_p4d))
>  		clear_stage2_pgd_entry(kvm, pgd, start_addr);
>  }
>  
> @@ -351,7 +385,7 @@ static void unmap_stage2_range(struct kv
>  			break;
>  		next = stage2_pgd_addr_end(kvm, addr, end);
>  		if (!stage2_pgd_none(kvm, *pgd))
> -			unmap_stage2_puds(kvm, pgd, addr, next);
> +			unmap_stage2_p4ds(kvm, pgd, addr, next);
>  		/*
>  		 * If the range is too large, release the kvm->mmu_lock
>  		 * to prevent starvation and lockup detector warnings.
> @@ -391,13 +425,13 @@ static void stage2_flush_pmds(struct kvm
>  	} while (pmd++, addr = next, addr != end);
>  }
>  
> -static void stage2_flush_puds(struct kvm *kvm, pgd_t *pgd,
> +static void stage2_flush_puds(struct kvm *kvm, p4d_t *p4d,
>  			      phys_addr_t addr, phys_addr_t end)
>  {
>  	pud_t *pud;
>  	phys_addr_t next;
>  
> -	pud = stage2_pud_offset(kvm, pgd, addr);
> +	pud = stage2_pud_offset(kvm, p4d, addr);
>  	do {
>  		next = stage2_pud_addr_end(kvm, addr, end);
>  		if (!stage2_pud_none(kvm, *pud)) {
> @@ -409,6 +443,20 @@ static void stage2_flush_puds(struct kvm
>  	} while (pud++, addr = next, addr != end);
>  }
>  
> +static void stage2_flush_p4ds(struct kvm *kvm, pgd_t *pgd,
> +			      phys_addr_t addr, phys_addr_t end)
> +{
> +	p4d_t *p4d;
> +	phys_addr_t next;
> +
> +	p4d = stage2_p4d_offset(kvm, pgd, addr);
> +	do {
> +		next = stage2_p4d_addr_end(kvm, addr, end);
> +		if (!stage2_p4d_none(kvm, *p4d))
> +			stage2_flush_puds(kvm, p4d, addr, next);
> +	} while (p4d++, addr = next, addr != end);
> +}
> +
>  static void stage2_flush_memslot(struct kvm *kvm,
>  				 struct kvm_memory_slot *memslot)
>  {
> @@ -421,7 +469,7 @@ static void stage2_flush_memslot(struct
>  	do {
>  		next = stage2_pgd_addr_end(kvm, addr, end);
>  		if (!stage2_pgd_none(kvm, *pgd))
> -			stage2_flush_puds(kvm, pgd, addr, next);
> +			stage2_flush_p4ds(kvm, pgd, addr, next);
>  
>  		if (next != end)
>  			cond_resched_lock(&kvm->mmu_lock);
> @@ -454,12 +502,21 @@ static void stage2_flush_vm(struct kvm *
>  
>  static void clear_hyp_pgd_entry(pgd_t *pgd)
>  {
> -	pud_t *pud_table __maybe_unused = pud_offset(pgd, 0UL);
> +	p4d_t *p4d_table __maybe_unused = p4d_offset(pgd, 0UL);
>  	pgd_clear(pgd);
> -	pud_free(NULL, pud_table);
> +	p4d_free(NULL, p4d_table);
>  	put_page(virt_to_page(pgd));
>  }
>  
> +static void clear_hyp_p4d_entry(p4d_t *p4d)
> +{
> +	pud_t *pud_table __maybe_unused = pud_offset(p4d, 0);
> +	VM_BUG_ON(p4d_huge(*p4d));
> +	p4d_clear(p4d);
> +	pud_free(NULL, pud_table);
> +	put_page(virt_to_page(p4d));
> +}
> +
>  static void clear_hyp_pud_entry(pud_t *pud)
>  {
>  	pmd_t *pmd_table __maybe_unused = pmd_offset(pud, 0);
> @@ -511,12 +568,12 @@ static void unmap_hyp_pmds(pud_t *pud, p
>  		clear_hyp_pud_entry(pud);
>  }
>  
> -static void unmap_hyp_puds(pgd_t *pgd, phys_addr_t addr, phys_addr_t end)
> +static void unmap_hyp_puds(p4d_t *p4d, phys_addr_t addr, phys_addr_t end)
>  {
>  	phys_addr_t next;
>  	pud_t *pud, *start_pud;
>  
> -	start_pud = pud = pud_offset(pgd, addr);
> +	start_pud = pud = pud_offset(p4d, addr);
>  	do {
>  		next = pud_addr_end(addr, end);
>  		/* Hyp doesn't use huge puds */
> @@ -525,6 +582,23 @@ static void unmap_hyp_puds(pgd_t *pgd, p
>  	} while (pud++, addr = next, addr != end);
>  
>  	if (hyp_pud_table_empty(start_pud))
> +		clear_hyp_p4d_entry(p4d);
> +}
> +
> +static void unmap_hyp_p4ds(pgd_t *pgd, phys_addr_t addr, phys_addr_t end)
> +{
> +	phys_addr_t next;
> +	p4d_t *p4d, *start_p4d;
> +
> +	start_p4d = p4d = p4d_offset(pgd, addr);
> +	do {
> +		next = p4d_addr_end(addr, end);
> +		/* Hyp doesn't use huge p4ds */
> +		if (!p4d_none(*p4d))
> +			unmap_hyp_puds(p4d, addr, next);
> +	} while (p4d++, addr = next, addr != end);
> +
> +	if (hyp_p4d_table_empty(start_p4d))
>  		clear_hyp_pgd_entry(pgd);
>  }
>  
> @@ -548,7 +622,7 @@ static void __unmap_hyp_range(pgd_t *pgd
>  	do {
>  		next = pgd_addr_end(addr, end);
>  		if (!pgd_none(*pgd))
> -			unmap_hyp_puds(pgd, addr, next);
> +			unmap_hyp_p4ds(pgd, addr, next);
>  	} while (pgd++, addr = next, addr != end);
>  }
>  
> @@ -658,7 +732,7 @@ static int create_hyp_pmd_mappings(pud_t
>  	return 0;
>  }
>  
> -static int create_hyp_pud_mappings(pgd_t *pgd, unsigned long start,
> +static int create_hyp_pud_mappings(p4d_t *p4d, unsigned long start,
>  				   unsigned long end, unsigned long pfn,
>  				   pgprot_t prot)
>  {
> @@ -669,7 +743,7 @@ static int create_hyp_pud_mappings(pgd_t
>  
>  	addr = start;
>  	do {
> -		pud = pud_offset(pgd, addr);
> +		pud = pud_offset(p4d, addr);
>  
>  		if (pud_none_or_clear_bad(pud)) {
>  			pmd = pmd_alloc_one(NULL, addr);
> @@ -691,12 +765,45 @@ static int create_hyp_pud_mappings(pgd_t
>  	return 0;
>  }
>  
> +static int create_hyp_p4d_mappings(pgd_t *pgd, unsigned long start,
> +				   unsigned long end, unsigned long pfn,
> +				   pgprot_t prot)
> +{
> +	p4d_t *p4d;
> +	pud_t *pud;
> +	unsigned long addr, next;
> +	int ret;
> +
> +	addr = start;
> +	do {
> +		p4d = p4d_offset(pgd, addr);
> +
> +		if (p4d_none(*p4d)) {
> +			pud = pud_alloc_one(NULL, addr);
> +			if (!pud) {
> +				kvm_err("Cannot allocate Hyp pud\n");
> +				return -ENOMEM;
> +			}
> +			kvm_p4d_populate(p4d, pud);
> +			get_page(virt_to_page(p4d));
> +		}
> +
> +		next = p4d_addr_end(addr, end);
> +		ret = create_hyp_pud_mappings(p4d, addr, next, pfn, prot);
> +		if (ret)
> +			return ret;
> +		pfn += (next - addr) >> PAGE_SHIFT;
> +	} while (addr = next, addr != end);
> +
> +	return 0;
> +}
> +
>  static int __create_hyp_mappings(pgd_t *pgdp, unsigned long ptrs_per_pgd,
>  				 unsigned long start, unsigned long end,
>  				 unsigned long pfn, pgprot_t prot)
>  {
>  	pgd_t *pgd;
> -	pud_t *pud;
> +	p4d_t *p4d;
>  	unsigned long addr, next;
>  	int err = 0;
>  
> @@ -707,18 +814,18 @@ static int __create_hyp_mappings(pgd_t *
>  		pgd = pgdp + kvm_pgd_index(addr, ptrs_per_pgd);
>  
>  		if (pgd_none(*pgd)) {
> -			pud = pud_alloc_one(NULL, addr);
> -			if (!pud) {
> -				kvm_err("Cannot allocate Hyp pud\n");
> +			p4d = p4d_alloc_one(NULL, addr);
> +			if (!p4d) {
> +				kvm_err("Cannot allocate Hyp p4d\n");
>  				err = -ENOMEM;
>  				goto out;
>  			}
> -			kvm_pgd_populate(pgd, pud);
> +			kvm_pgd_populate(pgd, p4d);
>  			get_page(virt_to_page(pgd));
>  		}
>  
>  		next = pgd_addr_end(addr, end);
> -		err = create_hyp_pud_mappings(pgd, addr, next, pfn, prot);
> +		err = create_hyp_p4d_mappings(pgd, addr, next, pfn, prot);
>  		if (err)
>  			goto out;
>  		pfn += (next - addr) >> PAGE_SHIFT;
> @@ -1015,22 +1122,40 @@ void kvm_free_stage2_pgd(struct kvm *kvm
>  		free_pages_exact(pgd, stage2_pgd_size(kvm));
>  }
>  
> -static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
> +static p4d_t *stage2_get_p4d(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
>  			     phys_addr_t addr)
>  {
>  	pgd_t *pgd;
> -	pud_t *pud;
> +	p4d_t *p4d;
>  
>  	pgd = kvm->arch.pgd + stage2_pgd_index(kvm, addr);
>  	if (stage2_pgd_none(kvm, *pgd)) {
>  		if (!cache)
>  			return NULL;
> -		pud = mmu_memory_cache_alloc(cache);
> -		stage2_pgd_populate(kvm, pgd, pud);
> +		p4d = mmu_memory_cache_alloc(cache);
> +		stage2_pgd_populate(kvm, pgd, p4d);
>  		get_page(virt_to_page(pgd));
>  	}
>  
> -	return stage2_pud_offset(kvm, pgd, addr);
> +	return stage2_p4d_offset(kvm, pgd, addr);
> +}
> +
> +static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
> +			     phys_addr_t addr)
> +{
> +	p4d_t *p4d;
> +	pud_t *pud;
> +
> +	p4d = stage2_get_p4d(kvm, cache, addr);
> +	if (stage2_p4d_none(kvm, *p4d)) {
> +		if (!cache)
> +			return NULL;
> +		pud = mmu_memory_cache_alloc(cache);
> +		stage2_p4d_populate(kvm, p4d, pud);
> +		get_page(virt_to_page(p4d));
> +	}
> +
> +	return stage2_pud_offset(kvm, p4d, addr);
>  }
>  
>  static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
> @@ -1423,18 +1548,18 @@ static void stage2_wp_pmds(struct kvm *k
>  }
>  
>  /**
> - * stage2_wp_puds - write protect PGD range
> + * stage2_wp_puds - write protect P4D range
>   * @pgd:	pointer to pgd entry
>   * @addr:	range start address
>   * @end:	range end address
>   */
> -static void  stage2_wp_puds(struct kvm *kvm, pgd_t *pgd,
> +static void  stage2_wp_puds(struct kvm *kvm, p4d_t *p4d,
>  			    phys_addr_t addr, phys_addr_t end)
>  {
>  	pud_t *pud;
>  	phys_addr_t next;
>  
> -	pud = stage2_pud_offset(kvm, pgd, addr);
> +	pud = stage2_pud_offset(kvm, p4d, addr);
>  	do {
>  		next = stage2_pud_addr_end(kvm, addr, end);
>  		if (!stage2_pud_none(kvm, *pud)) {
> @@ -1449,6 +1574,26 @@ static void  stage2_wp_puds(struct kvm *
>  }
>  
>  /**
> + * stage2_wp_p4ds - write protect PGD range
> + * @pgd:	pointer to pgd entry
> + * @addr:	range start address
> + * @end:	range end address
> + */
> +static void  stage2_wp_p4ds(struct kvm *kvm, pgd_t *pgd,
> +			    phys_addr_t addr, phys_addr_t end)
> +{
> +	p4d_t *p4d;
> +	phys_addr_t next;
> +
> +	p4d = stage2_p4d_offset(kvm, pgd, addr);
> +	do {
> +		next = stage2_p4d_addr_end(kvm, addr, end);
> +		if (!stage2_p4d_none(kvm, *p4d))
> +			stage2_wp_puds(kvm, p4d, addr, next);
> +	} while (p4d++, addr = next, addr != end);
> +}
> +
> +/**
>   * stage2_wp_range() - write protect stage2 memory region range
>   * @kvm:	The KVM pointer
>   * @addr:	Start address of range
> @@ -1475,7 +1620,7 @@ static void stage2_wp_range(struct kvm *
>  			break;
>  		next = stage2_pgd_addr_end(kvm, addr, end);
>  		if (stage2_pgd_present(kvm, *pgd))
> -			stage2_wp_puds(kvm, pgd, addr, next);
> +			stage2_wp_p4ds(kvm, pgd, addr, next);
>  	} while (pgd++, addr = next, addr != end);
>  }
>  
> --- a/arch/arm64/mm/fault.c~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/mm/fault.c
> @@ -145,6 +145,7 @@ static void show_pte(unsigned long addr)
>  	pr_alert("[%016lx] pgd=%016llx", addr, pgd_val(pgd));
>  
>  	do {
> +		p4d_t *p4dp, p4d;
>  		pud_t *pudp, pud;
>  		pmd_t *pmdp, pmd;
>  		pte_t *ptep, pte;
> @@ -152,7 +153,13 @@ static void show_pte(unsigned long addr)
>  		if (pgd_none(pgd) || pgd_bad(pgd))
>  			break;
>  
> -		pudp = pud_offset(pgdp, addr);
> +		p4dp = p4d_offset(pgdp, addr);
> +		p4d = READ_ONCE(*p4dp);
> +		pr_cont(", p4d=%016llx", p4d_val(p4d));
> +		if (p4d_none(p4d) || p4d_bad(p4d))
> +			break;
> +
> +		pudp = pud_offset(p4dp, addr);
>  		pud = READ_ONCE(*pudp);
>  		pr_cont(", pud=%016llx", pud_val(pud));
>  		if (pud_none(pud) || pud_bad(pud))
> --- a/arch/arm64/mm/hugetlbpage.c~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/mm/hugetlbpage.c
> @@ -67,11 +67,13 @@ static int find_num_contig(struct mm_str
>  			   pte_t *ptep, size_t *pgsize)
>  {
>  	pgd_t *pgdp = pgd_offset(mm, addr);
> +	p4d_t *p4dp;
>  	pud_t *pudp;
>  	pmd_t *pmdp;
>  
>  	*pgsize = PAGE_SIZE;
> -	pudp = pud_offset(pgdp, addr);
> +	p4dp = p4d_offset(pgdp, addr);
> +	pudp = pud_offset(p4dp, addr);
>  	pmdp = pmd_offset(pudp, addr);
>  	if ((pte_t *)pmdp == ptep) {
>  		*pgsize = PMD_SIZE;
> @@ -217,12 +219,14 @@ pte_t *huge_pte_alloc(struct mm_struct *
>  		      unsigned long addr, unsigned long sz)
>  {
>  	pgd_t *pgdp;
> +	p4d_t *p4dp;
>  	pud_t *pudp;
>  	pmd_t *pmdp;
>  	pte_t *ptep = NULL;
>  
>  	pgdp = pgd_offset(mm, addr);
> -	pudp = pud_alloc(mm, pgdp, addr);
> +	p4dp = p4d_offset(pgdp, addr);
> +	pudp = pud_alloc(mm, p4dp, addr);
>  	if (!pudp)
>  		return NULL;
>  
> @@ -261,6 +265,7 @@ pte_t *huge_pte_offset(struct mm_struct
>  		       unsigned long addr, unsigned long sz)
>  {
>  	pgd_t *pgdp;
> +	p4d_t *p4dp;
>  	pud_t *pudp, pud;
>  	pmd_t *pmdp, pmd;
>  
> @@ -268,7 +273,11 @@ pte_t *huge_pte_offset(struct mm_struct
>  	if (!pgd_present(READ_ONCE(*pgdp)))
>  		return NULL;
>  
> -	pudp = pud_offset(pgdp, addr);
> +	p4dp = p4d_offset(pgdp, addr);
> +	if (!p4d_present(READ_ONCE(*p4dp)))
> +		return NULL;
> +
> +	pudp = pud_offset(p4dp, addr);
>  	pud = READ_ONCE(*pudp);
>  	if (sz != PUD_SIZE && pud_none(pud))
>  		return NULL;
> --- a/arch/arm64/mm/kasan_init.c~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/mm/kasan_init.c
> @@ -84,17 +84,17 @@ static pmd_t *__init kasan_pmd_offset(pu
>  	return early ? pmd_offset_kimg(pudp, addr) : pmd_offset(pudp, addr);
>  }
>  
> -static pud_t *__init kasan_pud_offset(pgd_t *pgdp, unsigned long addr, int node,
> +static pud_t *__init kasan_pud_offset(p4d_t *p4dp, unsigned long addr, int node,
>  				      bool early)
>  {
> -	if (pgd_none(READ_ONCE(*pgdp))) {
> +	if (p4d_none(READ_ONCE(*p4dp))) {
>  		phys_addr_t pud_phys = early ?
>  				__pa_symbol(kasan_early_shadow_pud)
>  					: kasan_alloc_zeroed_page(node);
> -		__pgd_populate(pgdp, pud_phys, PMD_TYPE_TABLE);
> +		__p4d_populate(p4dp, pud_phys, PMD_TYPE_TABLE);
>  	}
>  
> -	return early ? pud_offset_kimg(pgdp, addr) : pud_offset(pgdp, addr);
> +	return early ? pud_offset_kimg(p4dp, addr) : pud_offset(p4dp, addr);
>  }
>  
>  static void __init kasan_pte_populate(pmd_t *pmdp, unsigned long addr,
> @@ -126,11 +126,11 @@ static void __init kasan_pmd_populate(pu
>  	} while (pmdp++, addr = next, addr != end && pmd_none(READ_ONCE(*pmdp)));
>  }
>  
> -static void __init kasan_pud_populate(pgd_t *pgdp, unsigned long addr,
> +static void __init kasan_pud_populate(p4d_t *p4dp, unsigned long addr,
>  				      unsigned long end, int node, bool early)
>  {
>  	unsigned long next;
> -	pud_t *pudp = kasan_pud_offset(pgdp, addr, node, early);
> +	pud_t *pudp = kasan_pud_offset(p4dp, addr, node, early);
>  
>  	do {
>  		next = pud_addr_end(addr, end);
> @@ -138,6 +138,18 @@ static void __init kasan_pud_populate(pg
>  	} while (pudp++, addr = next, addr != end && pud_none(READ_ONCE(*pudp)));
>  }
>  
> +static void __init kasan_p4d_populate(pgd_t *pgdp, unsigned long addr,
> +				      unsigned long end, int node, bool early)
> +{
> +	unsigned long next;
> +	p4d_t *p4dp = p4d_offset(pgdp, addr);
> +
> +	do {
> +		next = p4d_addr_end(addr, end);
> +		kasan_pud_populate(p4dp, addr, next, node, early);
> +	} while (p4dp++, addr = next, addr != end);
> +}
> +
>  static void __init kasan_pgd_populate(unsigned long addr, unsigned long end,
>  				      int node, bool early)
>  {
> @@ -147,7 +159,7 @@ static void __init kasan_pgd_populate(un
>  	pgdp = pgd_offset_k(addr);
>  	do {
>  		next = pgd_addr_end(addr, end);
> -		kasan_pud_populate(pgdp, addr, next, node, early);
> +		kasan_p4d_populate(pgdp, addr, next, node, early);
>  	} while (pgdp++, addr = next, addr != end);
>  }
>  
> --- a/arch/arm64/mm/mmu.c~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/mm/mmu.c
> @@ -290,18 +290,19 @@ static void alloc_init_pud(pgd_t *pgdp,
>  {
>  	unsigned long next;
>  	pud_t *pudp;
> -	pgd_t pgd = READ_ONCE(*pgdp);
> +	p4d_t *p4dp = p4d_offset(pgdp, addr);
> +	p4d_t p4d = READ_ONCE(*p4dp);
>  
> -	if (pgd_none(pgd)) {
> +	if (p4d_none(p4d)) {
>  		phys_addr_t pud_phys;
>  		BUG_ON(!pgtable_alloc);
>  		pud_phys = pgtable_alloc(PUD_SHIFT);
> -		__pgd_populate(pgdp, pud_phys, PUD_TYPE_TABLE);
> -		pgd = READ_ONCE(*pgdp);
> +		__p4d_populate(p4dp, pud_phys, PUD_TYPE_TABLE);
> +		p4d = READ_ONCE(*p4dp);
>  	}
> -	BUG_ON(pgd_bad(pgd));
> +	BUG_ON(p4d_bad(p4d));
>  
> -	pudp = pud_set_fixmap_offset(pgdp, addr);
> +	pudp = pud_set_fixmap_offset(p4dp, addr);
>  	do {
>  		pud_t old_pud = READ_ONCE(*pudp);
>  
> @@ -672,6 +673,7 @@ static void __init map_kernel(pgd_t *pgd
>  			READ_ONCE(*pgd_offset_k(FIXADDR_START)));
>  	} else if (CONFIG_PGTABLE_LEVELS > 3) {
>  		pgd_t *bm_pgdp;
> +		p4d_t *bm_p4dp;
>  		pud_t *bm_pudp;
>  		/*
>  		 * The fixmap shares its top level pgd entry with the kernel
> @@ -681,7 +683,8 @@ static void __init map_kernel(pgd_t *pgd
>  		 */
>  		BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
>  		bm_pgdp = pgd_offset_raw(pgdp, FIXADDR_START);
> -		bm_pudp = pud_set_fixmap_offset(bm_pgdp, FIXADDR_START);
> +		bm_p4dp = p4d_offset(bm_pgdp, FIXADDR_START);
> +		bm_pudp = pud_set_fixmap_offset(bm_p4dp, FIXADDR_START);
>  		pud_populate(&init_mm, bm_pudp, lm_alias(bm_pmd));
>  		pud_clear_fixmap();
>  	} else {
> @@ -715,6 +718,7 @@ void __init paging_init(void)
>  int kern_addr_valid(unsigned long addr)
>  {
>  	pgd_t *pgdp;
> +	p4d_t *p4dp;
>  	pud_t *pudp, pud;
>  	pmd_t *pmdp, pmd;
>  	pte_t *ptep, pte;
> @@ -726,7 +730,11 @@ int kern_addr_valid(unsigned long addr)
>  	if (pgd_none(READ_ONCE(*pgdp)))
>  		return 0;
>  
> -	pudp = pud_offset(pgdp, addr);
> +	p4dp = p4d_offset(pgdp, addr);
> +	if (p4d_none(READ_ONCE(*p4dp)))
> +		return 0;
> +
> +	pudp = pud_offset(p4dp, addr);
>  	pud = READ_ONCE(*pudp);
>  	if (pud_none(pud))
>  		return 0;
> @@ -1069,6 +1077,7 @@ int __meminit vmemmap_populate(unsigned
>  	unsigned long addr = start;
>  	unsigned long next;
>  	pgd_t *pgdp;
> +	p4d_t *p4dp;
>  	pud_t *pudp;
>  	pmd_t *pmdp;
>  
> @@ -1079,7 +1088,11 @@ int __meminit vmemmap_populate(unsigned
>  		if (!pgdp)
>  			return -ENOMEM;
>  
> -		pudp = vmemmap_pud_populate(pgdp, addr, node);
> +		p4dp = vmemmap_p4d_populate(pgdp, addr, node);
> +		if (!p4dp)
> +			return -ENOMEM;
> +
> +		pudp = vmemmap_pud_populate(p4dp, addr, node);
>  		if (!pudp)
>  			return -ENOMEM;
>  
> @@ -1114,11 +1127,12 @@ void vmemmap_free(unsigned long start, u
>  static inline pud_t * fixmap_pud(unsigned long addr)
>  {
>  	pgd_t *pgdp = pgd_offset_k(addr);
> -	pgd_t pgd = READ_ONCE(*pgdp);
> +	p4d_t *p4dp = p4d_offset(pgdp, addr);
> +	p4d_t p4d = READ_ONCE(*p4dp);
>  
> -	BUG_ON(pgd_none(pgd) || pgd_bad(pgd));
> +	BUG_ON(p4d_none(p4d) || p4d_bad(p4d));
>  
> -	return pud_offset_kimg(pgdp, addr);
> +	return pud_offset_kimg(p4dp, addr);
>  }
>  
>  static inline pmd_t * fixmap_pmd(unsigned long addr)
> @@ -1144,25 +1158,27 @@ static inline pte_t * fixmap_pte(unsigne
>   */
>  void __init early_fixmap_init(void)
>  {
> -	pgd_t *pgdp, pgd;
> +	pgd_t *pgdp;
> +	p4d_t *p4dp, p4d;
>  	pud_t *pudp;
>  	pmd_t *pmdp;
>  	unsigned long addr = FIXADDR_START;
>  
>  	pgdp = pgd_offset_k(addr);
> -	pgd = READ_ONCE(*pgdp);
> +	p4dp = p4d_offset(pgdp, addr);
> +	p4d = READ_ONCE(*p4dp);
>  	if (CONFIG_PGTABLE_LEVELS > 3 &&
> -	    !(pgd_none(pgd) || pgd_page_paddr(pgd) == __pa_symbol(bm_pud))) {
> +	    !(p4d_none(p4d) || p4d_page_paddr(p4d) == __pa_symbol(bm_pud))) {
>  		/*
>  		 * We only end up here if the kernel mapping and the fixmap
>  		 * share the top level pgd entry, which should only happen on
>  		 * 16k/4 levels configurations.
>  		 */
>  		BUG_ON(!IS_ENABLED(CONFIG_ARM64_16K_PAGES));
> -		pudp = pud_offset_kimg(pgdp, addr);
> +		pudp = pud_offset_kimg(p4dp, addr);
>  	} else {
> -		if (pgd_none(pgd))
> -			__pgd_populate(pgdp, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
> +		if (p4d_none(p4d))
> +			__p4d_populate(p4dp, __pa_symbol(bm_pud), PUD_TYPE_TABLE);
>  		pudp = fixmap_pud(addr);
>  	}
>  	if (pud_none(READ_ONCE(*pudp)))
> --- a/arch/arm64/mm/pageattr.c~arm64-add-support-for-folded-p4d-page-tables
> +++ a/arch/arm64/mm/pageattr.c
> @@ -198,6 +198,7 @@ void __kernel_map_pages(struct page *pag
>  bool kernel_page_present(struct page *page)
>  {
>  	pgd_t *pgdp;
> +	p4d_t *p4dp;
>  	pud_t *pudp, pud;
>  	pmd_t *pmdp, pmd;
>  	pte_t *ptep;
> @@ -210,7 +211,11 @@ bool kernel_page_present(struct page *pa
>  	if (pgd_none(READ_ONCE(*pgdp)))
>  		return false;
>  
> -	pudp = pud_offset(pgdp, addr);
> +	p4dp = p4d_offset(pgdp, addr);
> +	if (p4d_none(READ_ONCE(*p4dp)))
> +		return false;
> +
> +	pudp = pud_offset(p4dp, addr);
>  	pud = READ_ONCE(*pudp);
>  	if (pud_none(pud))
>  		return false;
> _
> 

-- 
Sincerely yours,
Mike.

_______________________________________________
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 v2 4/8] iio: stm32-dfsdm-adc: pass iio device as arg for the interrupt handler
From: Jonathan Cameron @ 2020-05-16 17:20 UTC (permalink / raw)
  To: Alexandru Ardelean
  Cc: alexandre.belloni, alexandre.torgue, linux-iio, linux-kernel,
	ludovic.desroches, ak, mcoquelin.stm32, eugen.hristev,
	linux-stm32, linux-arm-kernel
In-Reply-To: <20200514131710.84201-5-alexandru.ardelean@analog.com>

On Thu, 14 May 2020 16:17:06 +0300
Alexandru Ardelean <alexandru.ardelean@analog.com> wrote:

> This changes the argument for the interrupt handler to be the IIO device
> instead of the state-struct.
> Since there will be some changes to how iio_priv_to_dev() is implemented,
> it could be that the helper becomes a bit slower, as it will be hidden away
> in the IIO core.
> 
> The iio_priv() call will still be fast enough, as it will return a void
> pointer from the public IIO device structure. So it's better to switch the
> order.
> 
> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
Whilst this one looks fine to me. I'd definitely like an Ack from
one of the stm people in case I'm missing something.

> ---
>  drivers/iio/adc/stm32-dfsdm-adc.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/iio/adc/stm32-dfsdm-adc.c b/drivers/iio/adc/stm32-dfsdm-adc.c
> index 76a60d93fe23..28ef02887bd3 100644
> --- a/drivers/iio/adc/stm32-dfsdm-adc.c
> +++ b/drivers/iio/adc/stm32-dfsdm-adc.c
> @@ -1313,8 +1313,8 @@ static const struct iio_info stm32_dfsdm_info_adc = {
>  
>  static irqreturn_t stm32_dfsdm_irq(int irq, void *arg)
>  {
> -	struct stm32_dfsdm_adc *adc = arg;
> -	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
> +	struct iio_dev *indio_dev = arg;
> +	struct stm32_dfsdm_adc *adc = iio_priv(indio_dev);
>  	struct regmap *regmap = adc->dfsdm->regmap;
>  	unsigned int status, int_en;
>  
> @@ -1603,7 +1603,7 @@ static int stm32_dfsdm_adc_probe(struct platform_device *pdev)
>  		return irq;
>  
>  	ret = devm_request_irq(dev, irq, stm32_dfsdm_irq,
> -			       0, pdev->name, adc);
> +			       0, pdev->name, iio);
>  	if (ret < 0) {
>  		dev_err(dev, "Failed to request IRQ\n");
>  		return ret;


_______________________________________________
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 v2 5/8] iio: stm32-adc: pass iio device as arg for the interrupt handler
From: Jonathan Cameron @ 2020-05-16 17:21 UTC (permalink / raw)
  To: Alexandru Ardelean
  Cc: alexandre.belloni, alexandre.torgue, linux-iio, linux-kernel,
	ludovic.desroches, ak, mcoquelin.stm32, eugen.hristev,
	linux-stm32, linux-arm-kernel
In-Reply-To: <20200514131710.84201-6-alexandru.ardelean@analog.com>

On Thu, 14 May 2020 16:17:07 +0300
Alexandru Ardelean <alexandru.ardelean@analog.com> wrote:

> This changes the argument for the interrupt handler to be the IIO device
> instead of the state-struct.
> Since there will be some changes to how iio_priv_to_dev() is implemented,
> it could be that the helper becomes a bit slower, as it will be hidden away
> in the IIO core.
> 
> The iio_priv() call will still be fast enough, as it will return a void
> pointer from the public IIO device structure. So it's better to switch the
> order.
> 
> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
As with previous patch - looks good to me, but I'd like an stm32
Ack / review.

thanks,

Jonathan

> ---
>  drivers/iio/adc/stm32-adc.c | 10 +++++-----
>  1 file changed, 5 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/iio/adc/stm32-adc.c b/drivers/iio/adc/stm32-adc.c
> index 80c3f963527b..34885387fbdb 100644
> --- a/drivers/iio/adc/stm32-adc.c
> +++ b/drivers/iio/adc/stm32-adc.c
> @@ -1227,8 +1227,8 @@ static int stm32_adc_read_raw(struct iio_dev *indio_dev,
>  
>  static irqreturn_t stm32_adc_threaded_isr(int irq, void *data)
>  {
> -	struct stm32_adc *adc = data;
> -	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
> +	struct iio_dev *indio_dev = data;
> +	struct stm32_adc *adc = iio_priv(indio_dev);
>  	const struct stm32_adc_regspec *regs = adc->cfg->regs;
>  	u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg);
>  
> @@ -1240,8 +1240,8 @@ static irqreturn_t stm32_adc_threaded_isr(int irq, void *data)
>  
>  static irqreturn_t stm32_adc_isr(int irq, void *data)
>  {
> -	struct stm32_adc *adc = data;
> -	struct iio_dev *indio_dev = iio_priv_to_dev(adc);
> +	struct iio_dev *indio_dev = data;
> +	struct stm32_adc *adc = iio_priv(indio_dev);
>  	const struct stm32_adc_regspec *regs = adc->cfg->regs;
>  	u32 status = stm32_adc_readl(adc, regs->isr_eoc.reg);
>  
> @@ -1882,7 +1882,7 @@ static int stm32_adc_probe(struct platform_device *pdev)
>  
>  	ret = devm_request_threaded_irq(&pdev->dev, adc->irq, stm32_adc_isr,
>  					stm32_adc_threaded_isr,
> -					0, pdev->name, adc);
> +					0, pdev->name, indio_dev);
>  	if (ret) {
>  		dev_err(&pdev->dev, "failed to request IRQ\n");
>  		return ret;


_______________________________________________
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 v2 6/8] iio: core: wrap IIO device into an iio_dev_opaque object
From: Jonathan Cameron @ 2020-05-16 17:28 UTC (permalink / raw)
  To: Alexandru Ardelean
  Cc: alexandre.belloni, alexandre.torgue, linux-iio, linux-kernel,
	ludovic.desroches, ak, mcoquelin.stm32, eugen.hristev,
	linux-stm32, linux-arm-kernel
In-Reply-To: <20200514131710.84201-7-alexandru.ardelean@analog.com>

On Thu, 14 May 2020 16:17:08 +0300
Alexandru Ardelean <alexandru.ardelean@analog.com> wrote:

> There are plenty of bad designs we want to discourage or not have to review
> manually usually about accessing private (marked as [INTERN]) fields of
> 'struct iio_dev'.
> 
> Sometimes users copy drivers that are not always the best examples.
> 
> A better idea is to hide those fields into the framework.
> For 'struct iio_dev' this is a 'struct iio_dev_opaque' which wraps a public
> 'struct iio_dev' object.
> 
> In the next series, some fields will be moved to this new struct, each with
> it's own rework.
> 
> This rework will not be complete-able for a while, as many fields need some
> drivers to be reworked in order to finalize them (e.g. 'indio_dev->mlock').
> 
> But some fields can already be moved, and in time, all of them may get
> there (in the 'struct iio_dev_opaque' object).

Hopefully!  This is very nice.  One trivial comment inline.

> 
> Since a lot of drivers also call 'iio_priv()', in order to preserve
> fast-paths (where this matters), the public iio_dev object will have a
> 'priv' field that will have the pointer to the private information already
> computed. The reference returned by this field should be guaranteed to be
> cacheline aligned.
> 
> As for the 'iio_priv_to_dev()' helper, this needs to be hidden away. There
> aren't many users of this helper, and arguably drivers shouldn't need to
> use it in any fast-paths, as they can maintain a reference to the IIO
> device.
> 
> The opaque parts will be moved into the 'include/linux/iio/iio-opaque.h'
> header. Should the hidden information be required for some debugging or
> some special needs, it can be made available via this header.
> Otherwise, only the IIO core files should include this file.
> 
> Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
> ---
>  drivers/iio/industrialio-core.c | 27 ++++++++++++++++++++++-----
>  include/linux/iio/iio-opaque.h  | 17 +++++++++++++++++
>  include/linux/iio/iio.h         | 11 +++++------
>  3 files changed, 44 insertions(+), 11 deletions(-)
>  create mode 100644 include/linux/iio/iio-opaque.h
> 
> diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
> index 462d3e810013..a1b29e0f8fd6 100644
> --- a/drivers/iio/industrialio-core.c
> +++ b/drivers/iio/industrialio-core.c
> @@ -25,6 +25,7 @@
>  #include <linux/debugfs.h>
>  #include <linux/mutex.h>
>  #include <linux/iio/iio.h>
> +#include <linux/iio/iio-opaque.h>
>  #include "iio_core.h"
>  #include "iio_core_trigger.h"
>  #include <linux/iio/sysfs.h>
> @@ -164,6 +165,15 @@ static const char * const iio_chan_info_postfix[] = {
>  	[IIO_CHAN_INFO_THERMOCOUPLE_TYPE] = "thermocouple_type",
>  };
>  
> +struct iio_dev *iio_priv_to_dev(void *priv)
> +{
> +	struct iio_dev_opaque *iio_dev_opaque =
> +		(struct iio_dev_opaque *)((char *)priv -
> +				  ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN));
> +	return &iio_dev_opaque->indio_dev;
> +}
> +EXPORT_SYMBOL_GPL(iio_priv_to_dev);
> +
>  /**
>   * iio_find_channel_from_si() - get channel from its scan index
>   * @indio_dev:		device
> @@ -1476,6 +1486,8 @@ static void iio_device_unregister_sysfs(struct iio_dev *indio_dev)
>  static void iio_dev_release(struct device *device)
>  {
>  	struct iio_dev *indio_dev = dev_to_iio_dev(device);
> +	struct iio_dev_opaque *iio_dev_opaque = to_iio_dev_opaque(indio_dev);
> +
>  	if (indio_dev->modes & INDIO_ALL_TRIGGERED_MODES)
>  		iio_device_unregister_trigger_consumer(indio_dev);
>  	iio_device_unregister_eventset(indio_dev);
> @@ -1484,7 +1496,7 @@ static void iio_dev_release(struct device *device)
>  	iio_buffer_put(indio_dev->buffer);
>  
>  	ida_simple_remove(&iio_ida, indio_dev->id);
> -	kfree(indio_dev);
> +	kfree(iio_dev_opaque);
>  }
>  
>  struct device_type iio_device_type = {
> @@ -1498,10 +1510,11 @@ struct device_type iio_device_type = {
>   **/
>  struct iio_dev *iio_device_alloc(int sizeof_priv)
>  {
> +	struct iio_dev_opaque *iio_dev_opaque;
>  	struct iio_dev *dev;
>  	size_t alloc_size;
>  
> -	alloc_size = sizeof(struct iio_dev);
> +	alloc_size = sizeof(struct iio_dev_opaque);
>  	if (sizeof_priv) {
>  		alloc_size = ALIGN(alloc_size, IIO_ALIGN);
>  		alloc_size += sizeof_priv;
> @@ -1509,10 +1522,14 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
>  	/* ensure 32-byte alignment of whole construct ? */
>  	alloc_size += IIO_ALIGN - 1;
>  
> -	dev = kzalloc(alloc_size, GFP_KERNEL);
> -	if (!dev)
> +	iio_dev_opaque = kzalloc(alloc_size, GFP_KERNEL);
> +	if (!iio_dev_opaque)
>  		return NULL;
>  
> +	dev = &iio_dev_opaque->indio_dev;
> +	dev->priv = (char *)iio_dev_opaque +
> +		ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN);
> +
>  	dev->dev.groups = dev->groups;
>  	dev->dev.type = &iio_device_type;
>  	dev->dev.bus = &iio_bus_type;
> @@ -1526,7 +1543,7 @@ struct iio_dev *iio_device_alloc(int sizeof_priv)
>  	if (dev->id < 0) {
>  		/* cannot use a dev_err as the name isn't available */
>  		pr_err("failed to get device id\n");
> -		kfree(dev);
> +		kfree(iio_dev_opaque);
>  		return NULL;
>  	}
>  	dev_set_name(&dev->dev, "iio:device%d", dev->id);
> diff --git a/include/linux/iio/iio-opaque.h b/include/linux/iio/iio-opaque.h
> new file mode 100644
> index 000000000000..1375674f14cd
> --- /dev/null
> +++ b/include/linux/iio/iio-opaque.h
> @@ -0,0 +1,17 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +
> +#ifndef _INDUSTRIAL_IO_OPAQUE_H_
> +#define _INDUSTRIAL_IO_OPAQUE_H_
> +
> +/**
> + * struct iio_dev_opaque - industrial I/O device opaque information
> + * @indio_dev:			public industrial I/O device information
> + */
> +struct iio_dev_opaque {
> +	struct iio_dev			indio_dev;
> +};
> +
> +#define to_iio_dev_opaque(indio_dev)		\
> +	container_of(indio_dev, struct iio_dev_opaque, indio_dev)
> +
> +#endif
> diff --git a/include/linux/iio/iio.h b/include/linux/iio/iio.h
> index 5f9f439a4f01..e82693db6578 100644
> --- a/include/linux/iio/iio.h
> +++ b/include/linux/iio/iio.h
> @@ -522,6 +522,7 @@ struct iio_buffer_setup_ops {
>   * @flags:		[INTERN] file ops related flags including busy flag.
>   * @debugfs_dentry:	[INTERN] device specific debugfs dentry.
>   * @cached_reg_addr:	[INTERN] cached register address for debugfs reads.
> + * @priv:		[DRIVER] reference to driver's private information
Add a note to this to say it should be accessed only through the
iio_priv() route.  Whilst it's not opaque we might in theory change
what it does sometime in the future - just like we are doing here :)

>   */
>  struct iio_dev {
>  	int				id;
> @@ -571,6 +572,7 @@ struct iio_dev {
>  	char				read_buf[20];
>  	unsigned int			read_buf_len;
>  #endif
> +	void				*priv;
>  };
>  
>  const struct iio_chan_spec
> @@ -678,16 +680,13 @@ static inline void *iio_device_get_drvdata(struct iio_dev *indio_dev)
>  #define IIO_ALIGN L1_CACHE_BYTES
>  struct iio_dev *iio_device_alloc(int sizeof_priv);
>  
> +/* The information at this reference is guaranteed to be cacheline aligned */
>  static inline void *iio_priv(const struct iio_dev *indio_dev)
>  {
> -	return (char *)indio_dev + ALIGN(sizeof(struct iio_dev), IIO_ALIGN);
> +	return indio_dev->priv;
>  }
>  
> -static inline struct iio_dev *iio_priv_to_dev(void *priv)
> -{
> -	return (struct iio_dev *)((char *)priv -
> -				  ALIGN(sizeof(struct iio_dev), IIO_ALIGN));
> -}
> +struct iio_dev *iio_priv_to_dev(void *priv);
>  
>  void iio_device_free(struct iio_dev *indio_dev);
>  struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv);


_______________________________________________
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 v2 7/8] iio: core: simplify alloc alignment code
From: Jonathan Cameron @ 2020-05-16 17:30 UTC (permalink / raw)
  To: Sa, Nuno
  Cc: alexandre.belloni@bootlin.com, alexandre.torgue@st.com,
	linux-iio@vger.kernel.org, linux-kernel@vger.kernel.org,
	ludovic.desroches@microchip.com, ak@it-klinger.de,
	mcoquelin.stm32@gmail.com, eugen.hristev@microchip.com,
	Ardelean, Alexandru, linux-stm32@st-md-mailman.stormreply.com,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <BN6PR03MB3347D0598B1700D1A5C6974C99BD0@BN6PR03MB3347.namprd03.prod.outlook.com>

On Fri, 15 May 2020 12:37:28 +0000
"Sa, Nuno" <Nuno.Sa@analog.com> wrote:

> > From: Ardelean, Alexandru <alexandru.Ardelean@analog.com>
> > Sent: Freitag, 15. Mai 2020 13:48
> > To: linux-arm-kernel@lists.infradead.org; linux-stm32@st-md-
> > mailman.stormreply.com; Sa, Nuno <Nuno.Sa@analog.com>; linux-
> > kernel@vger.kernel.org; linux-iio@vger.kernel.org
> > Cc: ludovic.desroches@microchip.com; nicolas.ferre@microchip.com;
> > alexandre.torgue@st.com; ak@it-klinger.de; jic23@kernel.org;
> > eugen.hristev@microchip.com; mcoquelin.stm32@gmail.com;
> > alexandre.belloni@bootlin.com
> > Subject: Re: [PATCH v2 7/8] iio: core: simplify alloc alignment code
> > 
> > On Fri, 2020-05-15 at 07:12 +0000, Sa, Nuno wrote:  
> > > Hey Alex,
> > >
> > > Just a small question...
> > >  
> > > > From: linux-iio-owner@vger.kernel.org <linux-iio-  
> > owner@vger.kernel.org>  
> > > > On Behalf Of Alexandru Ardelean
> > > > Sent: Donnerstag, 14. Mai 2020 15:17
> > > > To: linux-iio@vger.kernel.org; linux-arm-kernel@lists.infradead.org;  
> > linux-  
> > > > stm32@st-md-mailman.stormreply.com; linux-kernel@vger.kernel.org
> > > > Cc: ludovic.desroches@microchip.com; eugen.hristev@microchip.com;
> > > > jic23@kernel.org; nicolas.ferre@microchip.com;
> > > > alexandre.belloni@bootlin.com; alexandre.torgue@st.com;
> > > > mcoquelin.stm32@gmail.com; ak@it-klinger.de; Ardelean, Alexandru
> > > > <alexandru.Ardelean@analog.com>
> > > > Subject: [PATCH v2 7/8] iio: core: simplify alloc alignment code
> > > >
> > > > There was a recent discussion about this code:
> > > >   https://urldefense.com/v3/__https://lore.kernel.org/linux-
> > > >  
> > iio/20200322165317.0b1f0674@archlinux/__;!!A3Ni8CS0y2Y!pgdUSayJCfxMiE  
> > > > w8Fpv0LkEZurCSkX0sEcLnXeDSCLmhpu1xont6-vBQj3ZbCw$
> > > >
> > > > This looks like a good time to rework this, since any issues about it
> > > > should pop-up under testing, because the iio_dev is having a bit of an
> > > > overhaul and stuff being moved to iio_dev_priv.
> > > >
> > > > Signed-off-by: Alexandru Ardelean <alexandru.ardelean@analog.com>
> > > > ---
> > > >  drivers/iio/industrialio-core.c | 10 +++-------
> > > >  1 file changed, 3 insertions(+), 7 deletions(-)
> > > >
> > > > diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-
> > > > core.c
> > > > index a1b29e0f8fd6..7671d36efae7 100644
> > > > --- a/drivers/iio/industrialio-core.c
> > > > +++ b/drivers/iio/industrialio-core.c
> > > > @@ -1514,13 +1514,9 @@ struct iio_dev *iio_device_alloc(int  
> > sizeof_priv)  
> > > >  	struct iio_dev *dev;
> > > >  	size_t alloc_size;
> > > >
> > > > -	alloc_size = sizeof(struct iio_dev_opaque);
> > > > -	if (sizeof_priv) {
> > > > -		alloc_size = ALIGN(alloc_size, IIO_ALIGN);
> > > > -		alloc_size += sizeof_priv;
> > > > -	}
> > > > -	/* ensure 32-byte alignment of whole construct ? */
> > > > -	alloc_size += IIO_ALIGN - 1;
> > > > +	alloc_size = ALIGN(sizeof(struct iio_dev_opaque), IIO_ALIGN);
> > > > +	if (sizeof_priv)
> > > > +		alloc_size += ALIGN(sizeof_priv, IIO_ALIGN);  
> > >
> > > Do we actually need to do the `ALIGN` again? It seems to me that  
> > `alloc_size  
> > > += sizeof_priv`
> > > would be enough or am I missing something obvious?  
> > 
> > Well, it's not always clear what value 'sizeof_priv' has, and whether it is
> > provided already aligned.
> > The requirement is usually that this data be cacheline aligned.
> > 
> > So, sizeof(struct iio_dev_opaque) is aligned already a few lines above, but
> > the
> > private information should also be aligned [given that it's an unknown value
> > provided by the driver].
> > I think this is mostly important, if we need to do DMA access to buffers
> > allocated on the driver's state-struct, which is allocated here, and which is
> > usually provided as sizeof_priv.  
> 
> Yes, AFAIU this is to guarantee that the priv struct will start at an address that is 
> DMA safe (cacheline-aligned). Hence, if there is any data in 'priv' that needs to be DMA
> safe, we are fine...
> 
> Well, I was also misreading the code. Still, I think it should look something like:
> 
> ````
> alloc_size = sizeof(struct iio_dev_opaque)
> if (sizeof_priv)
> 	alloc_size += ALIGN(alloc_size, IIO_ALIGN);
> ````
> 
> If there is no priv, I think we don't need the padding bytes...
Agreed - no need to guarantee alignment of something that doesn't exist :)

> 
> - Nuno Sá
> 


_______________________________________________
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 v9 2/6] arm: dts: mt2701: Add usb2 device nodes
From: Matthias Brugger @ 2020-05-16 17:31 UTC (permalink / raw)
  To: min.guo, Bin Liu, Rob Herring
  Cc: Mark Rutland, devicetree, tony, Greg Kroah-Hartman, linux-usb,
	linux-kernel, hdegoede, Alan Stern, chunfeng.yun, linux-mediatek,
	linux-arm-kernel
In-Reply-To: <20191211015446.11477-3-min.guo@mediatek.com>



On 11/12/2019 02:54, min.guo@mediatek.com wrote:
> From: Min Guo <min.guo@mediatek.com>
> 
> Add musb nodes and usb2 phy nodes for MT2701
> 
> Signed-off-by: Min Guo <min.guo@mediatek.com>

Applied now to v5.7-next/dts32

Sorry for the long delay!

> ---
> changes in v9:
> 1. Add usb-role-switch
> 2. Remove label of usb connector child node
> 3. Change usb connector child node compatible as "gpio-usb-b-connector", "usb-b-connector";
> 
> changes in v8:
> 1. no changes
> 
> changes in v7:
> 1. Change usb connector child node compatible as "gpio-usb-b-connector" 
> 
> changes in v6:
> 1. Modify usb connector child node
> 
> changes in v5:
> 1. Add usb connector child node
> 
> changes in v4:
> 1. no changes
> 
> changes in v3:
> 1. no changes
> 
> changes in v2:
> 1. Remove phy-names
> ---
>  arch/arm/boot/dts/mt2701-evb.dts | 21 ++++++++++++++++++++
>  arch/arm/boot/dts/mt2701.dtsi    | 33 ++++++++++++++++++++++++++++++++
>  2 files changed, 54 insertions(+)
> 
> diff --git a/arch/arm/boot/dts/mt2701-evb.dts b/arch/arm/boot/dts/mt2701-evb.dts
> index be0edb3dae6c..844ed3f971fe 100644
> --- a/arch/arm/boot/dts/mt2701-evb.dts
> +++ b/arch/arm/boot/dts/mt2701-evb.dts
> @@ -6,6 +6,7 @@
>   */
>  
>  /dts-v1/;
> +#include <dt-bindings/gpio/gpio.h>
>  #include "mt2701.dtsi"
>  
>  / {
> @@ -60,6 +61,15 @@ backlight_lcd: backlight_lcd {
>  		>;
>  		default-brightness-level = <9>;
>  	};
> +
> +	usb_vbus: regulator@0 {
> +		compatible = "regulator-fixed";
> +		regulator-name = "usb_vbus";
> +		regulator-min-microvolt = <5000000>;
> +		regulator-max-microvolt = <5000000>;
> +		gpio = <&pio 45 GPIO_ACTIVE_HIGH>;
> +		enable-active-high;
> +	};
>  };
>  
>  &auxadc {
> @@ -229,3 +239,14 @@ pins1 {
>  &uart0 {
>  	status = "okay";
>  };
> +
> +&usb2 {
> +	status = "okay";
> +	usb-role-switch;
> +	connector{
> +		compatible = "gpio-usb-b-connector", "usb-b-connector";
> +		type = "micro";
> +		id-gpios = <&pio 44 GPIO_ACTIVE_HIGH>;
> +		vbus-supply = <&usb_vbus>;
> +	};
> +};
> diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
> index 180377e56ef4..a6b1434e83fb 100644
> --- a/arch/arm/boot/dts/mt2701.dtsi
> +++ b/arch/arm/boot/dts/mt2701.dtsi
> @@ -670,6 +670,39 @@ u3port1: usb-phy@1a244900 {
>  		};
>  	};
>  
> +	usb2: usb@11200000 {
> +		compatible = "mediatek,mt2701-musb",
> +			     "mediatek,mtk-musb";
> +		reg = <0 0x11200000 0 0x1000>;
> +		interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_LOW>;
> +		interrupt-names = "mc";
> +		phys = <&u2port2 PHY_TYPE_USB2>;
> +		dr_mode = "otg";
> +		clocks = <&pericfg CLK_PERI_USB0>,
> +			 <&pericfg CLK_PERI_USB0_MCU>,
> +			 <&pericfg CLK_PERI_USB_SLV>;
> +		clock-names = "main","mcu","univpll";
> +		power-domains = <&scpsys MT2701_POWER_DOMAIN_IFR_MSC>;
> +		status = "disabled";
> +	};
> +
> +	u2phy0: usb-phy@11210000 {
> +		compatible = "mediatek,generic-tphy-v1";
> +		reg = <0 0x11210000 0 0x0800>;
> +		#address-cells = <2>;
> +		#size-cells = <2>;
> +		ranges;
> +		status = "okay";
> +
> +		u2port2: usb-phy@1a1c4800 {
> +			reg = <0 0x11210800 0 0x0100>;
> +			clocks = <&topckgen CLK_TOP_USB_PHY48M>;
> +			clock-names = "ref";
> +			#phy-cells = <1>;
> +			status = "okay";
> +		};
> +	};
> +
>  	ethsys: syscon@1b000000 {
>  		compatible = "mediatek,mt2701-ethsys", "syscon";
>  		reg = <0 0x1b000000 0 0x1000>;
> 

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

^ permalink raw reply

* [PATCH v3 5/5] scsi: ufs: Fix possible VCC power drain during runtime suspend
From: Stanley Chu @ 2020-05-16 17:46 UTC (permalink / raw)
  To: linux-scsi, martin.petersen, avri.altman, alim.akhtar, jejb,
	asutoshd
  Cc: bvanassche, andy.teng, chun-hung.wu, kuohong.wang, linux-kernel,
	cang, linux-mediatek, peter.wang, matthias.bgg, Stanley Chu,
	linux-arm-kernel, beanhuo
In-Reply-To: <20200516174615.15445-1-stanley.chu@mediatek.com>

The commit "scsi: ufs: Fix WriteBooster flush during runtime
suspend" promises essential resource, i.e., for UFS devices doing
WriteBooster buffer flush and Auto BKOPs. However if device
finishes its job but not resumed for a very long time, system
will have unnecessary power drain because VCC is still supplied.

To fix this, a method to recheck the threshold of keeping VCC
supply is required. However, the threshold recheck needs to
re-activate the link because the decision depends on the device
status.

Introduce a delayed work to force runtime resume after a certain
delay during runtime suspend. This makes threshold recheck simpler
which will be done in the next runtime-suspend.

Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
---
 drivers/scsi/ufs/ufs.h    |  1 +
 drivers/scsi/ufs/ufshcd.c | 43 ++++++++++++++++++++++++++++++++++-----
 drivers/scsi/ufs/ufshcd.h |  1 +
 3 files changed, 40 insertions(+), 5 deletions(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index db07eedfed96..c70845d41449 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -574,6 +574,7 @@ struct ufs_dev_info {
 	u32 d_ext_ufs_feature_sup;
 	u8 b_wb_buffer_type;
 	u32 d_wb_alloc_units;
+	bool b_rpm_dev_flush_capable;
 	u8 b_presrv_uspc_en;
 };
 
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f4f2c7b5ab0a..a137553f9b41 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -94,6 +94,9 @@
 /* default delay of autosuspend: 2000 ms */
 #define RPM_AUTOSUSPEND_DELAY_MS 2000
 
+/* Default delay of RPM device flush delayed work */
+#define RPM_DEV_FLUSH_RECHECK_WORK_DELAY_MS 5000
+
 /* Default value of wait time before gating device ref clock */
 #define UFSHCD_REF_CLK_GATING_WAIT_US 0xFF /* microsecs */
 
@@ -5310,7 +5313,7 @@ static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba,
 	return false;
 }
 
-static bool ufshcd_wb_keep_vcc_on(struct ufs_hba *hba)
+static bool ufshcd_wb_need_flush(struct ufs_hba *hba)
 {
 	int ret;
 	u32 avail_buf;
@@ -5348,6 +5351,21 @@ static bool ufshcd_wb_keep_vcc_on(struct ufs_hba *hba)
 	return ufshcd_wb_presrv_usrspc_keep_vcc_on(hba, avail_buf);
 }
 
+static void ufshcd_rpm_dev_flush_recheck_work(struct work_struct *work)
+{
+	struct ufs_hba *hba = container_of(to_delayed_work(work),
+					   struct ufs_hba,
+					   rpm_dev_flush_recheck_work);
+	/*
+	 * To prevent unnecessary VCC power drain after device finishes
+	 * WriteBooster buffer flush or Auto BKOPs, force runtime resume
+	 * after a certain delay to recheck the threshold by next runtime
+	 * supsend.
+	 */
+	pm_runtime_get_sync(hba->dev);
+	pm_runtime_put_sync(hba->dev);
+}
+
 /**
  * ufshcd_exception_event_handler - handle exceptions raised by device
  * @work: pointer to work data
@@ -8164,7 +8182,6 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 	enum ufs_pm_level pm_lvl;
 	enum ufs_dev_pwr_mode req_dev_pwr_mode;
 	enum uic_link_state req_link_state;
-	bool keep_curr_dev_pwr_mode = false;
 
 	hba->pm_op_in_progress = 1;
 	if (!ufshcd_is_shutdown_pm(pm_op)) {
@@ -8224,11 +8241,12 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 		 * Hibern8, keep device power mode as "active power mode"
 		 * and VCC supply.
 		 */
-		keep_curr_dev_pwr_mode = hba->auto_bkops_enabled ||
+		hba->dev_info.b_rpm_dev_flush_capable =
+			hba->auto_bkops_enabled ||
 			(((req_link_state == UIC_LINK_HIBERN8_STATE) ||
 			((req_link_state == UIC_LINK_ACTIVE_STATE) &&
 			ufshcd_is_auto_hibern8_enabled(hba))) &&
-			ufshcd_wb_keep_vcc_on(hba));
+			ufshcd_wb_need_flush(hba));
 	}
 
 	if (req_dev_pwr_mode != hba->curr_dev_pwr_mode) {
@@ -8238,7 +8256,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 			ufshcd_disable_auto_bkops(hba);
 		}
 
-		if (!keep_curr_dev_pwr_mode) {
+		if (!hba->dev_info.b_rpm_dev_flush_capable) {
 			ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
 			if (ret)
 				goto enable_gating;
@@ -8295,9 +8313,16 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 	if (hba->clk_scaling.is_allowed)
 		ufshcd_resume_clkscaling(hba);
 	hba->clk_gating.is_suspended = false;
+	hba->dev_info.b_rpm_dev_flush_capable = false;
 	ufshcd_release(hba);
 out:
+	if (hba->dev_info.b_rpm_dev_flush_capable) {
+		schedule_delayed_work(&hba->rpm_dev_flush_recheck_work,
+			msecs_to_jiffies(RPM_DEV_FLUSH_RECHECK_WORK_DELAY_MS));
+	}
+
 	hba->pm_op_in_progress = 0;
+
 	if (ret)
 		ufshcd_update_reg_hist(&hba->ufs_stats.suspend_err, (u32)ret);
 	return ret;
@@ -8386,6 +8411,11 @@ static int ufshcd_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 	/* Enable Auto-Hibernate if configured */
 	ufshcd_auto_hibern8_enable(hba);
 
+	if (hba->dev_info.b_rpm_dev_flush_capable) {
+		hba->dev_info.b_rpm_dev_flush_capable = false;
+		cancel_delayed_work(&hba->rpm_dev_flush_recheck_work);
+	}
+
 	/* Schedule clock gating in case of no access to UFS device yet */
 	ufshcd_release(hba);
 
@@ -8859,6 +8889,9 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq)
 						UFS_SLEEP_PWR_MODE,
 						UIC_LINK_HIBERN8_STATE);
 
+	INIT_DELAYED_WORK(&hba->rpm_dev_flush_recheck_work,
+			  ufshcd_rpm_dev_flush_recheck_work);
+
 	/* Set the default auto-hiberate idle timer value to 150 ms */
 	if (ufshcd_is_auto_hibern8_supported(hba) && !hba->ahit) {
 		hba->ahit = FIELD_PREP(UFSHCI_AHIBERN8_TIMER_MASK, 150) |
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index 8db7a6101892..9acd437037e8 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -745,6 +745,7 @@ struct ufs_hba {
 	struct request_queue	*bsg_queue;
 	bool wb_buf_flush_enabled;
 	bool wb_enabled;
+	struct delayed_work rpm_dev_flush_recheck_work;
 };
 
 /* Returns true if clocks can be gated. Otherwise false */
-- 
2.18.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 v3 4/5] scsi: ufs: Fix WriteBooster flush during runtime suspend
From: Stanley Chu @ 2020-05-16 17:46 UTC (permalink / raw)
  To: linux-scsi, martin.petersen, avri.altman, alim.akhtar, jejb,
	asutoshd
  Cc: bvanassche, andy.teng, chun-hung.wu, kuohong.wang, linux-kernel,
	cang, linux-mediatek, peter.wang, matthias.bgg, Stanley Chu,
	linux-arm-kernel, beanhuo
In-Reply-To: <20200516174615.15445-1-stanley.chu@mediatek.com>

Currently UFS host driver promises VCC supply if UFS device
needs to do WriteBooster flush during runtime suspend.

However the UFS specification mentions,

"While the flushing operation is in progress, the device is
in Active power mode."

Therefore UFS host driver needs to promise more: Keep UFS
device as "Active power mode", otherwise UFS device shall not
do any flush if device enters Sleep or PowerDown power mode.

Fix this by not changing device power mode if WriteBooster
flush is required in ufshcd_suspend().

Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
---
 drivers/scsi/ufs/ufs.h    |  1 -
 drivers/scsi/ufs/ufshcd.c | 42 ++++++++++++++++++++-------------------
 2 files changed, 22 insertions(+), 21 deletions(-)

diff --git a/drivers/scsi/ufs/ufs.h b/drivers/scsi/ufs/ufs.h
index fadba3a3bbcd..db07eedfed96 100644
--- a/drivers/scsi/ufs/ufs.h
+++ b/drivers/scsi/ufs/ufs.h
@@ -574,7 +574,6 @@ struct ufs_dev_info {
 	u32 d_ext_ufs_feature_sup;
 	u8 b_wb_buffer_type;
 	u32 d_wb_alloc_units;
-	bool keep_vcc_on;
 	u8 b_presrv_uspc_en;
 };
 
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index c7c2bd7860b8..f4f2c7b5ab0a 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -8094,8 +8094,7 @@ static void ufshcd_vreg_set_lpm(struct ufs_hba *hba)
 	    !hba->dev_info.is_lu_power_on_wp) {
 		ufshcd_setup_vreg(hba, false);
 	} else if (!ufshcd_is_ufs_dev_active(hba)) {
-		if (!hba->dev_info.keep_vcc_on)
-			ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
+		ufshcd_toggle_vreg(hba->dev, hba->vreg_info.vcc, false);
 		if (!ufshcd_is_link_active(hba)) {
 			ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq);
 			ufshcd_config_vreg_lpm(hba, hba->vreg_info.vccq2);
@@ -8165,6 +8164,7 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 	enum ufs_pm_level pm_lvl;
 	enum ufs_dev_pwr_mode req_dev_pwr_mode;
 	enum uic_link_state req_link_state;
+	bool keep_curr_dev_pwr_mode = false;
 
 	hba->pm_op_in_progress = 1;
 	if (!ufshcd_is_shutdown_pm(pm_op)) {
@@ -8220,27 +8220,29 @@ static int ufshcd_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
 			ufshcd_disable_auto_bkops(hba);
 		}
 		/*
-		 * With wb enabled, if the bkops is enabled or if the
-		 * configured WB type is 70% full, keep vcc ON
-		 * for the device to flush the wb buffer
+		 * If device needs to do BKOP or WB buffer flush during
+		 * Hibern8, keep device power mode as "active power mode"
+		 * and VCC supply.
 		 */
-		if ((hba->auto_bkops_enabled && ufshcd_is_wb_allowed(hba)) ||
-		    ufshcd_wb_keep_vcc_on(hba))
-			hba->dev_info.keep_vcc_on = true;
-		else
-			hba->dev_info.keep_vcc_on = false;
-	} else {
-		hba->dev_info.keep_vcc_on = false;
+		keep_curr_dev_pwr_mode = hba->auto_bkops_enabled ||
+			(((req_link_state == UIC_LINK_HIBERN8_STATE) ||
+			((req_link_state == UIC_LINK_ACTIVE_STATE) &&
+			ufshcd_is_auto_hibern8_enabled(hba))) &&
+			ufshcd_wb_keep_vcc_on(hba));
 	}
 
-	if ((req_dev_pwr_mode != hba->curr_dev_pwr_mode) &&
-	    ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
-	    !ufshcd_is_runtime_pm(pm_op))) {
-		/* ensure that bkops is disabled */
-		ufshcd_disable_auto_bkops(hba);
-		ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
-		if (ret)
-			goto enable_gating;
+	if (req_dev_pwr_mode != hba->curr_dev_pwr_mode) {
+		if ((ufshcd_is_runtime_pm(pm_op) && !hba->auto_bkops_enabled) ||
+		    !ufshcd_is_runtime_pm(pm_op)) {
+			/* ensure that bkops is disabled */
+			ufshcd_disable_auto_bkops(hba);
+		}
+
+		if (!keep_curr_dev_pwr_mode) {
+			ret = ufshcd_set_dev_pwr_mode(hba, req_dev_pwr_mode);
+			if (ret)
+				goto enable_gating;
+		}
 	}
 
 	flush_work(&hba->eeh_work);
-- 
2.18.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 v3 1/5] scsi: ufs: Remove unnecessary memset for dev_info
From: Stanley Chu @ 2020-05-16 17:46 UTC (permalink / raw)
  To: linux-scsi, martin.petersen, avri.altman, alim.akhtar, jejb,
	asutoshd
  Cc: bvanassche, andy.teng, chun-hung.wu, kuohong.wang, linux-kernel,
	cang, linux-mediatek, peter.wang, matthias.bgg, Stanley Chu,
	linux-arm-kernel, beanhuo
In-Reply-To: <20200516174615.15445-1-stanley.chu@mediatek.com>

The whole UFS host instance has been zero-initialized by
scsi_host_alloc(), thus UFS driver does not need to clear
"dev_info" member specifically in ufshcd_device_params_init().

Simply remove the unnecessary code.

Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
---
 drivers/scsi/ufs/ufshcd.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index aca50ed39844..4a3f3648c64f 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -7262,9 +7262,6 @@ static int ufshcd_device_params_init(struct ufs_hba *hba)
 	bool flag;
 	int ret;
 
-	/* Clear any previous UFS device information */
-	memset(&hba->dev_info, 0, sizeof(hba->dev_info));
-
 	/* Init check for device descriptor sizes */
 	ufshcd_init_desc_sizes(hba);
 
-- 
2.18.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 v3 3/5] scsi: ufs: Fix index of attributes query for WriteBooster feature
From: Stanley Chu @ 2020-05-16 17:46 UTC (permalink / raw)
  To: linux-scsi, martin.petersen, avri.altman, alim.akhtar, jejb,
	asutoshd
  Cc: bvanassche, andy.teng, chun-hung.wu, kuohong.wang, linux-kernel,
	cang, linux-mediatek, peter.wang, matthias.bgg, Stanley Chu,
	linux-arm-kernel, beanhuo
In-Reply-To: <20200516174615.15445-1-stanley.chu@mediatek.com>

For WriteBooster feature related attributes, the index used by
query shall be LUN ID if LU Dedicated buffer mode is enabled.

Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
---
 drivers/scsi/ufs/ufs-sysfs.c | 13 +++++++++++--
 drivers/scsi/ufs/ufshcd.c    | 16 ++++++++++------
 drivers/scsi/ufs/ufshcd.h    |  2 +-
 3 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/drivers/scsi/ufs/ufs-sysfs.c b/drivers/scsi/ufs/ufs-sysfs.c
index a0b3763e1dc2..2d71d232a69d 100644
--- a/drivers/scsi/ufs/ufs-sysfs.c
+++ b/drivers/scsi/ufs/ufs-sysfs.c
@@ -637,7 +637,7 @@ static ssize_t _name##_show(struct device *dev,				\
 	int ret;							\
 	struct ufs_hba *hba = dev_get_drvdata(dev);			\
 	if (ufshcd_is_wb_flags(QUERY_FLAG_IDN##_uname))			\
-		index = ufshcd_wb_get_flag_index(hba);			\
+		index = ufshcd_wb_get_query_index(hba);			\
 	pm_runtime_get_sync(hba->dev);					\
 	ret = ufshcd_query_flag(hba, UPIU_QUERY_OPCODE_READ_FLAG,	\
 		QUERY_FLAG_IDN##_uname, index, &flag);			\
@@ -680,6 +680,12 @@ static const struct attribute_group ufs_sysfs_flags_group = {
 	.attrs = ufs_sysfs_device_flags,
 };
 
+static inline bool ufshcd_is_wb_attrs(enum attr_idn idn)
+{
+	return ((idn >= QUERY_ATTR_IDN_WB_FLUSH_STATUS) &&
+		(idn <= QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE));
+}
+
 #define UFS_ATTRIBUTE(_name, _uname)					\
 static ssize_t _name##_show(struct device *dev,				\
 	struct device_attribute *attr, char *buf)			\
@@ -687,9 +693,12 @@ static ssize_t _name##_show(struct device *dev,				\
 	struct ufs_hba *hba = dev_get_drvdata(dev);			\
 	u32 value;							\
 	int ret;							\
+	u8 index = 0;							\
+	if (ufshcd_is_wb_attrs(QUERY_ATTR_IDN##_uname))			\
+		index = ufshcd_wb_get_query_index(hba);			\
 	pm_runtime_get_sync(hba->dev);					\
 	ret = ufshcd_query_attr(hba, UPIU_QUERY_OPCODE_READ_ATTR,	\
-		QUERY_ATTR_IDN##_uname, 0, 0, &value);			\
+		QUERY_ATTR_IDN##_uname, index, 0, &value);		\
 	pm_runtime_put_sync(hba->dev);					\
 	if (ret)							\
 		return -EINVAL;						\
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index f7fa571020da..c7c2bd7860b8 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -5195,7 +5195,7 @@ static int ufshcd_wb_ctrl(struct ufs_hba *hba, bool enable)
 	else
 		opcode = UPIU_QUERY_OPCODE_CLEAR_FLAG;
 
-	index = ufshcd_wb_get_flag_index(hba);
+	index = ufshcd_wb_get_query_index(hba);
 	ret = ufshcd_query_flag_retry(hba, opcode,
 				      QUERY_FLAG_IDN_WB_EN, index, NULL);
 	if (ret) {
@@ -5221,7 +5221,7 @@ static int ufshcd_wb_toggle_flush_during_h8(struct ufs_hba *hba, bool set)
 	else
 		val = UPIU_QUERY_OPCODE_CLEAR_FLAG;
 
-	index = ufshcd_wb_get_flag_index(hba);
+	index = ufshcd_wb_get_query_index(hba);
 	return ufshcd_query_flag_retry(hba, val,
 				QUERY_FLAG_IDN_WB_BUFF_FLUSH_DURING_HIBERN8,
 				index, NULL);
@@ -5244,7 +5244,7 @@ static int ufshcd_wb_buf_flush_enable(struct ufs_hba *hba)
 	if (!ufshcd_is_wb_allowed(hba) || hba->wb_buf_flush_enabled)
 		return 0;
 
-	index = ufshcd_wb_get_flag_index(hba);
+	index = ufshcd_wb_get_query_index(hba);
 	ret = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_SET_FLAG,
 				      QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN,
 				      index, NULL);
@@ -5266,7 +5266,7 @@ static int ufshcd_wb_buf_flush_disable(struct ufs_hba *hba)
 	if (!ufshcd_is_wb_allowed(hba) || !hba->wb_buf_flush_enabled)
 		return 0;
 
-	index = ufshcd_wb_get_flag_index(hba);
+	index = ufshcd_wb_get_query_index(hba);
 	ret = ufshcd_query_flag_retry(hba, UPIU_QUERY_OPCODE_CLEAR_FLAG,
 				      QUERY_FLAG_IDN_WB_BUFF_FLUSH_EN,
 				      index, NULL);
@@ -5286,10 +5286,12 @@ static bool ufshcd_wb_presrv_usrspc_keep_vcc_on(struct ufs_hba *hba,
 {
 	u32 cur_buf;
 	int ret;
+	u8 index;
 
+	index = ufshcd_wb_get_query_index(hba);
 	ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
 					      QUERY_ATTR_IDN_CURR_WB_BUFF_SIZE,
-					      0, 0, &cur_buf);
+					      index, 0, &cur_buf);
 	if (ret) {
 		dev_err(hba->dev, "%s dCurWriteBoosterBufferSize read failed %d\n",
 			__func__, ret);
@@ -5312,6 +5314,7 @@ static bool ufshcd_wb_keep_vcc_on(struct ufs_hba *hba)
 {
 	int ret;
 	u32 avail_buf;
+	u8 index;
 
 	if (!ufshcd_is_wb_allowed(hba))
 		return false;
@@ -5326,9 +5329,10 @@ static bool ufshcd_wb_keep_vcc_on(struct ufs_hba *hba)
 	 * buffer (dCurrentWriteBoosterBufferSize). There's no point in
 	 * keeping vcc on when current buffer is empty.
 	 */
+	index = ufshcd_wb_get_query_index(hba);
 	ret = ufshcd_query_attr_retry(hba, UPIU_QUERY_OPCODE_READ_ATTR,
 				      QUERY_ATTR_IDN_AVAIL_WB_BUFF_SIZE,
-				      0, 0, &avail_buf);
+				      index, 0, &avail_buf);
 	if (ret) {
 		dev_warn(hba->dev, "%s dAvailableWriteBoosterBufferSize read failed %d\n",
 			 __func__, ret);
diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h
index e3dfb48e669e..8db7a6101892 100644
--- a/drivers/scsi/ufs/ufshcd.h
+++ b/drivers/scsi/ufs/ufshcd.h
@@ -868,7 +868,7 @@ static inline bool ufshcd_keep_autobkops_enabled_except_suspend(
 	return hba->caps & UFSHCD_CAP_KEEP_AUTO_BKOPS_ENABLED_EXCEPT_SUSPEND;
 }
 
-static inline u8 ufshcd_wb_get_flag_index(struct ufs_hba *hba)
+static inline u8 ufshcd_wb_get_query_index(struct ufs_hba *hba)
 {
 	if (hba->dev_info.b_wb_buffer_type == WB_BUF_MODE_LU_DEDICATED)
 		return hba->dev_info.wb_dedicated_lu;
-- 
2.18.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 v3 0/5] scsi: ufs: Fix WriteBooster and cleanup UFS driver
From: Stanley Chu @ 2020-05-16 17:46 UTC (permalink / raw)
  To: linux-scsi, martin.petersen, avri.altman, alim.akhtar, jejb,
	asutoshd
  Cc: bvanassche, andy.teng, chun-hung.wu, kuohong.wang, linux-kernel,
	cang, linux-mediatek, peter.wang, matthias.bgg, Stanley Chu,
	linux-arm-kernel, beanhuo

Hi,

This patch set fixes some WriteBooster issues and do small cleanup in UFS driver

v2 -> v3
  - Introduce patch [5] to fix possible VCC power drain during runtime suspend (Asutosh)

v1 -> v2
  - Remove dummy new line in patch [4] (Asutosh)
  - Add more limitation to allow WriteBooster flush during Hibern8 in runtime-suspend. Now the device power mode is kept as Active power mode only if link is put in Hibern8 or Auto-Hibern8 is enabled during runtime-suspend (Asutosh)

Stanley Chu (5):
  scsi: ufs: Remove unnecessary memset for dev_info
  scsi: ufs: Allow WriteBooster on UFS 2.2 devices
  scsi: ufs: Fix index of attributes query for WriteBooster feature
  scsi: ufs: Fix WriteBooster flush during runtime suspend
  scsi: ufs: Fix possible VCC power drain during runtime suspend

 drivers/scsi/ufs/ufs-sysfs.c | 13 ++++-
 drivers/scsi/ufs/ufs.h       |  2 +-
 drivers/scsi/ufs/ufshcd.c    | 99 +++++++++++++++++++++++++-----------
 drivers/scsi/ufs/ufshcd.h    |  3 +-
 4 files changed, 82 insertions(+), 35 deletions(-)

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

^ permalink raw reply

* [PATCH v3 2/5] scsi: ufs: Allow WriteBooster on UFS 2.2 devices
From: Stanley Chu @ 2020-05-16 17:46 UTC (permalink / raw)
  To: linux-scsi, martin.petersen, avri.altman, alim.akhtar, jejb,
	asutoshd
  Cc: bvanassche, andy.teng, chun-hung.wu, kuohong.wang, linux-kernel,
	cang, linux-mediatek, peter.wang, matthias.bgg, Stanley Chu,
	linux-arm-kernel, beanhuo
In-Reply-To: <20200516174615.15445-1-stanley.chu@mediatek.com>

According to the UFS specification, WriteBooster is officially
supported by UFS 2.2.

Since UFS 2.2 specification has been finalized in JEDEC and
such devices have also showed up in the market, modify the
checking rule for ufshcd_wb_probe() to allow these devices to enable
WriteBooster.

Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
---
 drivers/scsi/ufs/ufshcd.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 4a3f3648c64f..f7fa571020da 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -6925,6 +6925,7 @@ static int ufs_get_device_desc(struct ufs_hba *hba)
 	 * UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES enabled
 	 */
 	if (dev_info->wspecversion >= 0x310 ||
+	    dev_info->wspecversion == 0x220 ||
 	    (hba->dev_quirks & UFS_DEVICE_QUIRK_SUPPORT_EXTENDED_FEATURES))
 		ufshcd_wb_probe(hba, desc_buf);
 
-- 
2.18.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 v5 05/13] soc: mediatek: cmdq: return send msg error code
From: Matthias Brugger @ 2020-05-16 17:56 UTC (permalink / raw)
  To: Dennis YC Hsieh, Rob Herring, Mark Rutland, Jassi Brar,
	Philipp Zabel, David Airlie, Daniel Vetter
  Cc: devicetree, wsd_upstream, linux-kernel, dri-devel, HS Liao,
	linux-mediatek, Houlong Wei, Bibby Hsieh, CK Hu, linux-arm-kernel
In-Reply-To: <1583664775-19382-6-git-send-email-dennis-yc.hsieh@mediatek.com>



On 08/03/2020 11:52, Dennis YC Hsieh wrote:
> Return error code to client if send message fail,
> so that client has chance to error handling.
> 
> Signed-off-by: Dennis YC Hsieh <dennis-yc.hsieh@mediatek.com>
> Fixes: 576f1b4bc802 ("soc: mediatek: Add Mediatek CMDQ helper")
> Reviewed-by: CK Hu <ck.hu@mediatek.com>

Queued for v5.7-fixes

> ---
>  drivers/soc/mediatek/mtk-cmdq-helper.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/soc/mediatek/mtk-cmdq-helper.c b/drivers/soc/mediatek/mtk-cmdq-helper.c
> index 2e1bc513569b..98f23ba3ba47 100644
> --- a/drivers/soc/mediatek/mtk-cmdq-helper.c
> +++ b/drivers/soc/mediatek/mtk-cmdq-helper.c
> @@ -351,7 +351,9 @@ int cmdq_pkt_flush_async(struct cmdq_pkt *pkt, cmdq_async_flush_cb cb,
>  		spin_unlock_irqrestore(&client->lock, flags);
>  	}
>  
> -	mbox_send_message(client->chan, pkt);
> +	err = mbox_send_message(client->chan, pkt);
> +	if (err < 0)
> +		return err;
>  	/* We can send next packet immediately, so just call txdone. */
>  	mbox_client_txdone(client->chan, 0);
>  
> 

_______________________________________________
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