Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* Re: [PATCH v3 4/7] PCI: dwc: Use common pci_host_common_link_train_delay() helper
From: Krzysztof Wilczyński @ 2026-05-12  7:14 UTC (permalink / raw)
  To: Manivannan Sadhasivam
  Cc: Hans Zhang, bhelgaas, lpieralisi, vigneshr, jingoohan1,
	thomas.petazzoni, pali, ryder.lee, claudiu.beznea.uj, mpillai,
	robh, s-vadapalli, linux-omap, linux-arm-kernel, claudiu.beznea,
	linux-mediatek, linux-renesas-soc, linux-pci, linux-kernel
In-Reply-To: <6xcq6e6c2jc7wxhvv3kjwp5d2ik62ed7kukb3e62yogf3phtxk@6besox4h2v4n>

Hello,

> > > -	/*
> > > -	 * As per PCIe r6.0, sec 6.6.1, a Downstream Port that supports Link
> > > -	 * speeds greater than 5.0 GT/s, software must wait a minimum of 100 ms
> > > -	 * after Link training completes before sending a Configuration Request.
> > > -	 */
> > > -	if (pci->max_link_speed > 2)
> > > -		msleep(PCIE_RESET_CONFIG_WAIT_MS);
> > > +	pci_host_common_link_train_delay(pci->max_link_speed);
> > 
> > This comment could move to the helper you added.
> > 
> 
> Not required, as the macro definition in drivers/pci/pci.h already has an
> elaborative comment with spec citation.

So it does, indeed.  Thank you for checking!

	Krzysztof


^ permalink raw reply

* Re: [PATCH v3 4/7] PCI: dwc: Use common pci_host_common_link_train_delay() helper
From: Krzysztof Wilczyński @ 2026-05-12  7:14 UTC (permalink / raw)
  To: Hans Zhang
  Cc: bhelgaas, lpieralisi, mani, vigneshr, jingoohan1,
	thomas.petazzoni, pali, ryder.lee, claudiu.beznea.uj, mpillai,
	robh, s-vadapalli, linux-omap, linux-arm-kernel, claudiu.beznea,
	linux-mediatek, linux-renesas-soc, linux-pci, linux-kernel
In-Reply-To: <e600d0a4-b93e-425f-a5f1-c76802c65622@163.com>

Hello,

> > > -	/*
> > > -	 * As per PCIe r6.0, sec 6.6.1, a Downstream Port that supports Link
> > > -	 * speeds greater than 5.0 GT/s, software must wait a minimum of 100 ms
> > > -	 * after Link training completes before sending a Configuration Request.
> > > -	 */
> > > -	if (pci->max_link_speed > 2)
> > > -		msleep(PCIE_RESET_CONFIG_WAIT_MS);
> > > +	pci_host_common_link_train_delay(pci->max_link_speed);
> > 
> > This comment could move to the helper you added.
> 
> Hi Krzysztof,
> 
> Will add.

No need.  Per Mani's feedback about macro being well documented.

Thank you nonetheless!

	Krzysztof


^ permalink raw reply

* Re: [PATCH v2 10/16] mfd: mt6397-core: add mt6323 thermal support
From: Andy Shevchenko @ 2026-05-12  7:07 UTC (permalink / raw)
  To: rva333
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Sen Chu, Sean Wang, Macpaul Lin,
	Lee Jones, Srinivas Kandagatla, Rafael J. Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, linux-iio, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, linux-pm, Ben Grisdale
In-Reply-To: <20260512-mt6323-v2-10-3efcba579e88@protonmail.com>

On Tue, May 12, 2026 at 8:21 AM Roman Vivchar via B4 Relay
<devnull+rva333.protonmail.com@kernel.org> wrote:
>
> The mt6323 PMIC temperature can be measured using AUXADC channel.
> Register the thermal in the mt6323 devices array to allow the
> corresponding driver to probe using compatible string.

Wouldn't it be better to interleave these MFD patches to enable each
driver just immediately after the driver provided? However, in
previous review somebody ( IIRC it was Krzysztof) asked how dependent
are they and it has something to do with the device tree bindings.
Take into account that one as well.

-- 
With Best Regards,
Andy Shevchenko


^ permalink raw reply

* RE: [PATCH 0/7] soc: aspeed: Add AST2600 eSPI controller support
From: YH Chung @ 2026-05-12  7:08 UTC (permalink / raw)
  To: Shulzhenko, Oleksandr, Arnd Bergmann, Andrew Jeffery,
	Conor Dooley
  Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Joel Stanley,
	Ryan Chen, Philipp Zabel, devicetree@vger.kernel.org,
	linux-arm-kernel@lists.infradead.org,
	linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org,
	openbmc@lists.ozlabs.org, maciej.lawniczak@intel.com, Mark Brown
In-Reply-To: <b1d56feb-9847-41b1-8bba-733963055cae@linux.intel.com>

Hi Shulzhenko, 

Thanks for the follow-up. 

> Integrating this driver into the SPI subsystem may allow reusing some existing 
> definitions, e.g.|spi_controller|,|spi_message|, and perhaps parts related to 
> single/dual/quad I/O handling. At the same time, parts such as the Flash channel 
> (included in the current series), and OOB / Virtual Wire support (I would expect 
> to come later), appear to be specific to the Intel eSPI protocol. Modeling all of 
> that as just another SPI IP driver may introduce some awkward layering and 
> overhead. 

Agreed. eSPI introduces two additional pins, RESET# and ALERT#, beyond the
standard SPI signals. More importantly, eSPI functionality is described
primarily in terms of four logical channels, rather than generic low-level
bus signaling or pure data transfers.

> Also, the current series already seems to separate common eSPI logic from 
> AST2600-specific pieces, assuming that 2700 driver is also coming at some point. 
>
> This makes me wonder whether a dedicated eSPI layer/subsystem could be a 
> better fit — either under the SPI or as something separate (but not SoC driver). 
>
> Given my limited experience with SPI/eSPI, could you help clarify a few points for 
> me (and probably others as well)? 
> 
> * How much of the SPI subsystem can be reused for this implementation, 
> both for the current patchset and for likely future extensions? 

I believe only a limited portion of the SPI subsystem can be reused. Some
generic framework elements, such as controller registration and basic
scaffolding, may be useful initially. But this reuse appears to be mostly
mechanical rather than semantic. Once eSPI-specific features like Flash
channels, OOB messaging, and Virtual Wire semantics are involved, the SPI
transaction model does not seem to map very naturally. 

> * Are there any pitfalls or abstraction mismatches in trying to reuse 
> the SPI core here? 

Our main concern is an abstraction mismatch. SPI is designed as a generic
peripheral bus, while eSPI is more of a system-management interface with
explicit host-BMC-specific semantics. Reusing the SPI core would likely
require treating eSPI packets as generic bus-level transfers in the kernel.

However, some eSPI transactions and protocol handling, such as LPC bridge
accesses, are performed autonomously by the hardware rather than being fully
driven as low-level bus operations by the driver. This makes the eSPI driver
somewhat different from a conventional serial bus controller driver
maintained under the SPI core.


^ permalink raw reply

* Re: [PATCH 4/4] remoteproc: switch drivers to optional resource-table helper
From: Geert Uytterhoeven @ 2026-05-12  7:07 UTC (permalink / raw)
  To: Ben Levinsky
  Cc: Bjorn Andersson, Mathieu Poirier, linux-remoteproc, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam, Magnus Damm,
	Patrice Chotard, Maxime Coquelin, Alexandre Torgue, imx,
	linux-arm-kernel, linux-kernel, linux-renesas-soc, linux-stm32,
	tanmay.shah
In-Reply-To: <20260511211841.284809-5-ben.levinsky@amd.com>

On Mon, 11 May 2026 at 23:18, Ben Levinsky <ben.levinsky@amd.com> wrote:
> Use the shared optional resource-table helper in the remoteproc
> drivers that currently ignore a missing table. This keeps the missing
> resource-table case non-fatal while letting other parsing failures
> propagate to the caller.
>
> Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>

>  drivers/remoteproc/rcar_rproc.c         | 13 +----------

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> # rcar

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


^ permalink raw reply

* Re: [PATCH 2/4] remoteproc: switch exact-match drivers to wc-ioremap callbacks
From: Geert Uytterhoeven @ 2026-05-12  7:06 UTC (permalink / raw)
  To: Ben Levinsky
  Cc: Bjorn Andersson, Mathieu Poirier, linux-remoteproc, Frank Li,
	Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
	Geert Uytterhoeven, Magnus Damm, Patrice Chotard, Maxime Coquelin,
	Alexandre Torgue, imx, linux-arm-kernel, linux-kernel,
	linux-renesas-soc, linux-stm32, tanmay.shah
In-Reply-To: <20260511211841.284809-3-ben.levinsky@amd.com>

Hi Ben,

On Mon, 11 May 2026 at 23:18, Ben Levinsky <ben.levinsky@amd.com> wrote:
> Replace the exact-match carveout map and unmap callbacks in the
> existing remoteproc drivers with the common wc-ioremap helpers. Leave
> the zynqmp R5 TCM callbacks alone because they also clear the mapped
> memory and are not exact matches.
>
> Signed-off-by: Ben Levinsky <ben.levinsky@amd.com>

Thanks for your patch!

>  drivers/remoteproc/rcar_rproc.c         | 33 ++---------------

This change also makes sure mem->is_iomem is true, which looks like
a valid bug fix. Do you know what was the impact of not setting
this before?

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be> # renesas

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


^ permalink raw reply

* Re: [PATCH v2 07/16] thermal: mediatek: add PMIC thermal support
From: Andy Shevchenko @ 2026-05-12  7:04 UTC (permalink / raw)
  To: rva333
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Sen Chu, Sean Wang, Macpaul Lin,
	Lee Jones, Srinivas Kandagatla, Rafael J. Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, linux-iio, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, linux-pm, Ben Grisdale
In-Reply-To: <20260512-mt6323-v2-7-3efcba579e88@protonmail.com>

On Tue, May 12, 2026 at 8:21 AM Roman Vivchar via B4 Relay
<devnull+rva333.protonmail.com@kernel.org> wrote:
>
> Add a new driver to support thermal monitoring on MediaTek PMICs.
>
> The driver retrieves calibration data from EFUSE, calculates the
> temperature using a linear interpolation, and registers the device with
> the thermal framework.
>
> Initial support is added for the mt6323 PMIC.

...

+ array_size.h

> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/cleanup.h>
> +#include <linux/err.h>
> +#include <linux/iio/consumer.h>

> +#include <linux/kernel.h>

No way the driver(s) nowadays use this header. Please, drop it and add
the ones that are really in use (there are missing ones).

> +#include <linux/module.h>
> +#include <linux/nvmem-consumer.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>

> +#include <linux/slab.h>

Is it used?

> +#include <linux/thermal.h>

Missing types.h

> +#include <linux/units.h>

...

> +#define MT6323_ADC_VOLTAGE_RANGE       1800
> +#define MT6323_ADC_RESOLUTION          32768

These two ring a bell with the first code patch. Are they the same?
Can they be deduplicated?

...

> +       ret = iio_read_channel_processed(sensor->adc_channel, &raw);
> +       if (ret < 0) {

Do we need that ' < 0' part? What is the meaning of positive returned
value (if any) and why do we ignore that? Same question to all similar
checks in the whole series.

> +               dev_err(sensor->mt->dev, "failed to read iio channel: %d\n",
> +                       ret);
> +               return ret;
> +       }

...

> +       /*
> +        * Temperature coefficient. The o_slope is a trim value applied to
> +        * the base calibration

Respect English grammar and punctuation. Here is the period missing.

> +        */

...

> +static int mtk_pmic_thermal_extract_efuse_mt6323(struct mtk_pmic_thermal *mt,
> +                                                u16 *buf)
> +{
> +       u32 reg;
> +       s32 vts, degc_cali, o_slope, o_slope_sign, id;
> +       int ret;

Better to keep reversed xmas tree order.

> +       return 0;
> +}

...

> +static int mtk_pmic_thermal_get_calib_data(struct device *dev,
> +                                          struct mtk_pmic_thermal *mt)
> +{

> +       void *buf __free(kfree) = NULL;

This is a discouraged way of defining variables with __free(). See below.

> +       struct nvmem_cell *cell;
> +       size_t len;
> +       int ret;
> +
> +       cell = nvmem_cell_get(dev, NULL);
> +       if (IS_ERR(cell))
> +               return PTR_ERR(cell);

> +       buf = nvmem_cell_read(cell, &len);

Should be rather here

       void *buf __free(kfree) = nvmem_cell_read(cell, &len);

> +       nvmem_cell_put(cell);
> +
> +       if (IS_ERR(buf)) {
> +               ret = PTR_ERR(buf);
> +               buf = NULL;
> +               return ret;
> +       }
> +
> +       if (len < 2 * sizeof(u16)) {
> +               dev_err(dev, "invalid calibration data length\n");
> +               return -EINVAL;

return dev_err_probe(...);

> +       }
> +
> +       ret = mt->data->extract_efuse(mt, buf);
> +       if (ret) {
> +               dev_info(dev, "device not calibrated, using default values\n");
> +               mt->data->precalc(mt, MT6323_DEFAULT_VTS,
> +                                 MT6323_DEFAULT_DEGC_CALI,
> +                                 MT6323_DEFAULT_SLOPE,
> +                                 MT6323_DEFAULT_SLOPE_SIGN);
> +       }
> +
> +       return 0;
> +}
> +
> +static int mtk_pmic_thermal_init_sensor(struct mtk_pmic_thermal *mt, int id)
> +{
> +       struct mtk_pmic_sensor *sensor = &mt->sensors[id];
> +       struct device *dev = mt->dev;
> +
> +       sensor->id = id;
> +       sensor->mt = mt;
> +
> +       if (mt->data->num_sensors > 1)
> +               sensor->adc_channel = devm_iio_channel_get(dev, mt->data->sensors[id]);
> +       else
> +               sensor->adc_channel = devm_iio_channel_get(dev, NULL);

> +

Unneeded blank line as the above and below are coupled semantically.

> +       if (IS_ERR(sensor->adc_channel))
> +               return dev_err_probe(dev, PTR_ERR(sensor->adc_channel),
> +                                    "failed to get channel %s\n",
> +                                    mt->data->sensors[id]);
> +
> +       sensor->tzdev = devm_thermal_of_zone_register(dev, id, sensor,
> +                                                     &mtk_pmic_thermal_ops);
> +       if (IS_ERR(sensor->tzdev))
> +               return dev_err_probe(dev, PTR_ERR(sensor->tzdev),
> +                                    "failed to register thermal zone %d\n", id);
> +
> +       return 0;
> +}

...

> +static const struct of_device_id mtk_pmic_thermal_of_match[] = {
> +       { .compatible = "mediatek,mt6323-thermal",
> +         .data = &mt6323_thermal_data },
> +       { /* sentinel */ },

No comma for the terminator entry.

> +};

-- 
With Best Regards,
Andy Shevchenko


^ permalink raw reply

* Re: [PATCH v3 1/7] PCI: Add pci_host_common_link_train_delay() helper
From: Claudiu Beznea @ 2026-05-12  7:05 UTC (permalink / raw)
  To: Hans Zhang, bhelgaas, lpieralisi, kwilczynski, mani, vigneshr,
	jingoohan1, thomas.petazzoni, pali, ryder.lee, claudiu.beznea.uj,
	mpillai
  Cc: robh, s-vadapalli, linux-omap, linux-arm-kernel, linux-mediatek,
	linux-renesas-soc, linux-pci, linux-kernel
In-Reply-To: <20260511055923.37117-2-18255117159@163.com>

Hi, Hans,

On 5/11/26 08:59, Hans Zhang wrote:
> PCIe r6.0, sec 6.6.1 (Conventional Reset) requires that for a Downstream
> Port supporting Link speeds greater than 5.0 GT/s, software must wait a
> minimum of 100 ms after Link training completes before sending any
> Configuration Request.
> 
> Introduce a static inline helper pci_host_common_link_train_delay() that
> checks the given max_link_speed (2 = 5.0 GT/s, 3 = 8.0 GT/s, etc.) and
> calls msleep(100) only when the speed is greater than 5.0 GT/s.
> 
> This allows multiple host controller drivers to share the same mandatory
> delay without duplicating the logic.
> 
> Signed-off-by: Hans Zhang <18255117159@163.com>
> ---
>   drivers/pci/controller/pci-host-common.h | 17 +++++++++++++++++
>   1 file changed, 17 insertions(+)
> 
> diff --git a/drivers/pci/controller/pci-host-common.h b/drivers/pci/controller/pci-host-common.h
> index b5075d4bd7eb..d709f7e3e11a 100644
> --- a/drivers/pci/controller/pci-host-common.h
> +++ b/drivers/pci/controller/pci-host-common.h
> @@ -10,6 +10,9 @@
>   #ifndef _PCI_HOST_COMMON_H
>   #define _PCI_HOST_COMMON_H
>   
> +#include <linux/delay.h>
> +#include "../pci.h"
> +
>   struct pci_ecam_ops;
>   
>   int pci_host_common_probe(struct platform_device *pdev);
> @@ -20,4 +23,18 @@ void pci_host_common_remove(struct platform_device *pdev);
>   
>   struct pci_config_window *pci_host_common_ecam_create(struct device *dev,
>   	struct pci_host_bridge *bridge, const struct pci_ecam_ops *ops);
> +
> +/**
> + * pci_host_common_link_train_delay - Wait 100 ms if link speed > 5 GT/s
> + * @max_link_speed: the maximum link speed (2 = 5.0 GT/s, 3 = 8.0 GT/s, ...)
> + *
> + * Must be called after Link training completes and before the first
> + * Configuration Request is sent.
> + */
> +static inline void pci_host_common_link_train_delay(int max_link_speed)
> +{
> +	if (max_link_speed > 2)
> +		msleep(PCIE_RESET_CONFIG_WAIT_MS);

In case of RZ/G3S driver the max_link_speed is populated based on 
"max-link-speed" DT property (by calling of_pci_get_max_link_speed()). My 
understanding from [1] (and the review of the initial RZ/G3S driver support) is 
that this is not a mandatory property (note also the "Host drivers *could* add 
this" from [1]). At least for the RZ/G3S driver, in case the "max-link-speed" DT 
property is not present in DT but the controller supports more than 5GT/s (that 
is possible as the driver supports more controller variants), the max_link_speed 
argument will be negative. In that case the msleep() will not be called. This 
looks like an opposite of what the patch set is trying to achieve.

Also, if I'm not wrong, there is also the possibility of having the 
max-link-speed > 2 but the downstream port to not support more than 5GT/s. In 
that case the mspeep() would also be executed (but I think that wouldn't be 
really an issue).

Thank you,
Claudiu

[1] 
https://github.com/devicetree-org/dt-schema/blob/main/dtschema/schemas/pci/pci-bus-common.yaml#L117

Thank you,
Claudiu



^ permalink raw reply

* [PATCH 08/19] raid6: improve the public interface
From: Christoph Hellwig @ 2026-05-12  5:20 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Catalin Marinas, Will Deacon, Ard Biesheuvel, Huacai Chen,
	WANG Xuerui, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Heiko Carstens,
	Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
	Sven Schnelle, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	Dave Hansen, x86, H. Peter Anvin, Herbert Xu, Dan Williams,
	Chris Mason, David Sterba, Arnd Bergmann, Song Liu, Yu Kuai,
	Li Nan, linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
	linux-riscv, linux-s390, linux-crypto, linux-btrfs, linux-arch,
	linux-raid
In-Reply-To: <20260512052230.2947683-1-hch@lst.de>

Stop directly calling into function pointers from users of the RAID6 PQ
API, and provide exported functions with proper documentation and
API guarantees asserts where applicable instead.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 Documentation/crypto/async-tx-api.rst         |   4 +-
 crypto/async_tx/async_pq.c                    |   6 +-
 crypto/async_tx/async_raid6_recov.c           |   4 +-
 drivers/md/raid5.c                            |   4 +-
 fs/btrfs/raid56.c                             |   8 +-
 include/linux/raid/pq.h                       |  28 ++--
 lib/raid/raid6/algos.c                        | 139 +++++++++++++++++-
 lib/raid/raid6/arm/recov_neon.c               |   4 +-
 .../raid6/loongarch/recov_loongarch_simd.c    |   8 +-
 lib/raid/raid6/recov.c                        |   4 +-
 lib/raid/raid6/riscv/recov_rvv.c              |   4 +-
 lib/raid/raid6/s390/recov_s390xc.c            |   4 +-
 lib/raid/raid6/x86/recov_avx2.c               |   4 +-
 lib/raid/raid6/x86/recov_avx512.c             |   4 +-
 lib/raid/raid6/x86/recov_ssse3.c              |   4 +-
 15 files changed, 181 insertions(+), 48 deletions(-)

diff --git a/Documentation/crypto/async-tx-api.rst b/Documentation/crypto/async-tx-api.rst
index f88a7809385e..49fcfc66314a 100644
--- a/Documentation/crypto/async-tx-api.rst
+++ b/Documentation/crypto/async-tx-api.rst
@@ -82,9 +82,9 @@ xor_val   xor a series of source buffers and set a flag if the
 pq	  generate the p+q (raid6 syndrome) from a series of source buffers
 pq_val    validate that a p and or q buffer are in sync with a given series of
 	  sources
-datap	  (raid6_datap_recov) recover a raid6 data block and the p block
+datap	  (raid6_recov_datap) recover a raid6 data block and the p block
 	  from the given sources
-2data	  (raid6_2data_recov) recover 2 raid6 data blocks from the given
+2data	  (raid6_recov_2data) recover 2 raid6 data blocks from the given
 	  sources
 ========  ====================================================================
 
diff --git a/crypto/async_tx/async_pq.c b/crypto/async_tx/async_pq.c
index 0ce6f07b4e0d..f3574f80d1df 100644
--- a/crypto/async_tx/async_pq.c
+++ b/crypto/async_tx/async_pq.c
@@ -131,11 +131,11 @@ do_sync_gen_syndrome(struct page **blocks, unsigned int *offsets, int disks,
 		}
 	}
 	if (submit->flags & ASYNC_TX_PQ_XOR_DST) {
-		BUG_ON(!raid6_call.xor_syndrome);
+		BUG_ON(!raid6_can_xor_syndrome());
 		if (start >= 0)
-			raid6_call.xor_syndrome(disks, start, stop, len, srcs);
+			raid6_xor_syndrome(disks, start, stop, len, srcs);
 	} else
-		raid6_call.gen_syndrome(disks, len, srcs);
+		raid6_gen_syndrome(disks, len, srcs);
 	async_tx_sync_epilog(submit);
 }
 
diff --git a/crypto/async_tx/async_raid6_recov.c b/crypto/async_tx/async_raid6_recov.c
index f2dc6af6e6a7..305ea1421a3e 100644
--- a/crypto/async_tx/async_raid6_recov.c
+++ b/crypto/async_tx/async_raid6_recov.c
@@ -418,7 +418,7 @@ async_raid6_2data_recov(int disks, size_t bytes, int faila, int failb,
 			else
 				ptrs[i] = page_address(blocks[i]) + offs[i];
 
-		raid6_2data_recov(disks, bytes, faila, failb, ptrs);
+		raid6_recov_2data(disks, bytes, faila, failb, ptrs);
 
 		async_tx_sync_epilog(submit);
 
@@ -501,7 +501,7 @@ async_raid6_datap_recov(int disks, size_t bytes, int faila,
 			else
 				ptrs[i] = page_address(blocks[i]) + offs[i];
 
-		raid6_datap_recov(disks, bytes, faila, ptrs);
+		raid6_recov_datap(disks, bytes, faila, ptrs);
 
 		async_tx_sync_epilog(submit);
 
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 0d76e82f4506..ebcb19317670 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -6955,7 +6955,7 @@ raid5_store_rmw_level(struct mddev  *mddev, const char *page, size_t len)
 	if (kstrtoul(page, 10, &new))
 		return -EINVAL;
 
-	if (new != PARITY_DISABLE_RMW && !raid6_call.xor_syndrome)
+	if (new != PARITY_DISABLE_RMW && !raid6_can_xor_syndrome())
 		return -EINVAL;
 
 	if (new != PARITY_DISABLE_RMW &&
@@ -7646,7 +7646,7 @@ static struct r5conf *setup_conf(struct mddev *mddev)
 	conf->level = mddev->new_level;
 	if (conf->level == 6) {
 		conf->max_degraded = 2;
-		if (raid6_call.xor_syndrome)
+		if (raid6_can_xor_syndrome())
 			conf->rmw_level = PARITY_ENABLE_RMW;
 		else
 			conf->rmw_level = PARITY_DISABLE_RMW;
diff --git a/fs/btrfs/raid56.c b/fs/btrfs/raid56.c
index 08ee8f316d96..dabc9522e881 100644
--- a/fs/btrfs/raid56.c
+++ b/fs/btrfs/raid56.c
@@ -1410,7 +1410,7 @@ static void generate_pq_vertical_step(struct btrfs_raid_bio *rbio, unsigned int
 				rbio_qstripe_paddr(rbio, sector_nr, step_nr));
 
 		assert_rbio(rbio);
-		raid6_call.gen_syndrome(rbio->real_stripes, step, pointers);
+		raid6_gen_syndrome(rbio->real_stripes, step, pointers);
 	} else {
 		/* raid5 */
 		memcpy(pointers[rbio->nr_data], pointers[0], step);
@@ -1987,10 +1987,10 @@ static void recover_vertical_step(struct btrfs_raid_bio *rbio,
 		}
 
 		if (failb == rbio->real_stripes - 2) {
-			raid6_datap_recov(rbio->real_stripes, step,
+			raid6_recov_datap(rbio->real_stripes, step,
 					  faila, pointers);
 		} else {
-			raid6_2data_recov(rbio->real_stripes, step,
+			raid6_recov_2data(rbio->real_stripes, step,
 					  faila, failb, pointers);
 		}
 	} else {
@@ -2644,7 +2644,7 @@ static bool verify_one_parity_step(struct btrfs_raid_bio *rbio,
 	if (has_qstripe) {
 		assert_rbio(rbio);
 		/* RAID6, call the library function to fill in our P/Q. */
-		raid6_call.gen_syndrome(rbio->real_stripes, step, pointers);
+		raid6_gen_syndrome(rbio->real_stripes, step, pointers);
 	} else {
 		/* RAID5. */
 		memcpy(pointers[nr_data], pointers[0], step);
diff --git a/include/linux/raid/pq.h b/include/linux/raid/pq.h
index f27a866c287f..662c2669f63f 100644
--- a/include/linux/raid/pq.h
+++ b/include/linux/raid/pq.h
@@ -11,6 +11,25 @@
 #include <linux/blkdev.h>
 #include <linux/mm.h>
 
+/*
+ * While the RAID6 algorithm could in theory support 3 devices by just copying
+ * the data disk to the two parity disks, this configuration is not only useless
+ * because it is a suboptimal version of 3-way mirroring, but also easy to get
+ * wrong in architecture-optimized implementations due to special casing, so
+ * don't support it.
+ */
+#define RAID6_MIN_DISKS		4
+
+void raid6_gen_syndrome(int disks, size_t bytes, void **ptrs);
+void raid6_xor_syndrome(int disks, int start, int stop, size_t bytes,
+		void **ptrs);
+bool raid6_can_xor_syndrome(void);
+
+void raid6_recov_2data(int disks, size_t bytes, int faila, int failb,
+		void **ptrs);
+void raid6_recov_datap(int disks, size_t bytes, int faila,
+		void **ptrs);
+
 /* Routine choices */
 struct raid6_calls {
 	void (*gen_syndrome)(int, size_t, void **);
@@ -20,9 +39,6 @@ struct raid6_calls {
 	int priority;		/* Relative priority ranking if non-zero */
 };
 
-/* Selected algorithm */
-extern struct raid6_calls raid6_call;
-
 /* Various routine sets */
 extern const struct raid6_calls raid6_intx1;
 extern const struct raid6_calls raid6_intx2;
@@ -92,10 +108,4 @@ extern const u8 raid6_gflog[256]      __attribute__((aligned(256)));
 extern const u8 raid6_gfinv[256]      __attribute__((aligned(256)));
 extern const u8 raid6_gfexi[256]      __attribute__((aligned(256)));
 
-/* Recovery routines */
-extern void (*raid6_2data_recov)(int disks, size_t bytes, int faila, int failb,
-		       void **ptrs);
-extern void (*raid6_datap_recov)(int disks, size_t bytes, int faila,
-			void **ptrs);
-
 #endif /* LINUX_RAID_RAID6_H */
diff --git a/lib/raid/raid6/algos.c b/lib/raid/raid6/algos.c
index 985c60bb00a4..683b97cb94ad 100644
--- a/lib/raid/raid6/algos.c
+++ b/lib/raid/raid6/algos.c
@@ -16,8 +16,85 @@
 #include <linux/gfp.h>
 #include <kunit/visibility.h>
 
-struct raid6_calls raid6_call;
-EXPORT_SYMBOL_GPL(raid6_call);
+static const struct raid6_recov_calls *raid6_recov_algo;
+
+/* Selected algorithm */
+static struct raid6_calls raid6_call;
+
+/**
+ * raid6_gen_syndrome - generate RAID6 P/Q parity
+ * @disks:	number of "disks" to operate on including parity
+ * @bytes:	length in bytes of each vector
+ * @ptrs:	@disks size array of memory pointers
+ *
+ * Generate @bytes worth of RAID6 P and Q parity in @ptrs[@disks - 2] and
+ * @ptrs[@disks - 1] respectively from the memory pointed to by @ptrs[0] to
+ * @ptrs[@disks - 3].
+ *
+ * @disks must be at least 3, and the memory pointed to by each member of @ptrs
+ * must be at least 64-byte aligned.  @bytes must be non-zero and a multiple of
+ * 512.
+ *
+ * See https://kernel.org/pub/linux/kernel/people/hpa/raid6.pdf for underlying
+ * algorithm.
+ */
+void raid6_gen_syndrome(int disks, size_t bytes, void **ptrs)
+{
+	WARN_ON_ONCE(!in_task() || irqs_disabled() || softirq_count());
+	WARN_ON_ONCE(bytes & 511);
+	WARN_ON_ONCE(disks < RAID6_MIN_DISKS);
+
+	raid6_call.gen_syndrome(disks, bytes, ptrs);
+}
+EXPORT_SYMBOL_GPL(raid6_gen_syndrome);
+
+/**
+ * raid6_xor_syndrome - update RAID6 P/Q parity
+ * @disks:	number of "disks" to operate on including parity
+ * @start:	first index into @disk to update
+ * @stop:	last index into @disk to update
+ * @bytes:	length in bytes of each vector
+ * @ptrs:	@disks size array of memory pointers
+ *
+ * Update @bytes worth of RAID6 P and Q parity in @ptrs[@disks - 2] and
+ * @ptrs[@disks - 1] respectively for the memory pointed to by
+ * @ptrs[@start..@stop].
+ *
+ * This is used to update parity in place using the following sequence:
+ *
+ * 1) call raid6_xor_syndrome(disk, start, stop, ...) for the existing data.
+ * 2) update the the data in @ptrs[@start..@stop].
+ * 3) call raid6_xor_syndrome(disk, start, stop, ...) for the new data.
+ *
+ * Data between @start and @stop that is not changed should be filled
+ * with a pointer to the kernel zero page.
+ *
+ * @disks must be at least 3, and the memory pointed to by each member of @ptrs
+ * must be at least 64-byte aligned.  @bytes must be non-zero and a multiple of
+ * 512.  @stop must be larger or equal to @start.
+ */
+void raid6_xor_syndrome(int disks, int start, int stop, size_t bytes,
+		void **ptrs)
+{
+	WARN_ON_ONCE(!in_task() || irqs_disabled() || softirq_count());
+	WARN_ON_ONCE(bytes & 511);
+	WARN_ON_ONCE(disks < RAID6_MIN_DISKS);
+	WARN_ON_ONCE(stop < start);
+
+	raid6_call.xor_syndrome(disks, start, stop, bytes, ptrs);
+}
+EXPORT_SYMBOL_GPL(raid6_xor_syndrome);
+
+/*
+ * raid6_can_xor_syndrome - check if raid6_xor_syndrome() can be used
+ *
+ * Returns %true if raid6_can_xor_syndrome() can be used, else %false.
+ */
+bool raid6_can_xor_syndrome(void)
+{
+	return !!raid6_call.xor_syndrome;
+}
+EXPORT_SYMBOL_GPL(raid6_can_xor_syndrome);
 
 const struct raid6_calls * const raid6_algos[] = {
 #if defined(__i386__) && !defined(__arch_um__)
@@ -84,11 +161,58 @@ const struct raid6_calls * const raid6_algos[] = {
 };
 EXPORT_SYMBOL_IF_KUNIT(raid6_algos);
 
-void (*raid6_2data_recov)(int, size_t, int, int, void **);
-EXPORT_SYMBOL_GPL(raid6_2data_recov);
+/**
+ * raid6_recov_2data - recover two missing data disks
+ * @disks:	number of "disks" to operate on including parity
+ * @bytes:	length in bytes of each vector
+ * @faila:	first failed data disk index
+ * @failb:	second failed data disk index
+ * @ptrs:	@disks size array of memory pointers
+ *
+ * Rebuild @bytes of missing data in @ptrs[@faila] and @ptrs[@failb] from the
+ * data in the remaining disks and the two parities pointed to by the other
+ * indices between 0 and @disks - 1 in @ptrs.  @disks includes the data disks
+ * and the two parities.  @faila must be smaller than @failb.
+ *
+ * Memory pointed to by each pointer in @ptrs must be page aligned and is
+ * limited to %PAGE_SIZE.
+ */
+void raid6_recov_2data(int disks, size_t bytes, int faila, int failb,
+		void **ptrs)
+{
+	WARN_ON_ONCE(!in_task() || irqs_disabled() || softirq_count());
+	WARN_ON_ONCE(bytes & 511);
+	WARN_ON_ONCE(bytes > PAGE_SIZE);
+	WARN_ON_ONCE(failb <= faila);
+
+	raid6_recov_algo->data2(disks, bytes, faila, failb, ptrs);
+}
+EXPORT_SYMBOL_GPL(raid6_recov_2data);
+
+/**
+ * raid6_recov_datap - recover a missing data disk and missing P-parity
+ * @disks:	number of "disks" to operate on including parity
+ * @bytes:	length in bytes of each vector
+ * @faila:	failed data disk index
+ * @ptrs:	@disks size array of memory pointers
+ *
+ * Rebuild @bytes of missing data in @ptrs[@faila] and the missing P-parity in
+ * @ptrs[@disks - 2] from the data in the remaining disks and the Q-parity
+ * pointed to by the other indices between 0 and @disks - 1 in @ptrs.  @disks
+ * includes the data disks and the two parities.
+ *
+ * Memory pointed to by each pointer in @ptrs must be page aligned and is
+ * limited to %PAGE_SIZE.
+ */
+void raid6_recov_datap(int disks, size_t bytes, int faila, void **ptrs)
+{
+	WARN_ON_ONCE(!in_task() || irqs_disabled() || softirq_count());
+	WARN_ON_ONCE(bytes & 511);
+	WARN_ON_ONCE(bytes > PAGE_SIZE);
 
-void (*raid6_datap_recov)(int, size_t, int, void **);
-EXPORT_SYMBOL_GPL(raid6_datap_recov);
+	raid6_recov_algo->datap(disks, bytes, faila, ptrs);
+}
+EXPORT_SYMBOL_GPL(raid6_recov_datap);
 
 const struct raid6_recov_calls *const raid6_recov_algos[] = {
 #ifdef CONFIG_X86
@@ -133,8 +257,7 @@ static inline const struct raid6_recov_calls *raid6_choose_recov(void)
 				best = *algo;
 
 	if (best) {
-		raid6_2data_recov = best->data2;
-		raid6_datap_recov = best->datap;
+		raid6_recov_algo = best;
 
 		pr_info("raid6: using %s recovery algorithm\n", best->name);
 	} else
diff --git a/lib/raid/raid6/arm/recov_neon.c b/lib/raid/raid6/arm/recov_neon.c
index 9993bda5d3a6..4eb0efb44750 100644
--- a/lib/raid/raid6/arm/recov_neon.c
+++ b/lib/raid/raid6/arm/recov_neon.c
@@ -35,7 +35,7 @@ static void raid6_2data_recov_neon(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks - 1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]     = dp;
@@ -69,7 +69,7 @@ static void raid6_datap_recov_neon(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks - 1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]     = dq;
diff --git a/lib/raid/raid6/loongarch/recov_loongarch_simd.c b/lib/raid/raid6/loongarch/recov_loongarch_simd.c
index 4d4563209647..7d4d349322b3 100644
--- a/lib/raid/raid6/loongarch/recov_loongarch_simd.c
+++ b/lib/raid/raid6/loongarch/recov_loongarch_simd.c
@@ -49,7 +49,7 @@ static void raid6_2data_recov_lsx(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks - 1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila] = dp;
@@ -201,7 +201,7 @@ static void raid6_datap_recov_lsx(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks - 1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila] = dq;
@@ -323,7 +323,7 @@ static void raid6_2data_recov_lasx(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks - 1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila] = dp;
@@ -440,7 +440,7 @@ static void raid6_datap_recov_lasx(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks - 1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila] = dq;
diff --git a/lib/raid/raid6/recov.c b/lib/raid/raid6/recov.c
index 211e1df28963..cc7e4dc1eaa6 100644
--- a/lib/raid/raid6/recov.c
+++ b/lib/raid/raid6/recov.c
@@ -37,7 +37,7 @@ static void raid6_2data_recov_intx1(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dp;
@@ -75,7 +75,7 @@ static void raid6_datap_recov_intx1(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dq;
diff --git a/lib/raid/raid6/riscv/recov_rvv.c b/lib/raid/raid6/riscv/recov_rvv.c
index f77d9c430687..3ff39826e33f 100644
--- a/lib/raid/raid6/riscv/recov_rvv.c
+++ b/lib/raid/raid6/riscv/recov_rvv.c
@@ -164,7 +164,7 @@ static void raid6_2data_recov_rvv(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks - 1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]     = dp;
@@ -199,7 +199,7 @@ static void raid6_datap_recov_rvv(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks - 1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]     = dq;
diff --git a/lib/raid/raid6/s390/recov_s390xc.c b/lib/raid/raid6/s390/recov_s390xc.c
index 0f32217b7123..2bc4c85174de 100644
--- a/lib/raid/raid6/s390/recov_s390xc.c
+++ b/lib/raid/raid6/s390/recov_s390xc.c
@@ -40,7 +40,7 @@ static void raid6_2data_recov_s390xc(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dp;
@@ -84,7 +84,7 @@ static void raid6_datap_recov_s390xc(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dq;
diff --git a/lib/raid/raid6/x86/recov_avx2.c b/lib/raid/raid6/x86/recov_avx2.c
index 325310c81e1c..bef82a38d8eb 100644
--- a/lib/raid/raid6/x86/recov_avx2.c
+++ b/lib/raid/raid6/x86/recov_avx2.c
@@ -34,7 +34,7 @@ static void raid6_2data_recov_avx2(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dp;
@@ -199,7 +199,7 @@ static void raid6_datap_recov_avx2(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dq;
diff --git a/lib/raid/raid6/x86/recov_avx512.c b/lib/raid/raid6/x86/recov_avx512.c
index 08de77fcb8bd..06c70e771eaa 100644
--- a/lib/raid/raid6/x86/recov_avx512.c
+++ b/lib/raid/raid6/x86/recov_avx512.c
@@ -43,7 +43,7 @@ static void raid6_2data_recov_avx512(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dp;
@@ -241,7 +241,7 @@ static void raid6_datap_recov_avx512(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dq;
diff --git a/lib/raid/raid6/x86/recov_ssse3.c b/lib/raid/raid6/x86/recov_ssse3.c
index 002bef1e0847..5ca7d56f23d8 100644
--- a/lib/raid/raid6/x86/recov_ssse3.c
+++ b/lib/raid/raid6/x86/recov_ssse3.c
@@ -36,7 +36,7 @@ static void raid6_2data_recov_ssse3(int disks, size_t bytes, int faila,
 	ptrs[failb] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dp;
@@ -206,7 +206,7 @@ static void raid6_datap_recov_ssse3(int disks, size_t bytes, int faila,
 	ptrs[faila] = page_address(ZERO_PAGE(0));
 	ptrs[disks-1] = dq;
 
-	raid6_call.gen_syndrome(disks, bytes, ptrs);
+	raid6_gen_syndrome(disks, bytes, ptrs);
 
 	/* Restore pointer table */
 	ptrs[faila]   = dq;
-- 
2.53.0



^ permalink raw reply related

* Re: [PATCH 4/8] ras: aest: Add panic_on_ue module parameter
From: Umang Chheda @ 2026-05-12  6:51 UTC (permalink / raw)
  To: Ruidong Tian, Ruidong Tian, Tony Luck, Borislav Petkov,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson,
	Konrad Dybcio, catalin.marinas, will, lpieralisi, rafael,
	mark.rutland, Sudeep Holla
  Cc: linux-arm-msm, linux-acpi, linux-arm-kernel, linux-edac,
	linux-kernel, devicetree
In-Reply-To: <24e7a997-9479-447e-a1e2-cfab9a904668@linux.alibaba.com>

Hi Ruidong,


On 5/6/2026 1:36 PM, Ruidong Tian wrote:
> 
> 
> 在 2026/5/5 20:23, Umang Chheda 写道:
>> The driver unconditionally calls panic() whenever an unrecoverable,
>> uncontainable UE (UET_UC or UET_UEU) is detected. There is no way
>> for the user to suppress this behaviour, which makes it difficult to
>> test UE injection or to run in environments where a kernel panic on
>> every UE is undesirable.
>>
>> Add a module parameter `aest_panic_on_ue` When set to 0 the driver
>> logs the UE and continues instead of panicking.
>>
>> Usage:
>>    # Boot time (kernel cmdline)
>>    aest.aest_panic_on_ue=0
>>
>>    # Runtime
>>    echo 0 > /sys/module/aest/parameters/aest_panic_on_ue
>>
>> Signed-off-by: Umang Chheda <umang.chheda@oss.qualcomm.com>
> 
> Hi Umang,
> 
> Thanks for the patch.
> 
> I understand that this parameter is intended to facilitate UE injection
> testing and to avoid kernel panics in certain environments. However, we
> need to carefully consider the potential risks.
> 
> When a UC (Uncontainable Error) or UEU (Unrecoverable Error) occurs, the
> hardware state may be unpredictable, and data integrity cannot be
> guaranteed. Allowing the system to continue running instead of panicking
> in these scenarios could lead to silent data corruption or other
> unforeseen side effects, which poses a significant risk to system
> stability.
> 
> For the sake of robustness and data safety, I do not believe we should
> expose an interface that allows users to suppress panic on such critical
> errors.
> 
> If the goal is primarily to ease testing, I suggest handling this via
> local driver modifications in your test environment rather than
> upstreaming it as a configurable runtime option.


IMO, it would be useful to have a module parameter for this. In some
cases—outside of test scenarios—it’s necessary to avoid triggering a
kernel panic on UE errors.
Would it make sense to keep the default behavior as panic on UE, while
also providing a module parameter to disable it when needed? This way,
we can preserve the default safety behavior while avoiding the need for
local rebuilds just to change this setting.


Thanks,
Umang


> 
> Best regards,
> Ruidong
> 
>> ---
>>   drivers/ras/aest/aest-core.c | 9 ++++++++-
>>   1 file changed, 8 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/ras/aest/aest-core.c b/drivers/ras/aest/aest-core.c
>> index b4f4c975da1d..9ce782a66edf 100644
>> --- a/drivers/ras/aest/aest-core.c
>> +++ b/drivers/ras/aest/aest-core.c
>> @@ -22,6 +22,11 @@ DEFINE_PER_CPU(struct aest_device, percpu_adev);
>>   #undef pr_fmt
>>   #define pr_fmt(fmt) "AEST: " fmt
>>   +static bool aest_panic_on_ue;
>> +module_param(aest_panic_on_ue, bool, 0644);
>> +MODULE_PARM_DESC(aest_panic_on_ue,
>> +         "Panic on unrecoverable error: 0=off 1=on (default: 1)");
>> +
>>   #ifdef CONFIG_DEBUG_FS
>>   struct dentry *aest_debugfs;
>>   #endif
>> @@ -342,9 +347,11 @@ void aest_proc_record(struct aest_record *record,
>> void *data, bool fake)
>>               aest_record_info(
>>                   record,
>>                   "Simulated error! Skip panic due to fault
>> injection\n");
>> -        else
>> +        else if (aest_panic_on_ue)
>>               aest_panic(record, &regs,
>>                      "AEST: unrecoverable error encountered");
>> +        else
>> +            aest_record_err(record, "UE detected, panic suppressed\n");
>>       }
>>         aest_log(record, &regs);
>>
> 



^ permalink raw reply

* Re: [PATCH v3 1/5] arm_mpam: resctrl: Pick classes for use as mbm counters
From: Shaopeng Tan (Fujitsu) @ 2026-05-12  6:50 UTC (permalink / raw)
  To: Ben Horgan
  Cc: amitsinght@marvell.com, baisheng.gao@unisoc.com,
	baolin.wang@linux.alibaba.com, carl@os.amperecomputing.com,
	dave.martin@arm.com, david@kernel.org, dfustini@baylibre.com,
	fenghuay@nvidia.com, gshan@redhat.com, james.morse@arm.com,
	jonathan.cameron@huawei.com, kobak@nvidia.com,
	lcherian@marvell.com, linux-arm-kernel@lists.infradead.org,
	linux-kernel@vger.kernel.org, peternewman@google.com,
	punit.agrawal@oss.qualcomm.com, quic_jiles@quicinc.com,
	reinette.chatre@intel.com, rohit.mathew@arm.com,
	scott@os.amperecomputing.com, sdonthineni@nvidia.com,
	xhao@linux.alibaba.com, zengheng4@huawei.com, x86@kernel.org
In-Reply-To: <20260511154147.557481-2-ben.horgan@arm.com>

Hello Ben,

> From: James Morse <james.morse@arm.com>
> 
> resctrl has two types of counters, NUMA-local and global. MPAM can only
> count global either using MSC at the L3 cache or in the memory controllers.
> When global and local equate to the same thing continue just to call it
> global.
> 
> Tested-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Tested-by: Zeng Heng <zengheng4@huawei.com>
> Reviewed-by: Shaopeng Tan <tan.shaopeng@jp.fujitsu.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Signed-off-by: James Morse <james.morse@arm.com>
> Signed-off-by: Ben Horgan <ben.horgan@arm.com>
> ---
> Changes since rfc v1:
> Move finding any_mon_comp into monitor boilerplate patch
> Move mpam_resctrl_get_domain_from_cpu() into monitor boilerplate
> Remove free running check
> Trim commit message
> ---
>  drivers/resctrl/mpam_resctrl.c | 26 ++++++++++++++++++++++++++
>  1 file changed, 26 insertions(+)
> 
> diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
> index 226ff6f532fa..f70fa65d39e4 100644
> --- a/drivers/resctrl/mpam_resctrl.c
> +++ b/drivers/resctrl/mpam_resctrl.c
> @@ -606,6 +606,16 @@ static bool cache_has_usable_csu(struct mpam_class *class)
>          return true;
>  }
>  
> +static bool class_has_usable_mbwu(struct mpam_class *class)
> +{
> +       struct mpam_props *cprops = &class->props;
> +
> +       if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops))
> +               return false;
> +
> +       return true;
> +}
> +
>  /*
>   * Calculate the worst-case percentage change from each implemented step
>   * in the control.
> @@ -983,6 +993,22 @@ static void mpam_resctrl_pick_counters(void)
>                                  break;
>                          }
>                  }
> +
> +               if (class_has_usable_mbwu(class) &&
> +                   topology_matches_l3(class) &&
> +                   traffic_matches_l3(class)) {
> +                       pr_debug("class %u has usable MBWU, and matches L3 topology and traffic\n",
> +                                class->level);
> +
> +                       /*
> +                        * We can't distinguish traffic by destination so
> +                        * we don't know if it's staying on the same NUMA
> +                        * node. Hence, we can't calculate mbm_local except
> +                        * when we only have one L3 and it's equivalent to
> +                        * mbm_total and so always use mbm_total.
> +                        */
> +                       counter_update_class(QOS_L3_MBM_TOTAL_EVENT_ID, class);
> +               }
>          }
>  }
>  
> -- 
> 2.43.0

https://lore.kernel.org/lkml/599617aa-aade-4fde-9efa-79d592f1ff3f@arm.com/

This concerns the comment I received last time. 
I may not have fully understood it, so I'd like to clarify it once more.

Even if the system as a whole has multiple L3 caches and multiple NUMA nodes,
ABMC will be enabled as long as there is a single L3 cache and a single corresponding NUMA node.
Is my understanding correct?
If my understanding is correct, within the 'traffic_matches_l3()' function,
ABMC is enabled only when the entire system has a single NUMA node and a single L3 cache.

 870 static bool traffic_matches_l3(struct mpam_class *class)
 871 {
...
 901
 902         if (!cpumask_equal(tmp_cpumask, cpu_possible_mask)) {
 903                 pr_debug("There is more than one L3\n");
 904                 return false; *
 905         }
...
 912
 913         if (num_possible_nodes() > 1) {
 914                 pr_debug("There is more than one numa node\n");
 915                 return false;  *
 916         }
 917
...
 926 }


Also, I'd also like to confirm one more thing.
The mpam_resctrl_pick_mba() function also calls traffic_matches_l3(). 
This suggests that, except in scenarios where the entire system has a single L3 cache and a single NUMA node (ABMC is disabled),
the Memory Bandwidth allocation will also be disabled.
Is this the intended behavior? If so, could you explain why?

Best regards,
Shaopeng TAN





^ permalink raw reply

* Re: [PATCH v2 06/16] nvmem: add mt6323 PMIC EFUSE driver
From: Andy Shevchenko @ 2026-05-12  6:47 UTC (permalink / raw)
  To: rva333
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Sen Chu, Sean Wang, Macpaul Lin,
	Lee Jones, Srinivas Kandagatla, Rafael J. Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, linux-iio, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, linux-pm, Ben Grisdale
In-Reply-To: <20260512-mt6323-v2-6-3efcba579e88@protonmail.com>

On Tue, May 12, 2026 at 8:21 AM Roman Vivchar via B4 Relay
<devnull+rva333.protonmail.com@kernel.org> wrote:
>
> Add support for the EFUSE controller found in the Mediatek MT6323 PMIC.
> The MT6323 EFUSE stores 24 bytes of hardware-related data, such as
> thermal sensor calibration values.

...

> +#include <linux/err.h>

> +#include <linux/errno.h>

Doesn't seem to be used as err.h implies asm/errno.h that provides
basic error codes.

> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/nvmem-provider.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +#include <linux/types.h>

...

> +static int mt6323_efuse_read(void *context, unsigned int offset, void *val,
> +                            size_t bytes)
> +{
> +       struct regmap *map = context;
> +       u32 tmp;
> +       u16 *buf = val;
> +       int ret;
> +
> +       /*
> +        * Manual regmap_read with loop is needed, because PWRAP is not
> +        * a continuous MMIO space, but rather FSM which doesn't implement
> +        * necessary read callback for the regmap_read_raw and regmap_read_bulk
> +        * functions.
> +        */
> +       for (size_t i = 0; i < bytes; i += sizeof(*buf)) {
> +               ret = regmap_read(map, MT6323_EFUSE_DOUT_BASE + offset + i, &tmp);
> +               if (ret)
> +                       return ret;

> +               *buf++ = (u16)tmp;

Why explicit casting?

> +       }
> +
> +       return 0;
> +}

-- 
With Best Regards,
Andy Shevchenko


^ permalink raw reply

* [PATCH] dt-bindings: arm-smmu: qcom: Add compatible for IPQ9650 SoC
From: Kathiravan Thirumoorthy @ 2026-05-12  6:47 UTC (permalink / raw)
  To: Will Deacon, Robin Murphy, Joerg Roedel, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley
  Cc: linux-arm-kernel, iommu, devicetree, linux-kernel,
	Kathiravan Thirumoorthy

Qualcomm IPQ9650 SoC include APPS SMMU that implements arm,mmu-500.
Document the compatible for the same.

Signed-off-by: Kathiravan Thirumoorthy <kathiravan.thirumoorthy@oss.qualcomm.com>
---
 Documentation/devicetree/bindings/iommu/arm,smmu.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
index 06fb5c8e7547..226f16711d67 100644
--- a/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
+++ b/Documentation/devicetree/bindings/iommu/arm,smmu.yaml
@@ -37,6 +37,7 @@ properties:
           - enum:
               - qcom,eliza-smmu-500
               - qcom,glymur-smmu-500
+              - qcom,ipq9650-smmu-500
               - qcom,kaanapali-smmu-500
               - qcom,milos-smmu-500
               - qcom,qcm2290-smmu-500

---
base-commit: e98d21c170b01ddef366f023bbfcf6b31509fa83
change-id: 20260512-ipq9650_smmu_binding-36dc05d39860

Best regards,
--  
Kathiravan Thirumoorthy <kathiravan.thirumoorthy@oss.qualcomm.com>



^ permalink raw reply related

* Re: [PATCH 0/8] ras: aest: extend AEST support to Device Tree frontend
From: Umang Chheda @ 2026-05-12  6:45 UTC (permalink / raw)
  To: Ruidong Tian, Tony Luck, Borislav Petkov, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Konrad Dybcio,
	catalin.marinas, will, lpieralisi, rafael, mark.rutland,
	Sudeep Holla
  Cc: linux-arm-msm, linux-acpi, linux-arm-kernel, linux-edac,
	linux-kernel, devicetree, Faruque Ansari
In-Reply-To: <8f1529af-f6fe-44bc-a4b1-c47a19824d1e@linux.alibaba.com>

Hi Ruidong,


On 5/6/2026 1:40 PM, Ruidong Tian wrote:
> Hi Umang,
> 
> Thanks for your patch.
> 
> Would it be okay if I include this patch in the next version of the AEST
> patch series? I will make sure to add your Signed-off-by line.


Yes, you can include this patch in the next version - we will represent
it and respond to all of the queries received on DT specific patches.

How should I be sharing the patch fixes based on comments received from
maintainers to you ? so that you can include in your patch series ?

Also, when is your plan to post the next version fixing the comments
received ?


Thanks,
Umang


> 
> Best regards,
> Ruidong
> 
> 在 2026/5/5 20:23, Umang Chheda 写道:
>> This series extends Tian Ruidong’s [1] ACPI-based AEST support series
>> to also cover Device Tree based platforms.
>>
>> While the existing AEST driver relies on the AEST ACPI table [3], many
>> embedded Arm platforms use Device Tree exclusively and cannot use the
>> driver today. This series adds a DT frontend that mirrors the ACPI
>> implementation and feeds the same core driver, keeping ACPI and DT
>> paths functionally equivalent.
>>
>> Along the way, several correctness issues were identified in the core
>> driver and are fixed in the first part of this series.
>>
>> The DT frontend is mutually exclusive with ACPI and does not introduce
>> any DT-specific logic into the core.
>>
>> How to test with QEMU
>> --------------------------
>> Tian Ruidong's QEMU fork [2] emulates AEST MMIO error records on the
>> virt machine.  To test the DT frontend:
>>
>> 1. Build QEMU:
>>
>>       git clone https://github.com/winterddd/qemu.git
>>       cd qemu
>>       git checkout c5e2d5dec9fd62ba622314c40bff0fbecb4dfb34
>>       ./configure --target-list=aarch64-softmmu
>>       make -j$(nproc)
>>
>> 2. Build the kernel with:
>>
>>       CONFIG_OF_AEST=y
>>       CONFIG_AEST=y
>>       CONFIG_ARM64_RAS_EXTN=y
>>       CONFIG_RAS=y
>>
>> 3. Add the following DT node to your virt machine DTB.  The QEMU
>>     fork maps DRAM error records at 0x090d0000 (SPI 44) and CMN
>>     vendor records at 0x090e0000 (SPI 45):
>>
>>       aest {
>>           compatible = "arm,aest";
>>           #address-cells = <2>;
>>           #size-cells = <2>;
>>           ranges;
>>           interrupt-parent = <&gic>;
>>
>>           /* DRAM memory node — MMIO at 0x090d0000, SPI 44 */
>>           aest-dram0@90d0000 {
>>               compatible               = "arm,aest-memory";
>>               arm,interface-type       = <1>;
>>               arm,group-format         = <0>;
>>               arm,interface-flags      = <0x22>;
>>               arm,num-records          = <4>;
>>               arm,record-impl          = /bits/ 64 <0x0>;
>>               arm,status-report        = /bits/ 64 <0x0>;
>>               arm,addr-mode            = /bits/ 64 <0x0>;
>>               arm,proximity-domain     = <0>;
>>               reg                      = <0x0 0x090d0000 0x0 0x1000>,
>>                                          <0x0 0x090d0800 0x0 0x200>,
>>                                          <0x0 0x090d0e00 0x0 0x100>;
>>               reg-names                = "errblock", "fault-inject",
>>                                          "err-group";
>>               interrupts               = <GIC_SPI 44
>> IRQ_TYPE_LEVEL_HIGH>;
>>               interrupt-names          = "fhi";
>>           };
>>     };
>>
>> 4. Boot QEMU with acpi=off:
>>
>>       ./qemu-system-aarch64 \
>>         -machine virt,accel=tcg,gic-version=3 \
>>         -cpu cortex-a57 -m 2G -smp 4 \
>>         -kernel Image -dtb virt-aest.dtb \
>>         -append "console=ttyAMA0 acpi=off earlycon" \
>>         -nographic
>>
>> 5. Verify probe:
>>
>>       dmesg | grep "DT AEST"
>>       # Expected: DT AEST: registered 1 AEST error source(s) from DT
>>       ls /sys/kernel/debug/aest/
>>
>> 6. Inject a CE error via the QEMU MMIO fault injection registers.
>>     The QEMU device accepts 64-bit accesses only (use devmem with
>>     the 64-bit width flag):
>>
>>       devmem 0x090d0808 64 0x80000040   # CDOFF | CE inject
>>
>>     This triggers QEMU's error_record_inj_write() which sets
>>     ERR<n>STATUS.V=1 and asserts the IRQ.  The kernel driver's
>>     aest_irq_func() fires, reads the status, and logs:
>>
>>       AEST: {1}[Hardware Error]: Hardware error from AEST memory.90d0000
>>       AEST: {1}[Hardware Error]: Error from memory at SRAT proximity
>> domain 0x0
>>
>> Testing
>> -------
>> - Validated on Qualcomm's lemans-evk and monaco-evk board with DT boot.
>> - Validated CE and UE injection via debugfs soft_inject.
>> - Tested ACPI path is unaffected: ACPI boot continues to use
>>    drivers/acpi/arm64/aest.c unchanged.
>>
>> [1] https://lore.kernel.org/lkml/20260122094656.73399-1-
>> tianruidong@linux.alibaba.com/
>> [2] https://github.com/winterddd/qemu/tree/error_record
>> [3] https://developer.arm.com/documentation/den0085/0200/
>>
>> Signed-off-by: Umang Chheda <umang.chheda@oss.qualcomm.com>
>> ---
>> Umang Chheda (8):
>>        ras: aest: Fix shared processor node handling and error log
>> messages
>>        ras: aest: Fix CE/UE error counts not incrementing in debugfs
>>        ras: aest: Skip unimplemented records in debugfs
>>        ras: aest: Add panic_on_ue module parameter
>>        dt-bindings: arm: ras: Introduce bindings for ARM AEST
>>        ras: aest: Add DT frontend for ARM AEST RAS error sources
>>        arm64: dts: qcom: lemans: add AEST error nodes
>>        arm64: dts: qcom: monaco: add AEST error nodes
>>
>>   .../devicetree/bindings/arm/arm,aest.yaml          | 406 +++++++++++++
>>   arch/arm64/boot/dts/qcom/lemans.dtsi               |  41 ++
>>   arch/arm64/boot/dts/qcom/monaco.dtsi               |  41 ++
>>   drivers/ras/aest/Kconfig                           |  15 +-
>>   drivers/ras/aest/Makefile                          |   2 +
>>   drivers/ras/aest/aest-core.c                       |  63 +-
>>   drivers/ras/aest/aest-of.c                         | 673 +++++++++++
>> ++++++++++
>>   drivers/ras/aest/aest-sysfs.c                      |  27 +-
>>   drivers/ras/aest/aest.h                            |  15 +-
>>   include/dt-bindings/arm/aest.h                     |  43 ++
>>   10 files changed, 1310 insertions(+), 16 deletions(-)
>> ---
>> base-commit: a67b7fd0dd1f6ccf3d128dc2099cdb07af1f6a09
>> change-id: 20260505-aest-devicetree-support-a3722d90e1f5
>> prerequisite-message-id: <20260122094656.73399-1-
>> tianruidong@linux.alibaba.com>
>> prerequisite-patch-id: c5a7c6431c6c1e6351241e694ee053800039d41d
>> prerequisite-patch-id: 1f6e2c20829eee41a210dd8a538f1e8efcc65872
>> prerequisite-patch-id: 5556287e3f46c2ed2c0431c53c7782e87bcbd866
>> prerequisite-patch-id: 2edae0a136d7779b8f686181720e71d044a73311
>> prerequisite-patch-id: b5190b2844dcb01e72f87a59f3a29548795fdb82
>> prerequisite-patch-id: 7ba848583708b2ae776a7ce847bb056e3de7f77b
>> prerequisite-patch-id: 397e5b22802b67942435f4f2968f0b1e210ba0e8
>> prerequisite-patch-id: 2169f4b65537eecbd0ccbd2ad6b28c64ec44655d
>> prerequisite-patch-id: b626f85d98747595b3240bc49e6ad9c9dd5c0fa9
>> prerequisite-patch-id: 1323dfd2eebad2ef6514dbbce58ba08e8859f894
>> prerequisite-patch-id: 95b826e5e329408437a3ef336c4f45d4d74f82bb
>> prerequisite-patch-id: b60ff489a5a33c5d5220fa8144af7b7511769cba
>> prerequisite-patch-id: 43f35a52b8a3d13c938ff08083403c1d3bd0df8b
>> prerequisite-patch-id: c55d4e9117ca36d3c2cba82d550a618cb82bb745
>> prerequisite-patch-id: 3885e10f318ae8101d6909b35d92a976cc359e3c
>> prerequisite-patch-id: 92958cde05577f069c5659018a274bb39cfb6b24
>>
>> Best regards,
>> -- 
>> Umang Chheda <umang.chheda@oss.qualcomm.com>
>>
> 



^ permalink raw reply

* Re: [PATCH v3 4/7] PCI: dwc: Use common pci_host_common_link_train_delay() helper
From: Manivannan Sadhasivam @ 2026-05-12  6:45 UTC (permalink / raw)
  To: Krzysztof Wilczyński
  Cc: Hans Zhang, bhelgaas, lpieralisi, vigneshr, jingoohan1,
	thomas.petazzoni, pali, ryder.lee, claudiu.beznea.uj, mpillai,
	robh, s-vadapalli, linux-omap, linux-arm-kernel, claudiu.beznea,
	linux-mediatek, linux-renesas-soc, linux-pci, linux-kernel
In-Reply-To: <20260511070139.GA1096586@rocinante>

On Mon, May 11, 2026 at 04:02:42PM +0900, Krzysztof Wilczyński wrote:
> Hello,
> 
> > -	/*
> > -	 * As per PCIe r6.0, sec 6.6.1, a Downstream Port that supports Link
> > -	 * speeds greater than 5.0 GT/s, software must wait a minimum of 100 ms
> > -	 * after Link training completes before sending a Configuration Request.
> > -	 */
> > -	if (pci->max_link_speed > 2)
> > -		msleep(PCIE_RESET_CONFIG_WAIT_MS);
> > +	pci_host_common_link_train_delay(pci->max_link_speed);
> 
> This comment could move to the helper you added.
> 

Not required, as the macro definition in drivers/pci/pci.h already has an
elaborative comment with spec citation.

- Mani

-- 
மணிவண்ணன் சதாசிவம்


^ permalink raw reply

* [PATCH RESEND] clocksource: move NXP timer selection to drivers/clocksource
From: Enric Balletbo i Serra @ 2026-05-12  6:45 UTC (permalink / raw)
  To: Russell King, Frank Li, Sascha Hauer, Pengutronix Kernel Team,
	Fabio Estevam, Daniel Lezcano, Thomas Gleixner
  Cc: linux-arm-kernel, imx, linux-kernel, Enric Balletbo i Serra

From: Enric Balletbo i Serra <eballetb@redhat.com>

The Kconfig logic for selecting the scheduler clocksource on
NXP Vybrid (VF610) uses a `choice` block restricted to 32-bit ARM. This
prevents 64-bit architectures, such as the NXP S32 family, from enabling
the NXP Periodic Interrupt Timer (PIT) driver (CONFIG_NXP_PIT_TIMER).

Relocate the NXP clocksource selection from arch/arm/mach-imx/Kconfig to
drivers/clocksource/Kconfig. This allows the configuration to be shared
across different architectures.

Update the selection to include support for ARCH_S32 and add a "None"
option to allow using the standard ARM Architected Timer. The Vybrid
Global Timer option is now specifically restricted to 32-bit ARM SOC_VF610
platforms.

Fixes: bee33f22d7c3 ("clocksource/drivers/nxp-pit: Add NXP Automotive s32g2 / s32g3 support")
Signed-off-by: Enric Balletbo i Serra <eballetb@redhat.com>
---
 arch/arm/mach-imx/Kconfig   | 21 ---------------------
 drivers/clocksource/Kconfig | 31 +++++++++++++++++++++++++++++++
 2 files changed, 31 insertions(+), 21 deletions(-)

diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 6ea1bd55acf8..a361840d7a04 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -227,27 +227,6 @@ config SOC_VF610
 	help
 	  This enables support for Freescale Vybrid VF610 processor.
 
-choice
-	prompt "Clocksource for scheduler clock"
-	depends on SOC_VF610
-	default VF_USE_ARM_GLOBAL_TIMER
-
-	config VF_USE_ARM_GLOBAL_TIMER
-		bool "Use ARM Global Timer"
-		depends on ARCH_MULTI_V7
-		select ARM_GLOBAL_TIMER
-		select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
-		help
-		  Use the ARM Global Timer as clocksource
-
-	config VF_USE_PIT_TIMER
-		bool "Use PIT timer"
-		select NXP_PIT_TIMER
-		help
-		  Use SoC Periodic Interrupt Timer (PIT) as clocksource
-
-endchoice
-
 endif
 
 endif
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index fd9112706545..b5c88ec65802 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -794,4 +794,35 @@ config RTK_SYSTIMER
 	  this option only when building for a Realtek platform or for compilation
 	  testing.
 
+choice
+	prompt "NXP clocksource for scheduler clock"
+	depends on SOC_VF610 || ARCH_S32
+	# Default to Global Timer for Vybrid (32-bit)
+	default VF_USE_ARM_GLOBAL_TIMER if SOC_VF610
+	# Default to None for S32 (64-bit)
+	default VF_TIMER_NONE if ARCH_S32
+
+	config VF_USE_ARM_GLOBAL_TIMER
+		bool "Use NXP Vybrid Global Timer"
+		# This option is ONLY visible if we are on 32-bit ARM
+		depends on ARM && SOC_VF610
+		select ARM_GLOBAL_TIMER
+		select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+		help
+		  Use the NXP Vybrid Global Timer as clocksource.
+
+	config VF_USE_PIT_TIMER
+		bool "Use NXP PIT timer"
+		select NXP_PIT_TIMER
+		help
+		  Use NXP Periodic Interrupt Timer (PIT) as clocksource.
+
+	config VF_TIMER_NONE
+		bool "None (Use standard Arch Timer)"
+		help
+		  Do not use any specific NXP timer driver. Use the standard
+		  ARM Architected Timer instead.
+
+endchoice
+
 endmenu

---
base-commit: 11439c4635edd669ae435eec308f4ab8a0804808
change-id: 20260302-fix-nxp-timer-9cb1fbd7afcd

Best regards,
-- 
Enric Balletbo i Serra <eballetb@redhat.com>



^ permalink raw reply related

* Re: [PATCH v2 05/16] iio: adc: mediatek: add mt6323 PMIC AUXADC driver
From: Andy Shevchenko @ 2026-05-12  6:43 UTC (permalink / raw)
  To: rva333
  Cc: Jonathan Cameron, David Lechner, Nuno Sá, Andy Shevchenko,
	Rob Herring, Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
	AngeloGioacchino Del Regno, Sen Chu, Sean Wang, Macpaul Lin,
	Lee Jones, Srinivas Kandagatla, Rafael J. Wysocki, Daniel Lezcano,
	Zhang Rui, Lukasz Luba, linux-iio, devicetree, linux-kernel,
	linux-arm-kernel, linux-mediatek, linux-pm, Ben Grisdale
In-Reply-To: <20260512-mt6323-v2-5-3efcba579e88@protonmail.com>

On Tue, May 12, 2026 at 8:21 AM Roman Vivchar via B4 Relay
<devnull+rva333.protonmail.com@kernel.org> wrote:
>
> The mt6323 AUXADC is a 15-bit ADC used for system monitoring. This driver
> provides support for reading various channels including battery and
> charger voltages, battery and chip temperature, current sensing and
> accessory detection.
>
> Add a driver for the AUXADC found in the MediaTek mt6323 PMIC.

...

> +#include <linux/array_size.h>
> +#include <linux/bitfield.h>
> +#include <linux/bits.h>
> +#include <linux/cleanup.h>
> +#include <linux/delay.h>
> +#include <linux/iio/iio.h>
> +#include <linux/mod_devicetable.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +#include <linux/stringify.h>

+ time.h // USEC_PER_MSEC

> +#include <linux/types.h>

...

> +#define AUXADC_TRIM_CH2                (3 << 10)
> +#define AUXADC_TRIM_CH4                (3 << 8)
> +#define AUXADC_TRIM_CH5                (3 << 4)
> +#define AUXADC_TRIM_CH6                (3 << 2)

Without a comment it's hard to say if these are like masks or actual
values. Can you clarify that in the comment on top of these four?

> +#define VOLTAGE_FULL_RANGE     1800

Are there any units? Are they millivolts or is it just some scale?

...

> +#define MTK_PMIC_IIO_CHAN(_name, _idx, _ch_type)       \
> +{                                                      \
> +       .type = _ch_type,                              \
> +       .indexed = 1,                                  \
> +       .channel = _idx,                               \
> +       .address = _idx,                               \
> +       .datasheet_name = __stringify(_name),          \
> +       .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
> +                             BIT(IIO_CHAN_INFO_SCALE) \

Keep the trailing comma as this is not a terminator.

> +}

...

> +/**
> + * struct mt6323_auxadc - Main driver structure
> + * @regmap:        Regmap from PWRAP
> + * @lock:          Mutex to serialize AUXADC reading vs configuration
> + *
> + * The MediaTek MT6323 (as well as lot of other PMICs) have the following hierarchy:
> + * PMIC AUXADC <- PMIC MFD <- SoC PWRAP (wrapper for PWRAP FSM)
> + *
> + * Therefore, PWRAP regmap should be get using dev->parent->parent.

get --> obtained

> + */

...

> +static int mt6323_auxadc_prepare_channel(struct mt6323_auxadc *auxadc)
> +{
> +       struct regmap *map = auxadc->regmap;
> +       u32 val;
> +       int ret;
> +
> +       ret = regmap_read(map, MT6323_AUXADC_CON19, &val);
> +       if (ret)
> +               return ret;
> +
> +       /* The ADC is idle */
> +       if (!(val & AUXADC_DECI_GDLY_MASK))
> +               return 0;
> +
> +       ret = regmap_read_poll_timeout(map, MT6323_AUXADC_ADC19, val,
> +                                      !(val & AUXADC_ADC19_BUSY_MASK), 10, 500);

It's better to have a logical split

       ret = regmap_read_poll_timeout(map, MT6323_AUXADC_ADC19,
                                      val, !(val & AUXADC_ADC19_BUSY_MASK),
                                      10, 500);

> +       if (ret)
> +               return ret;
> +
> +       return regmap_clear_bits(map, MT6323_AUXADC_CON19,
> +                                AUXADC_DECI_GDLY_MASK);
> +}

...

> +static int mt6323_auxadc_read(struct mt6323_auxadc *auxadc,
> +                             const struct iio_chan_spec *chan, int *out)
> +{
> +       struct regmap *map = auxadc->regmap;
> +       u32 val, reg = mt6323_auxadc_channel_to_reg(chan->address);
> +       int ret;
> +
> +       ret = regmap_read_poll_timeout(map, reg, val, (val & AUXADC_RDY_MASK),

Parentheses are not needed in this case. But I'm fine with it here as
it probably makes it easier to get the idea.

> +                                      1 * USEC_PER_MSEC, 100 * USEC_PER_MSEC);
> +       if (ret)
> +               return ret;
> +
> +       *out = FIELD_GET(AUXADC_DATA_MASK, val);
> +
> +       return 0;
> +}
> +
> +static int mt6323_auxadc_read_raw(struct iio_dev *indio_dev,
> +                                 const struct iio_chan_spec *chan, int *val,
> +                                 int *val2, long mask)

Logical split

static int mt6323_auxadc_read_raw(struct iio_dev *indio_dev,
                                 const struct iio_chan_spec *chan,
                                 int *val, int *val2, long mask)

> +{
> +       struct mt6323_auxadc *auxadc = iio_priv(indio_dev);
> +       int ret, mult = 1;

Decouple assignment and definition. These types of assignments are
hard to maintain and might lead to subtle mistakes in the future.

> +       if (mask == IIO_CHAN_INFO_RAW) {
> +               guard(mutex)(&auxadc->lock);
> +               ret = mt6323_auxadc_prepare_channel(auxadc);
> +               if (ret)
> +                       return ret;
> +
> +               ret = mt6323_auxadc_request(auxadc, chan->address);
> +               if (ret)
> +                       return ret;

Please, add a comment with the reference to a datasheet (ideally)
explaining this sleep.

> +               fsleep(300);
> +
> +               ret = mt6323_auxadc_read(auxadc, chan, val);
> +               if (ret)
> +                       return ret;
> +               return IIO_VAL_INT;
> +       } else if (mask == IIO_CHAN_INFO_SCALE) {

Redundant 'else'

> +               if (chan->channel == MT6323_AUXADC_ISENSE ||
> +                   chan->channel == MT6323_AUXADC_BATSNS)
> +                       mult = 4;
> +
> +               *val = mult * VOLTAGE_FULL_RANGE;
> +               *val2 = AUXADC_PRECISE;
> +
> +               return IIO_VAL_FRACTIONAL;

> +       } else

Ditto, and it's the wrong style. Read the Coding Style documentation
to clarify this.

> +               return -EINVAL;
> +}

...

> +       ret = devm_mutex_init(dev, &auxadc->lock);
> +       if (ret)
> +               return dev_err_probe(dev, ret, "failed to initialize mutex\n");

Unneeded error message. Most likely it's -ENOMEM, which will be
ignored by dev_err_probe() anyway.

...

> +       ret = devm_iio_device_register(dev, iio);
> +       if (ret)
> +               return dev_err_probe(dev, ret, "failed to register iio device\n");

If you don't see the device, it's failed to register, do we need this message?

-- 
With Best Regards,
Andy Shevchenko


^ permalink raw reply

* [LINUX PATCH] serial: xilinx_uartps: fix runtime PM race during probe
From: Shubhrajyoti Datta @ 2026-05-12  6:41 UTC (permalink / raw)
  To: linux-kernel
  Cc: git, shubhrajyoti.datta, Greg Kroah-Hartman, Jiri Slaby,
	Michal Simek, Shubhrajyoti Datta, linux-serial, linux-arm-kernel

pm_runtime_enable() was called with usage_count=0, allowing the PM
core to immediately queue a deferred suspend via pm_runtime_work.
This raced with console write, causing cdns_runtime_suspend to
fire before the port was fully registered.

Hold a reference with pm_runtime_get_noresume() before enabling
runtime PM.

Fixes: d62100f1aac2 ("serial: xilinx_uartps: Add pm runtime support")
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---
 drivers/tty/serial/xilinx_uartps.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index a072b75dbaf2..e316cac4f35b 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -1800,6 +1800,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
 	pm_runtime_use_autosuspend(&pdev->dev);
 	pm_runtime_set_autosuspend_delay(&pdev->dev, UART_AUTOSUSPEND_TIMEOUT);
 	pm_runtime_set_active(&pdev->dev);
+	pm_runtime_get_noresume(&pdev->dev);
 	pm_runtime_enable(&pdev->dev);
 	device_init_wakeup(port->dev, true);
 
@@ -1824,6 +1825,8 @@ static int cdns_uart_probe(struct platform_device *pdev)
 			"uart_add_one_port() failed; err=%i\n", rc);
 		goto err_out_pm_disable;
 	}
+	pm_runtime_mark_last_busy(&pdev->dev);
+	pm_runtime_put_autosuspend(&pdev->dev);
 
 #ifdef CONFIG_SERIAL_XILINX_PS_UART_CONSOLE
 	/* This is not port which is used for console that's why clean it up */
@@ -1842,6 +1845,7 @@ static int cdns_uart_probe(struct platform_device *pdev)
 	return 0;
 
 err_out_pm_disable:
+	pm_runtime_put_noidle(&pdev->dev);
 	pm_runtime_disable(&pdev->dev);
 	pm_runtime_set_suspended(&pdev->dev);
 	pm_runtime_dont_use_autosuspend(&pdev->dev);
-- 
2.49.1



^ permalink raw reply related

* Re: [PATCH v4] media: verisilicon: Create AV1 helper library
From: Hans Verkuil @ 2026-05-12  6:33 UTC (permalink / raw)
  To: Benjamin Gaignard, nicolas.dufresne, p.zabel, mchehab, heiko
  Cc: linux-kernel, linux-media, linux-rockchip, linux-arm-kernel,
	kernel
In-Reply-To: <20260505081939.17230-1-benjamin.gaignard@collabora.com>

Hi Benjamin,

It looks much better now that it uses a struct.

I have some other comments, though:

On 05/05/2026 10:19, Benjamin Gaignard wrote:
> Regroup all none hardware related AV1 functions into a helper library.
> The goal is to avoid code duplication for future AV1 codecs.
> 
> Tested on rock 5b board Fluster score remains the same 204/241.
> 
> Signed-off-by: Benjamin Gaignard <benjamin.gaignard@collabora.com>
> Reviewed-by: Nicolas Dufresne <nicolas.dufresne@collabora.com>
> ---
> version 4:
> - change functions prototypes to use a structure.
> - rebased on v7.1-rc2 tag.
> 
>  drivers/media/platform/verisilicon/Makefile   |   7 +-
>  .../media/platform/verisilicon/hantro_av1.c   | 782 ++++++++++++++
>  .../media/platform/verisilicon/hantro_av1.h   |  62 ++
>  ...entropymode.c => hantro_av1_entropymode.c} |  18 +-
>  ...entropymode.h => hantro_av1_entropymode.h} |  18 +-
>  ...av1_filmgrain.c => hantro_av1_filmgrain.c} | 125 ++-
>  .../verisilicon/hantro_av1_filmgrain.h        |  48 +
>  .../media/platform/verisilicon/hantro_hw.h    |   7 +-
>  .../verisilicon/rockchip_av1_filmgrain.h      |  36 -
>  .../verisilicon/rockchip_vpu981_hw_av1_dec.c  | 977 ++----------------
>  .../platform/verisilicon/rockchip_vpu_hw.c    |   7 +-
>  11 files changed, 1076 insertions(+), 1011 deletions(-)
>  create mode 100644 drivers/media/platform/verisilicon/hantro_av1.c
>  create mode 100644 drivers/media/platform/verisilicon/hantro_av1.h
>  rename drivers/media/platform/verisilicon/{rockchip_av1_entropymode.c => hantro_av1_entropymode.c} (99%)
>  rename drivers/media/platform/verisilicon/{rockchip_av1_entropymode.h => hantro_av1_entropymode.h} (95%)
>  rename drivers/media/platform/verisilicon/{rockchip_av1_filmgrain.c => hantro_av1_filmgrain.c} (85%)
>  create mode 100644 drivers/media/platform/verisilicon/hantro_av1_filmgrain.h
>  delete mode 100644 drivers/media/platform/verisilicon/rockchip_av1_filmgrain.h
> 

<snip>

> diff --git a/drivers/media/platform/verisilicon/hantro_av1.c b/drivers/media/platform/verisilicon/hantro_av1.c
> new file mode 100644
> index 000000000000..7258a749f7b5
> --- /dev/null
> +++ b/drivers/media/platform/verisilicon/hantro_av1.c
> @@ -0,0 +1,782 @@

<snip>

> +int hantro_av1_get_frame_index(struct hantro_ctx *ctx, int ref)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
> +	u64 timestamp;
> +	int i, idx = frame->ref_frame_idx[ref];

It's probably wise to check that 'ref' isn't out of bounds (< 0 or
>= V4L2_AV1_REFS_PER_FRAME).

> +
> +	if (idx >= V4L2_AV1_TOTAL_REFS_PER_FRAME || idx < 0)
> +		return AV1_INVALID_IDX;
> +
> +	timestamp = frame->reference_frame_ts[idx];
> +	for (i = 0; i < AV1_MAX_FRAME_BUF_COUNT; i++) {
> +		if (!av1_dec->frame_refs[i].used)
> +			continue;
> +		if (av1_dec->frame_refs[i].timestamp == timestamp)
> +			return i;
> +	}
> +
> +	return AV1_INVALID_IDX;
> +}
> +
> +int hantro_av1_get_order_hint(struct hantro_ctx *ctx, int ref)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	int idx = hantro_av1_get_frame_index(ctx, ref);
> +
> +	if (idx != AV1_INVALID_IDX)
> +		return av1_dec->frame_refs[idx].order_hint;
> +
> +	return 0;
> +}
> +
> +int hantro_av1_frame_ref(struct hantro_ctx *ctx, u64 timestamp)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
> +	int i;
> +
> +	for (i = 0; i < AV1_MAX_FRAME_BUF_COUNT; i++) {
> +		int j;
> +
> +		if (av1_dec->frame_refs[i].used)
> +			continue;
> +
> +		av1_dec->frame_refs[i].width = frame->frame_width_minus_1 + 1;
> +		av1_dec->frame_refs[i].height = frame->frame_height_minus_1 + 1;
> +		av1_dec->frame_refs[i].mi_cols = DIV_ROUND_UP(frame->frame_width_minus_1 + 1, 8);
> +		av1_dec->frame_refs[i].mi_rows = DIV_ROUND_UP(frame->frame_height_minus_1 + 1, 8);
> +		av1_dec->frame_refs[i].timestamp = timestamp;
> +		av1_dec->frame_refs[i].frame_type = frame->frame_type;
> +		av1_dec->frame_refs[i].order_hint = frame->order_hint;
> +		av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx);
> +
> +		for (j = 0; j < V4L2_AV1_TOTAL_REFS_PER_FRAME; j++)
> +			av1_dec->frame_refs[i].order_hints[j] = frame->order_hints[j];
> +		av1_dec->frame_refs[i].used = true;
> +		av1_dec->current_frame_index = i;
> +
> +		return i;
> +	}
> +
> +	return AV1_INVALID_IDX;
> +}
> +
> +static void hantro_av1_frame_unref(struct hantro_ctx *ctx, int idx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +
> +	if (idx >= 0)
> +		av1_dec->frame_refs[idx].used = false;
> +}
> +
> +void hantro_av1_clean_refs(struct hantro_ctx *ctx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +
> +	int ref, idx;
> +
> +	for (idx = 0; idx < AV1_MAX_FRAME_BUF_COUNT; idx++) {
> +		u64 timestamp = av1_dec->frame_refs[idx].timestamp;
> +		bool used = false;
> +
> +		if (!av1_dec->frame_refs[idx].used)
> +			continue;
> +
> +		for (ref = 0; ref < V4L2_AV1_TOTAL_REFS_PER_FRAME; ref++) {
> +			if (ctrls->frame->reference_frame_ts[ref] == timestamp)
> +				used = true;
> +		}
> +
> +		if (!used)
> +			hantro_av1_frame_unref(ctx, idx);
> +	}
> +}
> +
> +size_t hantro_av1_luma_size(struct hantro_ctx *ctx)
> +{
> +	return ctx->ref_fmt.plane_fmt[0].bytesperline * ctx->ref_fmt.height;
> +}
> +
> +size_t hantro_av1_chroma_size(struct hantro_ctx *ctx)
> +{
> +	size_t cr_offset = hantro_av1_luma_size(ctx);
> +
> +	return ALIGN((cr_offset * 3) / 2, 64);
> +}
> +
> +static void hantro_av1_tiles_free(struct hantro_ctx *ctx)
> +{
> +	struct hantro_dev *vpu = ctx->dev;
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +
> +	if (av1_dec->db_data_col.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->db_data_col.size,
> +				  av1_dec->db_data_col.cpu,
> +				  av1_dec->db_data_col.dma);
> +	av1_dec->db_data_col.cpu = NULL;
> +
> +	if (av1_dec->db_ctrl_col.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->db_ctrl_col.size,
> +				  av1_dec->db_ctrl_col.cpu,
> +				  av1_dec->db_ctrl_col.dma);
> +	av1_dec->db_ctrl_col.cpu = NULL;
> +
> +	if (av1_dec->cdef_col.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->cdef_col.size,
> +				  av1_dec->cdef_col.cpu, av1_dec->cdef_col.dma);
> +	av1_dec->cdef_col.cpu = NULL;
> +
> +	if (av1_dec->sr_col.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->sr_col.size,
> +				  av1_dec->sr_col.cpu, av1_dec->sr_col.dma);
> +	av1_dec->sr_col.cpu = NULL;
> +
> +	if (av1_dec->lr_col.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->lr_col.size,
> +				  av1_dec->lr_col.cpu, av1_dec->lr_col.dma);
> +	av1_dec->lr_col.cpu = NULL;
> +}
> +
> +static int hantro_av1_tiles_reallocate(struct hantro_ctx *ctx)
> +{
> +	struct hantro_dev *vpu = ctx->dev;
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
> +	unsigned int num_tile_cols = tile_info->tile_cols;
> +	unsigned int height = ALIGN(ctrls->frame->frame_height_minus_1 + 1, 64);
> +	unsigned int height_in_sb = height / 64;
> +	unsigned int stripe_num = ((height + 8) + 63) / 64;
> +	size_t size;
> +
> +	if (av1_dec->db_data_col.size >=
> +	    ALIGN(height * 12 * ctx->bit_depth / 8, 128) * num_tile_cols)
> +		return 0;
> +
> +	hantro_av1_tiles_free(ctx);
> +
> +	size = ALIGN(height * 12 * ctx->bit_depth / 8, 128) * num_tile_cols;
> +	av1_dec->db_data_col.cpu = dma_alloc_coherent(vpu->dev, size,
> +						      &av1_dec->db_data_col.dma,
> +						      GFP_KERNEL);
> +	if (!av1_dec->db_data_col.cpu)
> +		goto buffer_allocation_error;
> +	av1_dec->db_data_col.size = size;
> +
> +	size = ALIGN(height * 2 * 16 / 4, 128) * num_tile_cols;
> +	av1_dec->db_ctrl_col.cpu = dma_alloc_coherent(vpu->dev, size,
> +						      &av1_dec->db_ctrl_col.dma,
> +						      GFP_KERNEL);
> +	if (!av1_dec->db_ctrl_col.cpu)
> +		goto buffer_allocation_error;
> +	av1_dec->db_ctrl_col.size = size;
> +
> +	size = ALIGN(height_in_sb * 44 * ctx->bit_depth * 16 / 8, 128) * num_tile_cols;
> +	av1_dec->cdef_col.cpu = dma_alloc_coherent(vpu->dev, size,
> +						   &av1_dec->cdef_col.dma,
> +						   GFP_KERNEL);
> +	if (!av1_dec->cdef_col.cpu)
> +		goto buffer_allocation_error;
> +	av1_dec->cdef_col.size = size;
> +
> +	size = ALIGN(height_in_sb * (3040 + 1280), 128) * num_tile_cols;
> +	av1_dec->sr_col.cpu = dma_alloc_coherent(vpu->dev, size,
> +						 &av1_dec->sr_col.dma,
> +						 GFP_KERNEL);
> +	if (!av1_dec->sr_col.cpu)
> +		goto buffer_allocation_error;
> +	av1_dec->sr_col.size = size;
> +
> +	size = ALIGN(stripe_num * 1536 * ctx->bit_depth / 8, 128) * num_tile_cols;
> +	av1_dec->lr_col.cpu = dma_alloc_coherent(vpu->dev, size,
> +						 &av1_dec->lr_col.dma,
> +						 GFP_KERNEL);
> +	if (!av1_dec->lr_col.cpu)
> +		goto buffer_allocation_error;
> +	av1_dec->lr_col.size = size;
> +
> +	av1_dec->num_tile_cols_allocated = num_tile_cols;
> +	return 0;
> +
> +buffer_allocation_error:
> +	hantro_av1_tiles_free(ctx);
> +	return -ENOMEM;
> +}
> +
> +void hantro_av1_exit(struct hantro_ctx *ctx)
> +{
> +	struct hantro_dev *vpu = ctx->dev;
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +
> +	if (av1_dec->global_model.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->global_model.size,
> +				  av1_dec->global_model.cpu,
> +				  av1_dec->global_model.dma);
> +	av1_dec->global_model.cpu = NULL;
> +
> +	if (av1_dec->tile_info.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->tile_info.size,
> +				  av1_dec->tile_info.cpu,
> +				  av1_dec->tile_info.dma);
> +	av1_dec->tile_info.cpu = NULL;
> +
> +	if (av1_dec->film_grain.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->film_grain.size,
> +				  av1_dec->film_grain.cpu,
> +				  av1_dec->film_grain.dma);
> +	av1_dec->film_grain.cpu = NULL;
> +
> +	if (av1_dec->prob_tbl.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->prob_tbl.size,
> +				  av1_dec->prob_tbl.cpu, av1_dec->prob_tbl.dma);
> +	av1_dec->prob_tbl.cpu = NULL;
> +
> +	if (av1_dec->prob_tbl_out.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->prob_tbl_out.size,
> +				  av1_dec->prob_tbl_out.cpu,
> +				  av1_dec->prob_tbl_out.dma);
> +	av1_dec->prob_tbl_out.cpu = NULL;
> +
> +	if (av1_dec->tile_buf.cpu)
> +		dma_free_coherent(vpu->dev, av1_dec->tile_buf.size,
> +				  av1_dec->tile_buf.cpu, av1_dec->tile_buf.dma);
> +	av1_dec->tile_buf.cpu = NULL;
> +
> +	hantro_av1_tiles_free(ctx);
> +}
> +
> +int hantro_av1_init(struct hantro_ctx *ctx)
> +{
> +	struct hantro_dev *vpu = ctx->dev;
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +
> +	memset(av1_dec, 0, sizeof(*av1_dec));
> +
> +	av1_dec->global_model.cpu = dma_alloc_coherent(vpu->dev, GLOBAL_MODEL_SIZE,
> +						       &av1_dec->global_model.dma,
> +						       GFP_KERNEL);
> +	if (!av1_dec->global_model.cpu)
> +		return -ENOMEM;
> +	av1_dec->global_model.size = GLOBAL_MODEL_SIZE;
> +
> +	av1_dec->tile_info.cpu = dma_alloc_coherent(vpu->dev, AV1_TILE_INFO_SIZE,
> +						    &av1_dec->tile_info.dma,
> +						    GFP_KERNEL);
> +	if (!av1_dec->tile_info.cpu)
> +		return -ENOMEM;
> +	av1_dec->tile_info.size = AV1_TILE_INFO_SIZE;
> +
> +	av1_dec->film_grain.cpu = dma_alloc_coherent(vpu->dev,
> +						     ALIGN(sizeof(struct hantro_av1_film_grain),
> +							   2048),
> +						     &av1_dec->film_grain.dma,
> +						     GFP_KERNEL);
> +	if (!av1_dec->film_grain.cpu)
> +		return -ENOMEM;
> +	av1_dec->film_grain.size = ALIGN(sizeof(struct hantro_av1_film_grain), 2048);
> +
> +	av1_dec->prob_tbl.cpu = dma_alloc_coherent(vpu->dev,
> +						   ALIGN(sizeof(struct av1cdfs), 2048),
> +						   &av1_dec->prob_tbl.dma,
> +						   GFP_KERNEL);
> +	if (!av1_dec->prob_tbl.cpu)
> +		return -ENOMEM;
> +	av1_dec->prob_tbl.size = ALIGN(sizeof(struct av1cdfs), 2048);
> +
> +	av1_dec->prob_tbl_out.cpu = dma_alloc_coherent(vpu->dev,
> +						       ALIGN(sizeof(struct av1cdfs), 2048),
> +						       &av1_dec->prob_tbl_out.dma,
> +						       GFP_KERNEL);
> +	if (!av1_dec->prob_tbl_out.cpu)
> +		return -ENOMEM;
> +	av1_dec->prob_tbl_out.size = ALIGN(sizeof(struct av1cdfs), 2048);
> +	av1_dec->cdfs = &av1_dec->default_cdfs;
> +	av1_dec->cdfs_ndvc = &av1_dec->default_cdfs_ndvc;
> +
> +	hantro_av1_set_default_cdfs(av1_dec->cdfs, av1_dec->cdfs_ndvc);
> +
> +	av1_dec->tile_buf.cpu = dma_alloc_coherent(vpu->dev,
> +						   AV1_TILE_SIZE,
> +						   &av1_dec->tile_buf.dma,
> +						   GFP_KERNEL);
> +	if (!av1_dec->tile_buf.cpu)
> +		return -ENOMEM;
> +	av1_dec->tile_buf.size = AV1_TILE_SIZE;
> +
> +	return 0;
> +}
> +
> +int hantro_av1_prepare_run(struct hantro_ctx *ctx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +
> +	ctrls->sequence = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_SEQUENCE);
> +	if (WARN_ON(!ctrls->sequence))
> +		return -EINVAL;
> +
> +	ctrls->tile_group_entry =
> +	    hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_TILE_GROUP_ENTRY);
> +	if (WARN_ON(!ctrls->tile_group_entry))
> +		return -EINVAL;
> +
> +	ctrls->frame = hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FRAME);
> +	if (WARN_ON(!ctrls->frame))
> +		return -EINVAL;
> +
> +	ctrls->film_grain =
> +	    hantro_get_ctrl(ctx, V4L2_CID_STATELESS_AV1_FILM_GRAIN);
> +
> +	return hantro_av1_tiles_reallocate(ctx);
> +}
> +
> +static int hantro_av1_get_msb(u32 n)
> +{
> +	if (n == 0)
> +		return 0;
> +	return 31 ^ __builtin_clz(n);
> +}
> +
> +static short hantro_av1_resolve_divisor_32(u32 d, short *shift)
> +{
> +	int f;
> +	u64 e;
> +
> +	*shift = hantro_av1_get_msb(d);
> +	/* e is obtained from D after resetting the most significant 1 bit. */
> +	e = d - ((u32)1 << *shift);
> +	/* Get the most significant DIV_LUT_BITS (8) bits of e into f */
> +	if (*shift > DIV_LUT_BITS)
> +		f = AV1_DIV_ROUND_UP_POW2(e, *shift - DIV_LUT_BITS);
> +	else
> +		f = e << (DIV_LUT_BITS - *shift);
> +	if (f > DIV_LUT_NUM)
> +		return -1;
> +	*shift += DIV_LUT_PREC_BITS;
> +	/* Use f as lookup into the precomputed table of multipliers */
> +	return div_lut[f];
> +}
> +
> +static void hantro_av1_get_shear_params(const u32 *params, s64 *alpha,
> +					s64 *beta, s64 *gamma, s64 *delta)
> +{
> +	const int *mat = params;
> +	short shift;
> +	short y;
> +	long long gv, dv;
> +
> +	if (mat[2] <= 0)
> +		return;
> +
> +	*alpha = clamp_val(mat[2] - (1 << WARPEDMODEL_PREC_BITS), S16_MIN, S16_MAX);
> +	*beta = clamp_val(mat[3], S16_MIN, S16_MAX);
> +
> +	y = hantro_av1_resolve_divisor_32(abs(mat[2]), &shift) * (mat[2] < 0 ? -1 : 1);
> +
> +	gv = ((long long)mat[4] * (1 << WARPEDMODEL_PREC_BITS)) * y;
> +
> +	*gamma = clamp_val((int)AV1_DIV_ROUND_UP_POW2_SIGNED(gv, shift), S16_MIN, S16_MAX);
> +
> +	dv = ((long long)mat[3] * mat[4]) * y;
> +	*delta = clamp_val(mat[5] -
> +		(int)AV1_DIV_ROUND_UP_POW2_SIGNED(dv, shift) - (1 << WARPEDMODEL_PREC_BITS),
> +		S16_MIN, S16_MAX);
> +
> +	*alpha = AV1_DIV_ROUND_UP_POW2_SIGNED(*alpha, WARP_PARAM_REDUCE_BITS)
> +		 * (1 << WARP_PARAM_REDUCE_BITS);
> +	*beta = AV1_DIV_ROUND_UP_POW2_SIGNED(*beta, WARP_PARAM_REDUCE_BITS)
> +		* (1 << WARP_PARAM_REDUCE_BITS);
> +	*gamma = AV1_DIV_ROUND_UP_POW2_SIGNED(*gamma, WARP_PARAM_REDUCE_BITS)
> +		 * (1 << WARP_PARAM_REDUCE_BITS);
> +	*delta = AV1_DIV_ROUND_UP_POW2_SIGNED(*delta, WARP_PARAM_REDUCE_BITS)
> +		* (1 << WARP_PARAM_REDUCE_BITS);
> +}
> +
> +void hantro_av1_set_global_model(struct hantro_ctx *ctx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
> +	const struct v4l2_av1_global_motion *gm = &frame->global_motion;
> +	u8 *dst = av1_dec->global_model.cpu;
> +	int ref_frame, i;
> +
> +	memset(dst, 0, GLOBAL_MODEL_SIZE);
> +	for (ref_frame = 0; ref_frame < V4L2_AV1_REFS_PER_FRAME; ++ref_frame) {
> +		s64 alpha = 0, beta = 0, gamma = 0, delta = 0;
> +
> +		for (i = 0; i < 6; ++i) {
> +			if (i == 2)
> +				*(s32 *)dst =
> +					gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][3];
> +			else if (i == 3)
> +				*(s32 *)dst =
> +					gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][2];
> +			else
> +				*(s32 *)dst =
> +					gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][i];
> +			dst += 4;
> +		}
> +
> +		if (gm->type[V4L2_AV1_REF_LAST_FRAME + ref_frame] <= V4L2_AV1_WARP_MODEL_AFFINE)
> +			hantro_av1_get_shear_params(&gm->params[V4L2_AV1_REF_LAST_FRAME + ref_frame][0],
> +						    &alpha, &beta, &gamma, &delta);
> +
> +		*(s16 *)dst = alpha;
> +		dst += 2;
> +		*(s16 *)dst = beta;
> +		dst += 2;
> +		*(s16 *)dst = gamma;
> +		dst += 2;
> +		*(s16 *)dst = delta;
> +		dst += 2;
> +	}
> +}
> +
> +int hantro_av1_tile_log2(int target)
> +{
> +	int k;
> +
> +	/*
> +	 * returns the smallest value for k such that 1 << k is greater
> +	 * than or equal to target
> +	 */
> +	for (k = 0; (1 << k) < target; k++)
> +		;
> +
> +	return k;
> +}
> +
> +int hantro_av1_get_dist(struct hantro_ctx *ctx, int a, int b)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	int bits = ctrls->sequence->order_hint_bits - 1;
> +	int diff, m;
> +
> +	if (!ctrls->sequence->order_hint_bits)
> +		return 0;
> +
> +	diff = a - b;
> +	m = 1 << bits;
> +	diff = (diff & (m - 1)) - (diff & m);
> +
> +	return diff;
> +}
> +
> +void hantro_av1_set_frame_sign_bias(struct hantro_ctx *ctx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
> +	const struct v4l2_ctrl_av1_sequence *sequence = ctrls->sequence;
> +	int i;
> +
> +	if (!sequence->order_hint_bits || IS_INTRA(frame->frame_type)) {
> +		for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME; i++)
> +			av1_dec->ref_frame_sign_bias[i] = 0;
> +
> +		return;
> +	}
> +	// Identify the nearest forward and backward references.
> +	for (i = 0; i < V4L2_AV1_TOTAL_REFS_PER_FRAME - 1; i++) {
> +		if (hantro_av1_get_frame_index(ctx, i) >= 0) {
> +			int rel_off =
> +			    hantro_av1_get_dist(ctx,
> +						hantro_av1_get_order_hint(ctx, i),
> +						frame->order_hint);
> +			av1_dec->ref_frame_sign_bias[i + 1] = (rel_off <= 0) ? 0 : 1;
> +		}
> +	}
> +}
> +
> +void hantro_av1_init_scaling_function(const u8 *values, const u8 *scaling,
> +				      u8 num_points, u8 *scaling_lut)
> +{
> +	int i, point;
> +
> +	if (num_points == 0) {
> +		memset(scaling_lut, 0, 256);
> +		return;
> +	}
> +
> +	for (point = 0; point < num_points - 1; point++) {
> +		int x;
> +		s32 delta_y = scaling[point + 1] - scaling[point];
> +		s32 delta_x = values[point + 1] - values[point];
> +		s64 delta =
> +		    delta_x ? delta_y * ((65536 + (delta_x >> 1)) /
> +					 delta_x) : 0;
> +
> +		for (x = 0; x < delta_x; x++) {
> +			scaling_lut[values[point] + x] =
> +			    scaling[point] +
> +			    (s32)((x * delta + 32768) >> 16);
> +		}
> +	}
> +
> +	for (i = values[num_points - 1]; i < 256; i++)
> +		scaling_lut[i] = scaling[num_points - 1];
> +}
> +
> +void hantro_av1_set_tile_info(struct hantro_ctx *ctx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_av1_tile_info *tile_info = &ctrls->frame->tile_info;
> +	const struct v4l2_ctrl_av1_tile_group_entry *group_entry =
> +	    ctrls->tile_group_entry;
> +	u8 *dst = av1_dec->tile_info.cpu;
> +	int tile0, tile1;
> +
> +	memset(dst, 0, av1_dec->tile_info.size);
> +
> +	for (tile0 = 0; tile0 < tile_info->tile_cols; tile0++) {
> +		for (tile1 = 0; tile1 < tile_info->tile_rows; tile1++) {
> +			int tile_id = tile1 * tile_info->tile_cols + tile0;
> +			u32 start, end;
> +			u32 y0 =
> +			    tile_info->height_in_sbs_minus_1[tile1] + 1;
> +			u32 x0 = tile_info->width_in_sbs_minus_1[tile0] + 1;
> +
> +			/* tile size in SB units (width,height) */
> +			*dst++ = x0;
> +			*dst++ = 0;
> +			*dst++ = 0;
> +			*dst++ = 0;
> +			*dst++ = y0;
> +			*dst++ = 0;
> +			*dst++ = 0;
> +			*dst++ = 0;
> +
> +			/* tile start position */
> +			start = group_entry[tile_id].tile_offset - group_entry[0].tile_offset;
> +			*dst++ = start & 255;
> +			*dst++ = (start >> 8) & 255;
> +			*dst++ = (start >> 16) & 255;
> +			*dst++ = (start >> 24) & 255;
> +
> +			/* number of bytes in tile data */
> +			end = start + group_entry[tile_id].tile_size;
> +			*dst++ = end & 255;
> +			*dst++ = (end >> 8) & 255;
> +			*dst++ = (end >> 16) & 255;
> +			*dst++ = (end >> 24) & 255;
> +		}
> +	}
> +}
> +
> +bool hantro_av1_is_lossless(struct hantro_ctx *ctx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
> +	const struct v4l2_av1_segmentation *segmentation = &frame->segmentation;
> +	const struct v4l2_av1_quantization *quantization = &frame->quantization;
> +	int i;
> +
> +	for (i = 0; i < V4L2_AV1_MAX_SEGMENTS; i++) {
> +		int qindex = quantization->base_q_idx;
> +
> +		if (segmentation->feature_enabled[i] &
> +		    V4L2_AV1_SEGMENT_FEATURE_ENABLED(V4L2_AV1_SEG_LVL_ALT_Q)) {
> +			qindex += segmentation->feature_data[i][V4L2_AV1_SEG_LVL_ALT_Q];
> +		}
> +		qindex = clamp(qindex, 0, 255);
> +
> +		if (qindex ||
> +		    quantization->delta_q_y_dc ||
> +		    quantization->delta_q_u_dc ||
> +		    quantization->delta_q_u_ac ||
> +		    quantization->delta_q_v_dc ||
> +		    quantization->delta_q_v_ac)
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +void hantro_av1_update_prob(struct hantro_ctx *ctx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
> +	bool frame_is_intra = IS_INTRA(frame->frame_type);
> +	struct av1cdfs *out_cdfs = (struct av1cdfs *)av1_dec->prob_tbl_out.cpu;
> +	int i;
> +
> +	if (frame->flags & V4L2_AV1_FRAME_FLAG_DISABLE_FRAME_END_UPDATE_CDF)
> +		return;
> +
> +	for (i = 0; i < NUM_REF_FRAMES; i++) {
> +		if (frame->refresh_frame_flags & BIT(i)) {
> +			struct mvcdfs stored_mv_cdf;
> +
> +			hantro_av1_get_cdfs(ctx, i);
> +			stored_mv_cdf = av1_dec->cdfs->mv_cdf;
> +			*av1_dec->cdfs = *out_cdfs;
> +			if (frame_is_intra) {
> +				av1_dec->cdfs->mv_cdf = stored_mv_cdf;
> +				*av1_dec->cdfs_ndvc = out_cdfs->mv_cdf;
> +			}
> +			hantro_av1_store_cdfs(ctx, frame->refresh_frame_flags);
> +			break;
> +		}
> +	}
> +}
> +
> +void hantro_av1_set_prob(struct hantro_ctx *ctx)
> +{
> +	struct hantro_av1_dec_hw_ctx *av1_dec = &ctx->av1_dec;
> +	struct hantro_av1_dec_ctrls *ctrls = &av1_dec->ctrls;
> +	const struct v4l2_ctrl_av1_frame *frame = ctrls->frame;
> +	const struct v4l2_av1_quantization *quantization = &frame->quantization;
> +	bool error_resilient_mode =
> +	    !!(frame->flags & V4L2_AV1_FRAME_FLAG_ERROR_RESILIENT_MODE);
> +	bool frame_is_intra = IS_INTRA(frame->frame_type);
> +
> +	if (error_resilient_mode || frame_is_intra ||
> +	    frame->primary_ref_frame == AV1_PRIMARY_REF_NONE) {
> +		av1_dec->cdfs = &av1_dec->default_cdfs;
> +		av1_dec->cdfs_ndvc = &av1_dec->default_cdfs_ndvc;
> +		hantro_av1_default_coeff_probs(quantization->base_q_idx,
> +					       av1_dec->cdfs);
> +	} else {
> +		hantro_av1_get_cdfs(ctx, frame->ref_frame_idx[frame->primary_ref_frame]);

There is no sanity check for frame->primary_ref_frame to prevent out of bounds
array access. But perhaps this has to be checked elsewhere?

> +	}
> +	hantro_av1_store_cdfs(ctx, frame->refresh_frame_flags);
> +
> +	memcpy(av1_dec->prob_tbl.cpu, av1_dec->cdfs, sizeof(struct av1cdfs));
> +
> +	if (frame_is_intra) {
> +		int mv_offset = offsetof(struct av1cdfs, mv_cdf);
> +		/* Overwrite MV context area with intrabc MV context */
> +		memcpy(av1_dec->prob_tbl.cpu + mv_offset, av1_dec->cdfs_ndvc,
> +		       sizeof(struct mvcdfs));
> +	}
> +}

<snip>

> diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> index e4e21ad37323..5bf1f2689fbc 100644
> --- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
> @@ -7,622 +7,35 @@
<snip>

>  static void rockchip_vpu981_av1_dec_set_cdef(struct hantro_ctx *ctx)
> @@ -1617,12 +846,12 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  	int ref_ind = 0;
>  	int rf, idx;
>  
> -	alt_frame_offset = rockchip_vpu981_get_order_hint(ctx, ALT_BUF_IDX);
> -	gld_frame_offset = rockchip_vpu981_get_order_hint(ctx, GLD_BUF_IDX);
> -	bwd_frame_offset = rockchip_vpu981_get_order_hint(ctx, BWD_BUF_IDX);
> -	alt2_frame_offset = rockchip_vpu981_get_order_hint(ctx, ALT2_BUF_IDX);
> +	alt_frame_offset = hantro_av1_get_order_hint(ctx, ALT_BUF_IDX);
> +	gld_frame_offset = hantro_av1_get_order_hint(ctx, GLD_BUF_IDX);
> +	bwd_frame_offset = hantro_av1_get_order_hint(ctx, BWD_BUF_IDX);
> +	alt2_frame_offset = hantro_av1_get_order_hint(ctx, ALT2_BUF_IDX);
>  
> -	idx = rockchip_vpu981_get_frame_index(ctx, LST_BUF_IDX);
> +	idx = hantro_av1_get_frame_index(ctx, LST_BUF_IDX);
>  	if (idx >= 0) {
>  		int alt_frame_offset_in_lst =
>  			av1_dec->frame_refs[idx].order_hints[V4L2_AV1_REF_ALTREF_FRAME];
> @@ -1644,8 +873,8 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  		ref_stamp--;
>  	}
>  
> -	idx = rockchip_vpu981_get_frame_index(ctx, BWD_BUF_IDX);
> -	if (rockchip_vpu981_av1_dec_get_dist(ctx, bwd_frame_offset, cur_frame_offset) > 0) {
> +	idx = hantro_av1_get_frame_index(ctx, BWD_BUF_IDX);

Can idx be AV1_INVALID_IDX? It's checked for LST_BUF_IDX, but not for BWD_BUF_IDX and others below.

> +	if (hantro_av1_get_dist(ctx, bwd_frame_offset, cur_frame_offset) > 0) {
>  		int bwd_mi_cols = av1_dec->frame_refs[idx].mi_cols;
>  		int bwd_mi_rows = av1_dec->frame_refs[idx].mi_rows;
>  		bool bwd_intra_only =
> @@ -1659,8 +888,8 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  		}
>  	}
>  
> -	idx = rockchip_vpu981_get_frame_index(ctx, ALT2_BUF_IDX);
> -	if (rockchip_vpu981_av1_dec_get_dist(ctx, alt2_frame_offset, cur_frame_offset) > 0) {
> +	idx = hantro_av1_get_frame_index(ctx, ALT2_BUF_IDX);
> +	if (hantro_av1_get_dist(ctx, alt2_frame_offset, cur_frame_offset) > 0) {
>  		int alt2_mi_cols = av1_dec->frame_refs[idx].mi_cols;
>  		int alt2_mi_rows = av1_dec->frame_refs[idx].mi_rows;
>  		bool alt2_intra_only =
> @@ -1674,8 +903,8 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  		}
>  	}
>  
> -	idx = rockchip_vpu981_get_frame_index(ctx, ALT_BUF_IDX);
> -	if (rockchip_vpu981_av1_dec_get_dist(ctx, alt_frame_offset, cur_frame_offset) > 0 &&
> +	idx = hantro_av1_get_frame_index(ctx, ALT_BUF_IDX);
> +	if (hantro_av1_get_dist(ctx, alt_frame_offset, cur_frame_offset) > 0 &&
>  	    ref_stamp >= 0) {
>  		int alt_mi_cols = av1_dec->frame_refs[idx].mi_cols;
>  		int alt_mi_rows = av1_dec->frame_refs[idx].mi_rows;
> @@ -1690,7 +919,7 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  		}
>  	}
>  
> -	idx = rockchip_vpu981_get_frame_index(ctx, LST2_BUF_IDX);
> +	idx = hantro_av1_get_frame_index(ctx, LST2_BUF_IDX);
>  	if (idx >= 0 && ref_stamp >= 0) {
>  		int lst2_mi_cols = av1_dec->frame_refs[idx].mi_cols;
>  		int lst2_mi_rows = av1_dec->frame_refs[idx].mi_rows;
> @@ -1706,14 +935,14 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  	}
>  
>  	for (rf = 0; rf < V4L2_AV1_TOTAL_REFS_PER_FRAME - 1; ++rf) {
> -		idx = rockchip_vpu981_get_frame_index(ctx, rf);
> +		idx = hantro_av1_get_frame_index(ctx, rf);
>  		if (idx >= 0) {
> -			int rf_order_hint = rockchip_vpu981_get_order_hint(ctx, rf);
> +			int rf_order_hint = hantro_av1_get_order_hint(ctx, rf);
>  
>  			cur_offset[rf] =
> -			    rockchip_vpu981_av1_dec_get_dist(ctx, cur_frame_offset, rf_order_hint);
> +			    hantro_av1_get_dist(ctx, cur_frame_offset, rf_order_hint);
>  			cur_roffset[rf] =
> -			    rockchip_vpu981_av1_dec_get_dist(ctx, rf_order_hint, cur_frame_offset);
> +			    hantro_av1_get_dist(ctx, rf_order_hint, cur_frame_offset);
>  		} else {
>  			cur_offset[rf] = 0;
>  			cur_roffset[rf] = 0;
> @@ -1736,32 +965,32 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  	if (use_ref_frame_mvs && ref_ind > 0 &&
>  	    cur_offset[mf_types[0] - V4L2_AV1_REF_LAST_FRAME] <= MAX_FRAME_DISTANCE &&
>  	    cur_offset[mf_types[0] - V4L2_AV1_REF_LAST_FRAME] >= -MAX_FRAME_DISTANCE) {
> -		int rf = rockchip_vpu981_get_order_hint(ctx, refs_selected[0]);
> -		int idx = rockchip_vpu981_get_frame_index(ctx, refs_selected[0]);
> +		int rf = hantro_av1_get_order_hint(ctx, refs_selected[0]);
> +		int idx = hantro_av1_get_frame_index(ctx, refs_selected[0]);

There is no AV1_INVALID_IDX check here either.

I think it might be helpful if there is a comment in the cases where idx is always
valid. I don't know enough about this to be able to tell if it is a potential
out-of-bounds access or not.

>  		u32 *oh = av1_dec->frame_refs[idx].order_hints;
>  		int val;
>  
>  		hantro_reg_write(vpu, &av1_use_temporal0_mvs, 1);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf1_last_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf1_last2_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf1_last3_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf1_golden_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf1_bwdref_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf1_altref2_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf1_altref_offset, val);
>  	}
>  
> @@ -1776,32 +1005,32 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  	if (use_ref_frame_mvs && ref_ind > 1 &&
>  	    cur_offset[mf_types[1] - V4L2_AV1_REF_LAST_FRAME] <= MAX_FRAME_DISTANCE &&
>  	    cur_offset[mf_types[1] - V4L2_AV1_REF_LAST_FRAME] >= -MAX_FRAME_DISTANCE) {
> -		int rf = rockchip_vpu981_get_order_hint(ctx, refs_selected[1]);
> -		int idx = rockchip_vpu981_get_frame_index(ctx, refs_selected[1]);
> +		int rf = hantro_av1_get_order_hint(ctx, refs_selected[1]);
> +		int idx = hantro_av1_get_frame_index(ctx, refs_selected[1]);

Ditto.

>  		u32 *oh = av1_dec->frame_refs[idx].order_hints;
>  		int val;
>  
>  		hantro_reg_write(vpu, &av1_use_temporal1_mvs, 1);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf2_last_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf2_last2_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf2_last3_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf2_golden_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf2_bwdref_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf2_altref2_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf2_altref_offset, val);
>  	}
>  
> @@ -1816,32 +1045,32 @@ static void rockchip_vpu981_av1_dec_set_other_frames(struct hantro_ctx *ctx)
>  	if (use_ref_frame_mvs && ref_ind > 2 &&
>  	    cur_offset[mf_types[2] - V4L2_AV1_REF_LAST_FRAME] <= MAX_FRAME_DISTANCE &&
>  	    cur_offset[mf_types[2] - V4L2_AV1_REF_LAST_FRAME] >= -MAX_FRAME_DISTANCE) {
> -		int rf = rockchip_vpu981_get_order_hint(ctx, refs_selected[2]);
> -		int idx = rockchip_vpu981_get_frame_index(ctx, refs_selected[2]);
> +		int rf = hantro_av1_get_order_hint(ctx, refs_selected[2]);
> +		int idx = hantro_av1_get_frame_index(ctx, refs_selected[2]);

Ditto.

>  		u32 *oh = av1_dec->frame_refs[idx].order_hints;
>  		int val;
>  
>  		hantro_reg_write(vpu, &av1_use_temporal2_mvs, 1);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf3_last_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST2_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf3_last2_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_LAST3_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf3_last3_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_GOLDEN_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf3_golden_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_BWDREF_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf3_bwdref_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF2_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf3_altref2_offset, val);
>  
> -		val = rockchip_vpu981_av1_dec_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
> +		val = hantro_av1_get_dist(ctx, rf, oh[V4L2_AV1_REF_ALTREF_FRAME]);
>  		hantro_reg_write(vpu, &av1_mf3_altref_offset, val);
>  	}
>  
> @@ -1883,7 +1112,7 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
>  
>  	if (!allow_intrabc) {
>  		for (i = 0; i < V4L2_AV1_REFS_PER_FRAME; i++) {
> -			int idx = rockchip_vpu981_get_frame_index(ctx, i);
> +			int idx = hantro_av1_get_frame_index(ctx, i);
>  
>  			if (idx >= 0)
>  				ref_count[idx]++;
> @@ -1898,7 +1127,7 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
>  	}
>  	hantro_reg_write(vpu, &av1_ref_frames, ref_frames);
>  
> -	rockchip_vpu981_av1_dec_set_frame_sign_bias(ctx);
> +	hantro_av1_set_frame_sign_bias(ctx);
>  
>  	for (i = V4L2_AV1_REF_LAST_FRAME; i < V4L2_AV1_TOTAL_REFS_PER_FRAME; i++) {
>  		u32 ref = i - 1;
> @@ -1910,8 +1139,8 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
>  			width = frame->frame_width_minus_1 + 1;
>  			height = frame->frame_height_minus_1 + 1;
>  		} else {
> -			if (rockchip_vpu981_get_frame_index(ctx, ref) > 0)
> -				idx = rockchip_vpu981_get_frame_index(ctx, ref);
> +			if (hantro_av1_get_frame_index(ctx, ref) > 0)
> +				idx = hantro_av1_get_frame_index(ctx, ref);

Can idx be AV1_INVALID_IDX here?

>  			width = av1_dec->frame_refs[idx].width;
>  			height = av1_dec->frame_refs[idx].height;
>  		}
> @@ -1943,20 +1172,6 @@ static void rockchip_vpu981_av1_dec_set_reference_frames(struct hantro_ctx *ctx)
>  	rockchip_vpu981_av1_dec_set_other_frames(ctx);
>  }
>  
> -static int rockchip_vpu981_av1_get_hardware_tx_mode(enum v4l2_av1_tx_mode tx_mode)
> -{
> -	switch (tx_mode) {
> -	case V4L2_AV1_TX_MODE_ONLY_4X4:
> -		return ROCKCHIP_AV1_TX_MODE_ONLY_4X4;
> -	case V4L2_AV1_TX_MODE_LARGEST:
> -		return ROCKCHIP_AV1_TX_MODE_32x32;
> -	case V4L2_AV1_TX_MODE_SELECT:
> -		return ROCKCHIP_AV1_TX_MODE_SELECT;
> -	}
> -
> -	return ROCKCHIP_AV1_TX_MODE_32x32;
> -}
> -
>  static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
>  {
>  	struct hantro_dev *vpu = ctx->dev;
> @@ -2029,7 +1244,7 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
>  	hantro_reg_write(vpu, &av1_comp_pred_mode,
>  			 (ctrls->frame->flags & V4L2_AV1_FRAME_FLAG_REFERENCE_SELECT) ? 2 : 0);
>  
> -	tx_mode = rockchip_vpu981_av1_get_hardware_tx_mode(ctrls->frame->tx_mode);
> +	tx_mode = hantro_av1_get_hardware_tx_mode(ctrls->frame->tx_mode);
>  	hantro_reg_write(vpu, &av1_transform_mode, tx_mode);
>  	hantro_reg_write(vpu, &av1_max_cb_size,
>  			 (ctrls->sequence->flags
> @@ -2061,7 +1276,7 @@ static void rockchip_vpu981_av1_dec_set_parameters(struct hantro_ctx *ctx)
>  		hantro_reg_write(vpu, &av1_qmlevel_v, 0xff);
>  	}
>  
> -	hantro_reg_write(vpu, &av1_lossless_e, rockchip_vpu981_av1_dec_is_lossless(ctx));
> +	hantro_reg_write(vpu, &av1_lossless_e, hantro_av1_is_lossless(ctx));
>  	hantro_reg_write(vpu, &av1_quant_delta_v_dc, ctrls->frame->quantization.delta_q_v_dc);
>  	hantro_reg_write(vpu, &av1_quant_delta_v_ac, ctrls->frame->quantization.delta_q_v_ac);
>  
> @@ -2109,8 +1324,8 @@ rockchip_vpu981_av1_dec_set_output_buffer(struct hantro_ctx *ctx)
>  	struct hantro_decoded_buffer *dst;
>  	struct vb2_v4l2_buffer *vb2_dst;
>  	dma_addr_t luma_addr, chroma_addr, mv_addr = 0;
> -	size_t cr_offset = rockchip_vpu981_av1_dec_luma_size(ctx);
> -	size_t mv_offset = rockchip_vpu981_av1_dec_chroma_size(ctx);
> +	size_t cr_offset = hantro_av1_luma_size(ctx);
> +	size_t mv_offset = hantro_av1_chroma_size(ctx);
>  
>  	vb2_dst = av1_dec->frame_refs[av1_dec->current_frame_index].vb2_ref;
>  	dst = vb2_to_hantro_decoded_buf(&vb2_dst->vb2_buf);
> @@ -2134,7 +1349,7 @@ int rockchip_vpu981_av1_dec_run(struct hantro_ctx *ctx)
>  
>  	hantro_start_prepare_run(ctx);
>  
> -	ret = rockchip_vpu981_av1_dec_prepare_run(ctx);
> +	ret = hantro_av1_prepare_run(ctx);
>  	if (ret)
>  		goto prepare_error;
>  
> @@ -2144,8 +1359,8 @@ int rockchip_vpu981_av1_dec_run(struct hantro_ctx *ctx)
>  		goto prepare_error;
>  	}
>  
> -	rockchip_vpu981_av1_dec_clean_refs(ctx);
> -	rockchip_vpu981_av1_dec_frame_ref(ctx, vb2_src->vb2_buf.timestamp);
> +	hantro_av1_clean_refs(ctx);
> +	hantro_av1_frame_ref(ctx, vb2_src->vb2_buf.timestamp);
>  
>  	rockchip_vpu981_av1_dec_set_parameters(ctx);
>  	rockchip_vpu981_av1_dec_set_global_model(ctx);
Regards,

	Hans


^ permalink raw reply

* [PATCH v4 2/3] dt-bindings: gpio: Add EIO GPIO compatible to gpio-zynq
From: Shubhrajyoti Datta @ 2026-05-12  6:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: git, shubhrajyoti.datta, Shubhrajyoti Datta, Srinivas Neeli,
	Michal Simek, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-gpio, devicetree,
	linux-arm-kernel
In-Reply-To: <20260512060917.2096456-1-shubhrajyoti.datta@amd.com>

EIO (Extended IO) GPIO is a Xilinx IP block that exposes
multiplexed I/O pins through an EIO interface.

The EIO GPIO block has 2 banks with 26 GPIOs each (52 total).
The GPIO width cannot be determined from the hardware registers,
the driver relies on the compatible string to select the correct
bank/pin configuration. A new compatible is therefore required.

The block is currently present on xa2ve3288 silicon.
The compatible string uses version 1.0 matching the IP core version.

Acked-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

Changes in v4:
- Remove the min 52 for eio

Changes in v3:
- Update the commit message

Changes in v2:
- Add description of EIO block

 .../devicetree/bindings/gpio/gpio-zynq.yaml         | 13 ++++++++++++-
 1 file changed, 12 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml b/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
index 30a7f836c341..de24bb361e9f 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
+++ b/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
@@ -12,6 +12,7 @@ maintainers:
 properties:
   compatible:
     enum:
+      - xlnx,eio-gpio-1.0
       - xlnx,pmc-gpio-1.0
       - xlnx,versal-gpio-1.0
       - xlnx,zynq-gpio-1.0
@@ -30,7 +31,7 @@ properties:
 
   gpio-line-names:
     description: strings describing the names of each gpio line
-    minItems: 58
+    minItems: 52
     maxItems: 174
 
   interrupt-controller: true
@@ -89,6 +90,16 @@ allOf:
           minItems: 116
           maxItems: 116
 
+  - if:
+      properties:
+        compatible:
+          enum:
+            - xlnx,eio-gpio-1.0
+    then:
+      properties:
+        gpio-line-names:
+          maxItems: 52
+
 required:
   - compatible
   - reg
-- 
2.34.1



^ permalink raw reply related

* [PATCH v4 3/3] gpio: zynq: Add eio gpio support
From: Shubhrajyoti Datta @ 2026-05-12  6:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: git, shubhrajyoti.datta, Shubhrajyoti Datta, Srinivas Neeli,
	Michal Simek, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-gpio, devicetree,
	linux-arm-kernel
In-Reply-To: <20260512060917.2096456-1-shubhrajyoti.datta@amd.com>

Add support for the EIO GPIO controller found on
xa2ve3288 silicon.

The EIO GPIO block provides access to multiplexed I/O pins exposed
through the EIO interface. Only bank 0 and bank 1 are connected to
external MIO pins, with 26 GPIOs per bank (52 GPIOs total). This
change extends the Zynq GPIO driver to support the EIO GPIO
variant.

Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

(no changes since v1)

 drivers/gpio/gpio-zynq.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 571e366624d2..8118ae3412c2 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -25,6 +25,7 @@
 #define VERSAL_GPIO_MAX_BANK	4
 #define PMC_GPIO_MAX_BANK	5
 #define VERSAL_UNUSED_BANKS	2
+#define EIO_GPIO_MAX_BANK	2
 
 #define ZYNQ_GPIO_BANK0_NGPIO	32
 #define ZYNQ_GPIO_BANK1_NGPIO	22
@@ -818,6 +819,16 @@ static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
 	RUNTIME_PM_OPS(zynq_gpio_runtime_suspend, zynq_gpio_runtime_resume, NULL)
 };
 
+static const struct zynq_platform_data eio_gpio_def = {
+	.label = "eio_gpio",
+	.ngpio = 52,
+	.max_bank = EIO_GPIO_MAX_BANK,
+	.bank_min[0] = 0,
+	.bank_max[0] = 25, /* 0 to 25 are connected to MIOs (26 pins) */
+	.bank_min[1] = 26,
+	.bank_max[1] = 51, /* Bank 1 are connected to MIOs (26 pins) */
+};
+
 static const struct zynq_platform_data versal_gpio_def = {
 	.label = "versal_gpio",
 	.quirks = GPIO_QUIRK_VERSAL,
@@ -882,6 +893,7 @@ static const struct of_device_id zynq_gpio_of_match[] = {
 	{ .compatible = "xlnx,zynqmp-gpio-1.0", .data = &zynqmp_gpio_def },
 	{ .compatible = "xlnx,versal-gpio-1.0", .data = &versal_gpio_def },
 	{ .compatible = "xlnx,pmc-gpio-1.0", .data = &pmc_gpio_def },
+	{ .compatible = "xlnx,eio-gpio-1.0", .data = &eio_gpio_def },
 	{ /* end of table */ }
 };
 MODULE_DEVICE_TABLE(of, zynq_gpio_of_match);
-- 
2.34.1



^ permalink raw reply related

* [PATCH v4 0/3] gpio: Add EIO GPIO support
From: Shubhrajyoti Datta @ 2026-05-12  6:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: git, shubhrajyoti.datta, Shubhrajyoti Datta, Srinivas Neeli,
	Michal Simek, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-gpio, devicetree,
	linux-arm-kernel

Add the EIO GPIO support.
Add the dt description and the compatible to the driver.

Changes in v4:
- Add Conor ack
- Remove the min 52 for eio

Changes in v3:
- Update the commit message

Changes in v2:
- Add new patch to sort the compatible strings alphabetically
- Add description of EIO block

Shubhrajyoti Datta (3):
  dt-bindings: gpio: zynq: Sort compatible strings alphabetically
  dt-bindings: gpio: Add EIO GPIO compatible to gpio-zynq
  gpio: zynq: Add eio gpio support

 .../devicetree/bindings/gpio/gpio-zynq.yaml     | 17 ++++++++++++++---
 drivers/gpio/gpio-zynq.c                        | 12 ++++++++++++
 2 files changed, 26 insertions(+), 3 deletions(-)

-- 
2.34.1



^ permalink raw reply

* [PATCH v4 1/3] dt-bindings: gpio: zynq: Sort compatible strings alphabetically
From: Shubhrajyoti Datta @ 2026-05-12  6:08 UTC (permalink / raw)
  To: linux-kernel
  Cc: git, shubhrajyoti.datta, Shubhrajyoti Datta, Srinivas Neeli,
	Michal Simek, Linus Walleij, Bartosz Golaszewski, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, linux-gpio, devicetree,
	linux-arm-kernel
In-Reply-To: <20260512060917.2096456-1-shubhrajyoti.datta@amd.com>

Sort the compatible string alphabetically.

Acked-by: Conor Dooley <conor.dooley@microchip.com>
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@amd.com>
---

Changes in v4:
- Add Conor ack

Changes in v2:
- Add new patch to sort the compatible strings alphabetically

 Documentation/devicetree/bindings/gpio/gpio-zynq.yaml | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml b/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
index 5e2496379a3c..30a7f836c341 100644
--- a/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
+++ b/Documentation/devicetree/bindings/gpio/gpio-zynq.yaml
@@ -12,10 +12,10 @@ maintainers:
 properties:
   compatible:
     enum:
+      - xlnx,pmc-gpio-1.0
+      - xlnx,versal-gpio-1.0
       - xlnx,zynq-gpio-1.0
       - xlnx,zynqmp-gpio-1.0
-      - xlnx,versal-gpio-1.0
-      - xlnx,pmc-gpio-1.0
 
   reg:
     maxItems: 1
-- 
2.34.1



^ permalink raw reply related

* [PATCH net-next 2/2] net: ti: icssg: Add HSR and LRE PA statistics
From: MD Danish Anwar @ 2026-05-12  6:06 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Shuah Khan, MD Danish Anwar,
	Roger Quadros, Andrew Lunn, Jacob Keller, Meghana Malladi,
	David Carlier, Kevin Hao, Vadim Fedorenko
  Cc: netdev, linux-doc, linux-kernel, linux-arm-kernel,
	Vignesh Raghavendra
In-Reply-To: <20260512060627.3781329-1-danishanwar@ti.com>

Add new firmware PA statistics counters for HSR and LRE to the ethtool
statistics exposed by the ICSSG driver.

New statistics added:
 - FW_HSR_FWD_CHECK_FAIL_DROP: Packets dropped on the HSR forwarding path
 - FW_HSR_HE_CHECK_FAIL_DROP: Packets dropped on the HSR host egress path
 - FW_HSR_SKIP_HOST_DUP_DISCARD_FRAMES: Frames with duplicate discard
   skipped
 - FW_LRE_CNT_UNIQUE/DUPLICATE/MULTIPLE_RX: LRE duplicate detetcion
   counters
 - FW_LRE_CNT_RX/TX: LRE per-port frame counters
 - FW_LRE_CNT_OWN_RX: Own HSR tagged frames received
 - FW_LRE_CNT_ERRWRONGLAN: Frames with wrong LAN identifier (PRP)

Document the new HSR/LRE statistics in icssg_prueth.rst.

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 .../device_drivers/ethernet/ti/icssg_prueth.rst        | 10 ++++++++++
 drivers/net/ethernet/ti/icssg/icssg_common.c           |  7 +++++--
 drivers/net/ethernet/ti/icssg/icssg_stats.h            | 10 ++++++++++
 drivers/net/ethernet/ti/icssg/icssg_switch_map.h       | 10 ++++++++++
 4 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/Documentation/networking/device_drivers/ethernet/ti/icssg_prueth.rst b/Documentation/networking/device_drivers/ethernet/ti/icssg_prueth.rst
index da21ddf431bb..b0bda7327b2a 100644
--- a/Documentation/networking/device_drivers/ethernet/ti/icssg_prueth.rst
+++ b/Documentation/networking/device_drivers/ethernet/ti/icssg_prueth.rst
@@ -54,3 +54,13 @@ These statistics are as follows,
  - ``FW_HOST_TX_PKT_CNT``: Number of valid packets copied by RTU0 to Tx queues
  - ``FW_HOST_EGRESS_Q_PRE_OVERFLOW``: Host Egress Q (Pre-emptible) Overflow Counter
  - ``FW_HOST_EGRESS_Q_EXP_OVERFLOW``: Host Egress Q (Pre-emptible) Overflow Counter
+ - ``FW_HSR_FWD_CHECK_FAIL_DROP``: Packets dropped on the HSR forwarding path due to failed checks
+ - ``FW_HSR_HE_CHECK_FAIL_DROP``: Packets dropped on the host egress path due to failed checks
+ - ``FW_HSR_SKIP_HOST_DUP_DISCARD_FRAMES``: Frames for which the host duplicate discard check was skipped
+ - ``FW_LRE_CNT_UNIQUE_RX``: Number of frames received with no duplicate detected
+ - ``FW_LRE_CNT_DUPLICATE_RX``: Number of frames received for which exactly one duplicate was detected
+ - ``FW_LRE_CNT_MULTIPLE_RX``: Number of frames received for which more than one duplicate was detected
+ - ``FW_LRE_CNT_RX``: Number of HSR/PRP tagged frames received
+ - ``FW_LRE_CNT_TX``: Number of HSR/PRP tagged frames sent
+ - ``FW_LRE_CNT_OWN_RX``: Number of HSR/PRP tagged frames received whose source MAC matches the node's own address
+ - ``FW_LRE_CNT_ERRWRONGLAN``: Number of frames received with a wrong LAN identifier, PRP only
diff --git a/drivers/net/ethernet/ti/icssg/icssg_common.c b/drivers/net/ethernet/ti/icssg/icssg_common.c
index a28a608f9bf4..e7a51a9eee24 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -1633,7 +1633,8 @@ void icssg_ndo_get_stats64(struct net_device *ndev,
 			    emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") +
 			    emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") +
 			    emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") +
-			    emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN");
+			    emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN") +
+			    emac_get_stat_by_name(emac, "FW_LRE_CNT_ERRWRONGLAN");
 	stats->rx_dropped = ndev->stats.rx_dropped +
 			    emac_get_stat_by_name(emac, "FW_DROPPED_PKT") +
 			    emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") +
@@ -1643,7 +1644,9 @@ void icssg_ndo_get_stats64(struct net_device *ndev,
 			    emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") +
 			    emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") +
 			    emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER");
+			    emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER") +
+			    emac_get_stat_by_name(emac, "FW_HSR_FWD_CHECK_FAIL_DROP") +
+			    emac_get_stat_by_name(emac, "FW_HSR_HE_CHECK_FAIL_DROP");
 	stats->tx_errors  = ndev->stats.tx_errors;
 	stats->tx_dropped = ndev->stats.tx_dropped +
 			    emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") +
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
index b854eb587c1e..af3fcecac403 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
@@ -204,6 +204,16 @@ static const struct icssg_pa_stats icssg_all_pa_stats[] = {
 	ICSSG_PA_STATS(FW_HOST_TX_PKT_CNT),
 	ICSSG_PA_STATS(FW_HOST_EGRESS_Q_PRE_OVERFLOW),
 	ICSSG_PA_STATS(FW_HOST_EGRESS_Q_EXP_OVERFLOW),
+	ICSSG_PA_STATS(FW_HSR_FWD_CHECK_FAIL_DROP),
+	ICSSG_PA_STATS(FW_HSR_HE_CHECK_FAIL_DROP),
+	ICSSG_PA_STATS(FW_HSR_SKIP_HOST_DUP_DISCARD_FRAMES),
+	ICSSG_PA_STATS(FW_LRE_CNT_UNIQUE_RX),
+	ICSSG_PA_STATS(FW_LRE_CNT_DUPLICATE_RX),
+	ICSSG_PA_STATS(FW_LRE_CNT_MULTIPLE_RX),
+	ICSSG_PA_STATS(FW_LRE_CNT_RX),
+	ICSSG_PA_STATS(FW_LRE_CNT_TX),
+	ICSSG_PA_STATS(FW_LRE_CNT_OWN_RX),
+	ICSSG_PA_STATS(FW_LRE_CNT_ERRWRONGLAN),
 };
 
 #endif /* __NET_TI_ICSSG_STATS_H */
diff --git a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
index 7e053b8af3ec..bd2d54dd7f45 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_switch_map.h
@@ -266,5 +266,15 @@
 #define FW_HOST_TX_PKT_CNT		0x0250
 #define FW_HOST_EGRESS_Q_PRE_OVERFLOW	0x0258
 #define FW_HOST_EGRESS_Q_EXP_OVERFLOW	0x0260
+#define FW_HSR_FWD_CHECK_FAIL_DROP		0x0500
+#define FW_HSR_HE_CHECK_FAIL_DROP		0x0508
+#define FW_HSR_SKIP_HOST_DUP_DISCARD_FRAMES	0x0510
+#define FW_LRE_CNT_UNIQUE_RX			0x0518
+#define FW_LRE_CNT_DUPLICATE_RX			0x0520
+#define FW_LRE_CNT_MULTIPLE_RX			0x0528
+#define FW_LRE_CNT_RX				0x0530
+#define FW_LRE_CNT_TX				0x0538
+#define FW_LRE_CNT_OWN_RX			0x0540
+#define FW_LRE_CNT_ERRWRONGLAN			0x0548
 
 #endif /* __NET_TI_ICSSG_SWITCH_MAP_H  */
-- 
2.34.1



^ permalink raw reply related

* [PATCH net-next 1/2] net: ti: icssg: Derive stats array lengths from ARRAY_SIZE
From: MD Danish Anwar @ 2026-05-12  6:06 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Shuah Khan, MD Danish Anwar,
	Roger Quadros, Andrew Lunn, Jacob Keller, Meghana Malladi,
	David Carlier, Kevin Hao, Vadim Fedorenko
  Cc: netdev, linux-doc, linux-kernel, linux-arm-kernel,
	Vignesh Raghavendra
In-Reply-To: <20260512060627.3781329-1-danishanwar@ti.com>

Replace the manually maintained ICSSG_NUM_MIIG_STATS and
ICSSG_NUM_PA_STATS constants with ARRAY_SIZE() expressions derived
directly from the corresponding stat descriptor arrays, so that adding
new entries to icssg_all_miig_stats[] or icssg_all_pa_stats[] no longer
requires a separate update to a numeric constant.

To make this self-contained, break the circular include dependency
between icssg_stats.h and icssg_prueth.h:

  - icssg_stats.h previously included icssg_prueth.h (transitively
    pulling in icssg_switch_map.h and ETH_GSTRING_LEN).  Replace that
    with direct includes of <linux/ethtool.h>, <linux/kernel.h> and
    "icssg_switch_map.h".

  - icssg_prueth.h now includes icssg_stats.h, giving it access to
    the ARRAY_SIZE-based ICSSG_NUM_MIIG_STATS and ICSSG_NUM_PA_STATS
    before they are used in the prueth_emac struct and ICSSG_NUM_STATS.

Signed-off-by: MD Danish Anwar <danishanwar@ti.com>
---
 drivers/net/ethernet/ti/icssg/icssg_prueth.h | 3 +--
 drivers/net/ethernet/ti/icssg/icssg_stats.h  | 7 ++++++-
 2 files changed, 7 insertions(+), 3 deletions(-)

diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
index df93d15c5b78..e2ccecb0a0dd 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h
@@ -43,6 +43,7 @@
 
 #include "icssg_config.h"
 #include "icss_iep.h"
+#include "icssg_stats.h"
 #include "icssg_switch_map.h"
 
 #define PRUETH_MAX_MTU          (2000 - ETH_HLEN - ETH_FCS_LEN)
@@ -57,8 +58,6 @@
 
 #define ICSSG_MAX_RFLOWS	8	/* per slice */
 
-#define ICSSG_NUM_PA_STATS	32
-#define ICSSG_NUM_MIIG_STATS	60
 /* Number of ICSSG related stats */
 #define ICSSG_NUM_STATS (ICSSG_NUM_MIIG_STATS + ICSSG_NUM_PA_STATS)
 #define ICSSG_NUM_STANDARD_STATS 31
diff --git a/drivers/net/ethernet/ti/icssg/icssg_stats.h b/drivers/net/ethernet/ti/icssg/icssg_stats.h
index 5ec0b38e0c67..b854eb587c1e 100644
--- a/drivers/net/ethernet/ti/icssg/icssg_stats.h
+++ b/drivers/net/ethernet/ti/icssg/icssg_stats.h
@@ -8,10 +8,15 @@
 #ifndef __NET_TI_ICSSG_STATS_H
 #define __NET_TI_ICSSG_STATS_H
 
-#include "icssg_prueth.h"
+#include <linux/ethtool.h>
+#include <linux/kernel.h>
+#include "icssg_switch_map.h"
 
 #define STATS_TIME_LIMIT_1G_MS    25000    /* 25 seconds @ 1G */
 
+#define ICSSG_NUM_MIIG_STATS	ARRAY_SIZE(icssg_all_miig_stats)
+#define ICSSG_NUM_PA_STATS	ARRAY_SIZE(icssg_all_pa_stats)
+
 struct miig_stats_regs {
 	/* Rx */
 	u32 rx_packets;
-- 
2.34.1



^ permalink raw reply related


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