* Re: [PATCH v3] dt-bindings: iio: adc: Convert xilinx-xadc bindings to YAML schema
From: Jonathan Cameron @ 2026-05-11 16:15 UTC (permalink / raw)
To: Pramod Maurya
Cc: David Lechner, Nuno Sá, Andy Shevchenko, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Michal Simek,
Lars-Peter Clausen, linux-iio, devicetree, linux-arm-kernel,
linux-kernel
In-Reply-To: <20260510120141.118057-1-pramod.nexgen@gmail.com>
On Sun, 10 May 2026 08:01:36 -0400
Pramod Maurya <pramod.nexgen@gmail.com> wrote:
> Convert the Xilinx XADC and UltraScale System Monitor device tree binding
> from the legacy plain-text format to a YAML schema, enabling automated
> validation with dt-schema.
>
> The new binding covers the same hardware and compatible strings:
> - xlnx,zynq-xadc-1.00.a (ZYNQ hardmacro)
> - xlnx,axi-xadc-1.00.a (AXI softmacro)
> - xlnx,system-management-wiz-1.3 (UltraScale System Management Wizard)
>
> Signed-off-by: Pramod Maurya <pramod.nexgen@gmail.com>
Hi Pramod,
Something went wrong with your sending of v3. I have two versions sent
half a day apart and no idea how they are related.
Anyhow one of them got feedback from Rob's bot so I'll assume we are
getting a v4 and wait for that.
Jonathan
^ permalink raw reply
* Re: [PATCH 2/3] [v5 net-next] p54spi: convert to devicetree
From: Simon Horman @ 2026-05-11 16:12 UTC (permalink / raw)
To: arnd
Cc: 'Simon Horman', netdev, arnd, aaro.koskinen, andreas,
brgl, bcousson, davem, dmitry.torokhov, edumazet, balbi, kuba,
johannes, khilman, krzk+dt, linusw, pabeni, robh+dt, rogerq, tony,
linux-wireless, devicetree, linux-kernel, linux-arm-kernel,
linux-gpio, linux-omap, krzk
In-Reply-To: <20260507212451.3333185-3-arnd@kernel.org>
From: 'Simon Horman' <horms@kernel.org>
This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
p54spi: convert to devicetree
This commit converts the Prism54 SPI driver from using hardcoded GPIO
module parameters to using the GPIO descriptor interface and device tree
probing.
> diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c
> index 9d66dcae54e02..d18be25450285 100644
> --- a/drivers/net/wireless/intersil/p54/p54spi.c
> +++ b/drivers/net/wireless/intersil/p54/p54spi.c
[ ... ]
> @@ -30,19 +31,6 @@
> MODULE_FIRMWARE("3826.arm");
> MODULE_FIRMWARE("3826.eeprom");
>
> -/* gpios should be handled in board files and provided via platform data,
> - * but because it's currently impossible for p54spi to have a header file
> - * in include/linux, let's use module parameters for now
> - */
> -
> -static int p54spi_gpio_power = 97;
> -module_param(p54spi_gpio_power, int, 0444);
> -MODULE_PARM_DESC(p54spi_gpio_power, "gpio number for power line");
> -
> -static int p54spi_gpio_irq = 87;
> -module_param(p54spi_gpio_irq, int, 0444);
> -MODULE_PARM_DESC(p54spi_gpio_irq, "gpio number for irq line");
> -
> static void p54spi_spi_read(struct p54s_priv *priv, u8 address,
> void *buf, size_t len)
> {
Simon says: As a pre-existing issue I don't think we need to be concerned
about this in the scope of this patch-set. But it may
be a potential for follow-up.
This problem wasn't introduced by this patch, but I noticed a pre-existing
issue in the context here. Does the p54spi_spi_read() function perform an SPI
transfer using a stack-allocated buffer?
Looking at p54spi_spi_read(), the addr variable is allocated on the stack and
passed as a transfer buffer to spi_sync(). The SPI framework maps transfer
buffers for DMA. Passing a stack-allocated buffer is illegal, particularly with
CONFIG_VMAP_STACK enabled, because stack memory resides in vmalloc space and
cannot be safely DMA-mapped.
Could this cause memory corruption or a kernel panic during the transfer?
[ ... ]
> @@ -608,31 +596,20 @@ static int p54spi_probe(struct spi_device *spi)
> goto err_free;
> }
>
> - ret = gpio_request(p54spi_gpio_power, "p54spi power");
> - if (ret < 0) {
> - dev_err(&priv->spi->dev, "power GPIO request failed: %d", ret);
> + priv->gpio_powerdown = gpiod_get_optional(&spi->dev, "powerdown", GPIOD_OUT_HIGH);
> + if (IS_ERR(priv->gpio_powerdown)) {
> + ret = dev_err_probe(&priv->spi->dev, PTR_ERR(priv->gpio_powerdown),
> + "powerdown GPIO request failed\n");
> goto err_free;
> }
>
> - ret = gpio_request(p54spi_gpio_irq, "p54spi irq");
> - if (ret < 0) {
> - dev_err(&priv->spi->dev, "irq GPIO request failed: %d", ret);
> - goto err_free_gpio_power;
> - }
> -
> - gpio_direction_output(p54spi_gpio_power, 0);
> - gpio_direction_input(p54spi_gpio_irq);
> -
> - ret = request_irq(gpio_to_irq(p54spi_gpio_irq),
> - p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi",
> - priv->spi);
> + ret = request_irq(spi->irq, p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi", priv->spi);
Simon says: This one seems more concerning in the context of this patch-set.
Is there missing validation for spi->irq before calling request_irq()?
If the device tree node lacks an interrupts property, the SPI core may set
spi->irq to 0 or a negative error code.
Passing this directly to request_irq() without validation can successfully
hijack a core system interrupt like the system timer on some architectures,
leading to system instability or deadlocks.
Should there be a check like if (spi->irq <= 0) to fail the probe gracefully?
> if (ret < 0) {
> dev_err(&priv->spi->dev, "request_irq() failed");
> - goto err_free_gpio_irq;
> + goto err_free_gpio_power;
> }
^ permalink raw reply
* Re: [PATCH 1/2] [RFC] debugobjects: avoid gcc-16.0.1 section mismatch
From: Thomas Gleixner @ 2026-05-11 16:10 UTC (permalink / raw)
To: Arnd Bergmann, Arnd Bergmann, Will Deacon, Robin Murphy,
Joerg Roedel, Andrew Morton
Cc: linux-arm-kernel, iommu, linux-kernel, Sebastian Andrzej Siewior
In-Reply-To: <34af0db2-7a04-4119-925f-3aa3e3ecb683@app.fastmail.com>
On Mon, May 11 2026 at 11:46, Arnd Bergmann wrote:
> On Mon, May 11, 2026, at 09:18, Thomas Gleixner wrote:
>> I agree that the compiler does not know what __init means, but this
>> sucks as it leaves an unused copy of lookup_object_or_alloc() around
>> after init.
>>
>> What happens if you mark is_static_object() with 'noinline'?
>
> I've reproduced the issue with the release gcc-16.1.0 build,
> and tested marking is_static_object (along with
> dummy_tlb_add_page and dummy_tlb_flush from the other
> instance) as noinline.
>
> As expected, this avoids the problem as well.
I rather prefer that along with a comment explaining the 'noinline' oddity.
^ permalink raw reply
* [PATCH 3/3] usb: dwc3: xilinx: fix error handling in zynqmp init error paths
From: Radhey Shyam Pandey @ 2026-05-11 16:08 UTC (permalink / raw)
To: Thinh.Nguyen, gregkh, michal.simek, p.zabel
Cc: linux-usb, linux-arm-kernel, linux-kernel, git,
Radhey Shyam Pandey, stable
In-Reply-To: <20260511160814.2904882-1-radhey.shyam.pandey@amd.com>
Fix error handling and resource cleanup i.e remove invalid
phy_exit() after failed phy_init(), route failures through
proper cleanup paths and return 0 explicitly on success.
Fixes: 84770f028fab ("usb: dwc3: Add driver for Xilinx platforms")
Cc: stable@vger.kernel.org
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
---
drivers/usb/dwc3/dwc3-xilinx.c | 27 +++++++++++++++------------
1 file changed, 15 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index 94458b3da1a0..b832505e1b04 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -176,15 +176,13 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
}
ret = phy_init(priv_data->usb3_phy);
- if (ret < 0) {
- phy_exit(priv_data->usb3_phy);
+ if (ret < 0)
goto err;
- }
ret = reset_control_deassert(apbrst);
if (ret < 0) {
dev_err(dev, "Failed to release APB reset\n");
- goto err;
+ goto err_phy_exit;
}
if (priv_data->usb3_phy) {
@@ -200,26 +198,24 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
ret = reset_control_deassert(crst);
if (ret < 0) {
dev_err(dev, "Failed to release core reset\n");
- goto err;
+ goto err_phy_exit;
}
ret = reset_control_deassert(hibrst);
if (ret < 0) {
dev_err(dev, "Failed to release hibernation reset\n");
- goto err;
+ goto err_phy_exit;
}
ret = phy_power_on(priv_data->usb3_phy);
- if (ret < 0) {
- phy_exit(priv_data->usb3_phy);
- goto err;
- }
+ if (ret < 0)
+ goto err_phy_exit;
/* ulpi reset via gpio-modepin or gpio-framework driver */
reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(reset_gpio)) {
- return dev_err_probe(dev, PTR_ERR(reset_gpio),
- "Failed to request reset GPIO\n");
+ ret = PTR_ERR(reset_gpio);
+ goto err_phy_power_off;
}
if (reset_gpio) {
@@ -229,6 +225,13 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
}
dwc3_xlnx_set_coherency(priv_data, XLNX_USB_TRAFFIC_ROUTE_CONFIG);
+
+ return 0;
+
+err_phy_power_off:
+ phy_power_off(priv_data->usb3_phy);
+err_phy_exit:
+ phy_exit(priv_data->usb3_phy);
err:
return ret;
}
--
2.44.4
^ permalink raw reply related
* [PATCH 2/3] usb: dwc3: xilinx: use reset_control_reset() in versal init
From: Radhey Shyam Pandey @ 2026-05-11 16:08 UTC (permalink / raw)
To: Thinh.Nguyen, gregkh, michal.simek, p.zabel
Cc: linux-usb, linux-arm-kernel, linux-kernel, git,
Radhey Shyam Pandey
In-Reply-To: <20260511160814.2904882-1-radhey.shyam.pandey@amd.com>
Replace separate reset_control_assert() and reset_control_deassert() calls
with reset_control_reset(), which pulses the reset in one step. Report
failures with dev_err_probe() and a single message. No functional change.
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
---
drivers/usb/dwc3/dwc3-xilinx.c | 16 ++++------------
1 file changed, 4 insertions(+), 12 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index a3c7dc258c7d..94458b3da1a0 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -98,18 +98,10 @@ static int dwc3_xlnx_init_versal(struct dwc3_xlnx *priv_data)
dwc3_xlnx_mask_phy_rst(priv_data, false);
- /* Assert and De-assert reset */
- ret = reset_control_assert(crst);
- if (ret < 0) {
- dev_err_probe(dev, ret, "failed to assert Reset\n");
- return ret;
- }
-
- ret = reset_control_deassert(crst);
- if (ret < 0) {
- dev_err_probe(dev, ret, "failed to De-assert Reset\n");
- return ret;
- }
+ /* assert and deassert reset */
+ ret = reset_control_reset(crst);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to assert and deassert reset\n");
dwc3_xlnx_mask_phy_rst(priv_data, true);
dwc3_xlnx_set_coherency(priv_data, XLNX_USB2_TRAFFIC_ROUTE_CONFIG);
--
2.44.4
^ permalink raw reply related
* [PATCH 0/3] usb: dwc3: xilinx: minor fixes for dwc3-xilinx glue driver
From: Radhey Shyam Pandey @ 2026-05-11 16:08 UTC (permalink / raw)
To: Thinh.Nguyen, gregkh, michal.simek, p.zabel
Cc: linux-usb, linux-arm-kernel, linux-kernel, git,
Radhey Shyam Pandey
Minor cleanups and a bug fix for the dwc3-xilinx glue driver:
- Fix a comment style violation (missing space before closing delimiter).
- Use reset_control_reset in versal init.
- Fix phy resource leak in zynqmp init error paths where phy_init() and
phy_power_on() resources were not properly released on failure.
Radhey Shyam Pandey (3):
usb: dwc3: xilinx: fix missing space before closing comment delimiter
usb: dwc3: xilinx: use reset_control_reset() in versal init
usb: dwc3: xilinx: fix error handling in zynqmp init error paths
drivers/usb/dwc3/dwc3-xilinx.c | 45 +++++++++++++++-------------------
1 file changed, 20 insertions(+), 25 deletions(-)
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
--
2.44.4
^ permalink raw reply
* [PATCH 1/3] usb: dwc3: xilinx: fix missing space before closing comment delimiter
From: Radhey Shyam Pandey @ 2026-05-11 16:08 UTC (permalink / raw)
To: Thinh.Nguyen, gregkh, michal.simek, p.zabel
Cc: linux-usb, linux-arm-kernel, linux-kernel, git,
Radhey Shyam Pandey
In-Reply-To: <20260511160814.2904882-1-radhey.shyam.pandey@amd.com>
Add missing space before '*/' in an inline comment to follow
the kernel coding style.
Signed-off-by: Radhey Shyam Pandey <radhey.shyam.pandey@amd.com>
---
drivers/usb/dwc3/dwc3-xilinx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/usb/dwc3/dwc3-xilinx.c b/drivers/usb/dwc3/dwc3-xilinx.c
index f41b0da5e89d..a3c7dc258c7d 100644
--- a/drivers/usb/dwc3/dwc3-xilinx.c
+++ b/drivers/usb/dwc3/dwc3-xilinx.c
@@ -196,7 +196,7 @@ static int dwc3_xlnx_init_zynqmp(struct dwc3_xlnx *priv_data)
}
if (priv_data->usb3_phy) {
- /* Set PIPE Power Present signal in FPD Power Present Register*/
+ /* Set PIPE Power Present signal in FPD Power Present Register */
writel(FPD_POWER_PRSNT_OPTION, priv_data->regs + XLNX_USB_FPD_POWER_PRSNT);
/* Set the PIPE Clock Select bit in FPD PIPE Clock register */
writel(PIPE_CLK_SELECT, priv_data->regs + XLNX_USB_FPD_PIPE_CLK);
--
2.44.4
^ permalink raw reply related
* Re: [PATCH v2 2/3] dt-bindings: arm: sunxi: Add Baijie HelperBoard A133 compatible
From: Conor Dooley @ 2026-05-11 16:08 UTC (permalink / raw)
To: Alexander Sverdlin
Cc: linux-sunxi, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Andre Przywara,
devicetree, linux-arm-kernel, linux-kernel
In-Reply-To: <20260510201644.4143710-3-alexander.sverdlin@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1471 bytes --]
On Sun, May 10, 2026 at 10:16:39PM +0200, Alexander Sverdlin wrote:
> Baijie HelperBoard A133 is a development board around their A133 Core
> board. Introduce a compatible for both the Core and the development
> boards.
>
> Signed-off-by: Alexander Sverdlin <alexander.sverdlin@gmail.com>
> ---
>
> Changelog:
> v2:
> - introduced baijie,helper-a133-core compatible for the Core (SoM) board
>
> Documentation/devicetree/bindings/arm/sunxi.yaml | 11 +++++++++++
> 1 file changed, 11 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
> index e6443c266fa1..d7b9dec81165 100644
> --- a/Documentation/devicetree/bindings/arm/sunxi.yaml
> +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
> @@ -96,6 +96,17 @@ properties:
> - const: allwinner,ba10-tvbox
> - const: allwinner,sun4i-a10
>
> + - description: Baijie Helper A133
> + items:
> + - const: baijie,helper-a133
> + - const: baijie,helper-a133-core
> + - const: allwinner,sun50i-a100
> +
> + - description: HelperBoardA133 Core
> + items:
> + - const: baijie,helper-a133-core
> + - const: allwinner,sun50i-a100
Does this make sense? Can the core board be used without a carrier?
> +
> - description: BananaPi
> items:
> - const: lemaker,bananapi
> --
> 2.54.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH RFC v2 1/4] dt-bindings: clk: zte: Add zx297520v3 clock and reset bindings.
From: Conor Dooley @ 2026-05-11 16:07 UTC (permalink / raw)
To: Stefan Dösinger
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Philipp Zabel, linux-clk, devicetree, linux-kernel,
linux-arm-kernel
In-Reply-To: <20260511-zx29clk-v2-1-29f0edc300f5@gmail.com>
[-- Attachment #1: Type: text/plain, Size: 16624 bytes --]
On Mon, May 11, 2026 at 12:49:50AM +0300, Stefan Dösinger wrote:
> These SoCs have 3 clock and reset controllers. The "top" controller -
> all names follow ZTE's naming - controls core devices like the AHB bus,
> most timers and the Cortex M0 that brings up the board. The register
> layout is fairly chaotic. Some patterns can be found, but nothing that
> holds true for all devices it controls.
>
> Generally every device has two clocks (one work clock, and one that
> connects it to the bus, I call it PCLK), two reset bits (I don't know
> what the difference is - sometimes asserting one is enough to reset the
> device, sometimes both need to be asserted) and one mux. Some devices,
> like the GPIO controller, only have reset bits and no clocks.
>
> The top clock controller is fed by a 26mhz external oscillator and has 4
> PLLs to generate other clock rates. ZTE's kernel does not manipulate the
> PLLs at all and relies on BROM and the boot loader to set them up. The
> bitfields in the control registers are somewhat documented in a
> Lauterback TRACE32 debug file in the kernel sources though. At the
> moment, my driver extracts clock rates from the PLLs, but cannot change
> them. A proper PLL clk is on my TODO list before I remove the [RFC] tag
> from the submission. It will be necessary for the LTE hardware with
> replacement boot loaders because BROM does not set up the LTE-related
> PLL.
>
> The "matrix" controller controls the main Cortex A53 CPU, the LTE ZSP,
> SDIO and a few others. It is even more chaotic than the "top"
> controller.
>
> The "LSP" controller - I suspect it stands for "low speed peripherals" -
> is very regular. One 32 bit register for 2 clock gates, two resets, one
> mux (1-3 bit) and in some cases a 4 bit divider.
>
> Not all clocks will have an explicit user in the end. I am defining a
> lot of them simply to shut them off. The boot loader sets up a few of
> the proprietary timers, which will send regular IRQs (although the
> kernel of course doesn't need to listen to them). I don't plan to add a
> driver for the proprietary timer as I see no use for them - the ARM arch
> timer works just fine. I will add a driver for the very similar
> proprietary watchdog though.
>
> The top and matrix list is not exhaustive. There are other bits
> that are enabled, but I couldn't deduce what they are controlling by
> trial and error. Some of them seem to do nothing. Others cause an
> instant hang of the board when disabled. I isolated a few (SRAM PCLK,
> arm arch timer clock) where I don't see a reason to manipulate them. It
> is quite likely that a handful more clocks will be added in the future,
> but not a large number.
>
> Signed-off-by: Stefan Dösinger <stefandoesinger@gmail.com>
> ---
> .../bindings/clock/zte,zx297520v3-clk.yaml | 173 ++++++++++++++++++++
> include/dt-bindings/clock/zte,zx297520v3-clk.h | 179 +++++++++++++++++++++
> 2 files changed, 352 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/clock/zte,zx297520v3-clk.yaml b/Documentation/devicetree/bindings/clock/zte,zx297520v3-clk.yaml
> new file mode 100644
> index 000000000000..3b7084a18a97
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/clock/zte,zx297520v3-clk.yaml
> @@ -0,0 +1,173 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/clock/zte,zx297520v3-clk.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: ZTE zx297520v3 SoC clock and reset controller
> +
> +maintainers:
> + - Stefan Dösinger <stefandoesinger@gmail.com>
> +
> +description: |
> + The zx297520v3's clock controller consists of 3 controllers, which generate
> + clocks for internal SoC devices. In addition to clocks it also has reset
> + controls for most, but not all, devices.
> +
> + While there is a certain hierarchy among the controllers ("top" controlls core
> + parts like the boot-up Cortex M0, "matrix" controls the main CPU and LTE DSP,
> + "lsp" controls peripherals"), in practise all 3 are required to reasonably
> + operate the SoC.
> +
> + The top controller has two inputs: a 26 MHz and a 32 KHz external oscillator.
> + They need to be provided as input clocks. The matrix controller controlls 10
> + clock lines that get fed into the LSP controller. The LSP device node needs
> + to list these input clocks.
> +
> + The matrix controller consumes clocks generated by PLLs in the top
> + controller, but there are no controls in the top controller to sever this
> + link. The interface between these controllers is not expressed in the device
> + tree, but the matrix controller cannot work without the clock handles
> + registered by the top controller.
> +
> + All available clocks are defined as preprocessor macros in
> + 'dt-bindings/clock/zte,zx297520v3-clk.h' header.
> +
> +properties:
> + compatible:
> + enum:
> + - zte,zx297520v3-topclk
> + - zte,zx297520v3-matrixclk
How come the "matrixclk" has no constraints on clock properties?
> + - zte,zx297520v3-lspclk
> +
> + clocks:
> + minItems: 2
> + maxItems: 10
> +
> + clock-names:
> + minItems: 2
> + maxItems: 10
> +
> + "#clock-cells":
> + const: 1
> +
> + "#reset-cells":
> + const: 1
> +
> + reg:
> + maxItems: 1
> +
> +allOf:
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: zte,zx297520v3-topclk
> + then:
> + properties:
> + clocks:
> + items:
> + - description: External reference clock (26 MHz)
> + - description: External reference clock (32 KHz)
> + clock-names:
> + items:
> + - const: osc26m
> + - const: osc32k
> + required:
> + - clocks
> + - clock-names
> +
> + - if:
> + properties:
> + compatible:
> + contains:
> + const: zte,zx297520v3-lspclk
Although, these two devices seem too different to be in the same
dt-binding. Do they have anyhting in common other than the SoC they are
part of?
Cheers,
Conor.
> + then:
> + properties:
> + clocks:
> + items:
> + - description: Main PLL divided by 5 output from matrixclk (124.8 MHz)
> + - description: Main PLL divided by 4 output from matrixclk (156 MHz)
> + - description: Main PLL divided by 6 output from matrixclk (104 MHz)
> + - description: Main PLL divided by 8 output from matrixclk (78 MHz)
> + - description: Main PLL divided by 12 output from matrixclk (52 MHz)
> + - description: Main oscillator output from matrixclk (26 MHz)
> + - description: Timer oscillator output from matrixclk (32 KHz)
> + - description: LSP pclk output from matrixclk (26 MHz)
> + - description: TDM wclk mux output from matrixclk
> + - description: DPLL divided by 4 output from matrixclk (122.88 MHz)
> + clock-names:
> + items:
> + - const: mpll_d5
> + - const: mpll_d4
> + - const: mpll_d6
> + - const: mpll_d8
> + - const: mpll_d12
> + - const: osc26m
> + - const: osc32k
> + - const: pclk
> + - const: tdm_wclk
> + - const: dpll_d4
> + required:
> + - clocks
> + - clock-names
> +
> +additionalProperties: false
> +
> +required:
> + - compatible
> + - '#clock-cells'
> + - reg
> + - '#reset-cells'
> +
> +examples:
> + - |
> + #include <dt-bindings/clock/zte,zx297520v3-clk.h>
> +
> + osc26m: osc26m {
> + compatible = "fixed-clock";
> + clock-output-names = "osc26m";
> + #clock-cells = <0>;
> + };
> +
> + osc32k: osc32k {
> + compatible = "fixed-clock";
> + clock-output-names = "osc32k";
> + #clock-cells = <0>;
> + };
> +
> + topclk: topclk@13b000 {
> + compatible = "zte,zx297520v3-topclk";
> + reg = <0x0013b000 0x400>;
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> + clocks = <&osc26m>, <&osc32k>;
> + clock-names = "osc26m", "osc32k";
> + };
> +
> + matrixclk: matrixclk@1306000 {
> + compatible = "zte,zx297520v3-matrixclk";
> + reg = <0x01306000 0x400>;
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> + };
> +
> + lspclk: lspclk@1400000 {
> + compatible = "zte,zx297520v3-lspclk";
> + reg = <0x01400000 0x100>;
> + #clock-cells = <1>;
> + #reset-cells = <1>;
> +
> + clocks = <&matrixclk ZX297520V3_LSP_MPLL_D5_WCLK>,
> + <&matrixclk ZX297520V3_LSP_MPLL_D4_WCLK>,
> + <&matrixclk ZX297520V3_LSP_MPLL_D6_WCLK>,
> + <&matrixclk ZX297520V3_LSP_MPLL_D8_WCLK>,
> + <&matrixclk ZX297520V3_LSP_MPLL_D12_WCLK>,
> + <&matrixclk ZX297520V3_LSP_OSC26M_WCLK>,
> + <&matrixclk ZX297520V3_LSP_OSC32K_WCLK>,
> + <&matrixclk ZX297520V3_LSP_PCLK>,
> + <&matrixclk ZX297520V3_LSP_TDM_WCLK>,
> + <&matrixclk ZX297520V3_LSP_DPLL_D4_WCLK>;
> + clock-names = "mpll_d5", "mpll_d4", "mpll_d6", "mpll_d8", "mpll_d12",
> + "osc26m", "osc32k", "pclk", "tdm_wclk", "dpll_d4";
> + };
> diff --git a/include/dt-bindings/clock/zte,zx297520v3-clk.h b/include/dt-bindings/clock/zte,zx297520v3-clk.h
> new file mode 100644
> index 000000000000..322b53be8b12
> --- /dev/null
> +++ b/include/dt-bindings/clock/zte,zx297520v3-clk.h
> @@ -0,0 +1,179 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * Copyright (C) Stefan Dösinger.
> + */
> +
> +#ifndef __DT_BINDINGS_CLOCK_ZX297520V3_H
> +#define __DT_BINDINGS_CLOCK_ZX297520V3_H
> +
> +#define ZX297520V3_AHB_WCLK 0
> +#define ZX297520V3_AHB_PCLK 1
> +#define ZX297520V3_PMM_WCLK 2
> +#define ZX297520V3_PMM_PCLK 3
> +#define ZX297520V3_USB_24M 4
> +#define ZX297520V3_USB_AHB 5
> +#define ZX297520V3_TIMER_T08_WCLK 6
> +#define ZX297520V3_TIMER_T08_PCLK 7
> +#define ZX297520V3_TIMER_T09_WCLK 8
> +#define ZX297520V3_TIMER_T09_PCLK 9
> +#define ZX297520V3_TIMER_T12_WCLK 10
> +#define ZX297520V3_TIMER_T12_PCLK 11
> +#define ZX297520V3_TIMER_T13_WCLK 12
> +#define ZX297520V3_TIMER_T13_PCLK 13
> +#define ZX297520V3_TIMER_T14_WCLK 14
> +#define ZX297520V3_TIMER_T14_PCLK 15
> +#define ZX297520V3_TIMER_T15_WCLK 16
> +#define ZX297520V3_TIMER_T15_PCLK 17
> +#define ZX297520V3_TIMER_T16_WCLK 18
> +#define ZX297520V3_TIMER_T16_PCLK 19
> +#define ZX297520V3_TIMER_T17_WCLK 20
> +#define ZX297520V3_TIMER_T17_PCLK 21
> +#define ZX297520V3_WDT_T18_WCLK 22
> +#define ZX297520V3_WDT_T18_PCLK 23
> +#define ZX297520V3_UART0_WCLK 24
> +#define ZX297520V3_UART0_PCLK 25
> +#define ZX297520V3_I2C0_WCLK 26
> +#define ZX297520V3_I2C0_PCLK 27
> +#define ZX297520V3_RTC_WCLK 28
> +#define ZX297520V3_RTC_PCLK 29
> +#define ZX297520V3_LPM_GSM_WCLK 30
> +#define ZX297520V3_LPM_GSM_PCLK 31
> +#define ZX297520V3_LPM_LTE_WCLK 32
> +#define ZX297520V3_LPM_LTE_PCLK 33
> +#define ZX297520V3_LPM_TD_WCLK 34
> +#define ZX297520V3_LPM_TD_PCLK 35
> +#define ZX297520V3_LPM_W_WCLK 36
> +#define ZX297520V3_LPM_W_PCLK 37
> +#define ZX297520V3_USIM1_WCLK 38
> +#define ZX297520V3_USIM1_PCLK 39
> +#define ZX297520V3_M0_WCLK 40
> +#define ZX297520V3_TOPCLK_END 41
> +
> +#define ZX297520V3_AHB_RESET 0
> +#define ZX297520V3_TIMER_T08_RESET 1
> +#define ZX297520V3_TIMER_T09_RESET 2
> +#define ZX297520V3_TIMER_T12_RESET 3
> +#define ZX297520V3_TIMER_T13_RESET 4
> +#define ZX297520V3_TIMER_T14_RESET 5
> +#define ZX297520V3_TIMER_T15_RESET 6
> +#define ZX297520V3_TIMER_T16_RESET 7
> +#define ZX297520V3_TIMER_T17_RESET 8
> +#define ZX297520V3_WDT_T18_RESET 9
> +#define ZX297520V3_UART0_RESET 10
> +#define ZX297520V3_I2C0_RESET 11
> +#define ZX297520V3_RTC_RESET 12
> +#define ZX297520V3_USIM1_RESET 13
> +#define ZX297520V3_PMM_RESET 14
> +#define ZX297520V3_GPIO8_RESET 15
> +#define ZX297520V3_GPIO_RESET 16
> +#define ZX297520V3_ZSP_RESET 17
> +#define ZX297520V3_USB_RESET 18
> +#define ZX297520V3_TOPRST_END 19
> +
> +#define ZX297520V3_CPU_WCLK 0
> +#define ZX297520V3_CPU_PCLK 1
> +#define ZX297520V3_SD0_WCLK 2
> +#define ZX297520V3_SD0_PCLK 3
> +#define ZX297520V3_SD1_WCLK 4
> +#define ZX297520V3_SD1_PCLK 5
> +#define ZX297520V3_SD1_CDET 6
> +#define ZX297520V3_NAND_WCLK 7
> +#define ZX297520V3_NAND_PCLK 8
> +#define ZX297520V3_SSC_WCLK 9
> +#define ZX297520V3_SSC_PCLK 10
> +#define ZX297520V3_EDCP_WCLK 11
> +#define ZX297520V3_EDCP_PCLK 12
> +#define ZX297520V3_EDCP_SYNCAXI 13
> +#define ZX297520V3_VOU_WCLK 14
> +#define ZX297520V3_VOU_PCLK 15
> +#define ZX297520V3_PDCFG_WCLK 16
> +#define ZX297520V3_PDCFG_PCLK 17
> +#define ZX297520V3_GMAC_WCLK 18
> +#define ZX297520V3_GMAC_RMII 19
> +#define ZX297520V3_GMAC_PCLK 20
> +#define ZX297520V3_ZSP_WCLK 21
> +#define ZX297520V3_MBOX_PCLK 22
> +#define ZX297520V3_DMA_PCLK 23
> +#define ZX297520V3_LSP_MPLL_D5_WCLK 24
> +#define ZX297520V3_LSP_MPLL_D4_WCLK 25
> +#define ZX297520V3_LSP_MPLL_D6_WCLK 26
> +#define ZX297520V3_LSP_MPLL_D8_WCLK 27
> +#define ZX297520V3_LSP_MPLL_D12_WCLK 28
> +#define ZX297520V3_LSP_OSC26M_WCLK 29
> +#define ZX297520V3_LSP_OSC32K_WCLK 30
> +#define ZX297520V3_LSP_PCLK 31
> +#define ZX297520V3_LSP_TDM_WCLK 32
> +#define ZX297520V3_LSP_DPLL_D4_WCLK 33
> +#define ZX297520V3_MATRIXCLK_END 34
> +
> +#define ZX297520V3_CPU_RESET 0
> +#define ZX297520V3_SD0_RESET 1
> +#define ZX297520V3_SD1_RESET 2
> +#define ZX297520V3_NAND_RESET 3
> +#define ZX297520V3_SSC_RESET 4
> +#define ZX297520V3_EDCP_RESET 5
> +#define ZX297520V3_VOU_RESET 6
> +#define ZX297520V3_PDCFG_RESET 7
> +#define ZX297520V3_GMAC_RESET 8
> +#define ZX297520V3_DMA_RESET 9
> +#define ZX297520V3_MATRIXRST_END 10
> +
> +#define ZX297520V3_TIMER_L1_WCLK 0
> +#define ZX297520V3_TIMER_L1_PCLK 1
> +#define ZX297520V3_WDT_L2_WCLK 2
> +#define ZX297520V3_WDT_L2_PCLK 3
> +#define ZX297520V3_WDT_L3_WCLK 4
> +#define ZX297520V3_WDT_L3_PCLK 5
> +#define ZX297520V3_I2C1_WCLK 6
> +#define ZX297520V3_I2C1_PCLK 7
> +#define ZX297520V3_I2S0_WCLK 8
> +#define ZX297520V3_I2S0_PCLK 9
> +#define ZX297520V3_I2S1_WCLK 10
> +#define ZX297520V3_I2S1_PCLK 11
> +#define ZX297520V3_QSPI_WCLK 12
> +#define ZX297520V3_QSPI_PCLK 13
> +#define ZX297520V3_UART1_WCLK 14
> +#define ZX297520V3_UART1_PCLK 15
> +#define ZX297520V3_I2C2_WCLK 16
> +#define ZX297520V3_I2C2_PCLK 17
> +#define ZX297520V3_SPI0_WCLK 18
> +#define ZX297520V3_SPI0_PCLK 19
> +#define ZX297520V3_TIMER_LB_WCLK 20
> +#define ZX297520V3_TIMER_LB_PCLK 21
> +#define ZX297520V3_TIMER_LC_WCLK 22
> +#define ZX297520V3_TIMER_LC_PCLK 23
> +#define ZX297520V3_UART2_WCLK 24
> +#define ZX297520V3_UART2_PCLK 25
> +#define ZX297520V3_WDT_LE_WCLK 26
> +#define ZX297520V3_WDT_LE_PCLK 27
> +#define ZX297520V3_TIMER_LF_WCLK 28
> +#define ZX297520V3_TIMER_LF_PCLK 29
> +#define ZX297520V3_SPI1_WCLK 30
> +#define ZX297520V3_SPI1_PCLK 31
> +#define ZX297520V3_TIMER_L11_WCLK 32
> +#define ZX297520V3_TIMER_L11_PCLK 33
> +#define ZX297520V3_TDM_WCLK 34
> +#define ZX297520V3_TDM_PCLK 35
> +#define ZX297520V3_LSPCLK_END 36
> +
> +#define ZX297520V3_TIMER_L1_RESET 0
> +#define ZX297520V3_WDT_L2_RESET 1
> +#define ZX297520V3_WDT_L3_RESET 2
> +#define ZX297520V3_I2C1_RESET 3
> +#define ZX297520V3_I2S0_RESET 4
> +#define ZX297520V3_I2S1_RESET 5
> +#define ZX297520V3_QSPI_RESET 6
> +#define ZX297520V3_UART1_RESET 7
> +#define ZX297520V3_I2C2_RESET 8
> +#define ZX297520V3_SPI0_RESET 9
> +#define ZX297520V3_TIMER_LB_RESET 10
> +#define ZX297520V3_TIMER_LC_RESET 11
> +#define ZX297520V3_UART2_RESET 12
> +#define ZX297520V3_WDT_LE_RESET 13
> +#define ZX297520V3_TIMER_LF_RESET 14
> +#define ZX297520V3_SPI1_RESET 15
> +#define ZX297520V3_TIMER_L11_RESET 16
> +#define ZX297520V3_TDM_RESET 17
> +#define ZX297520V3_LSPRST_END 18
> +
> +#endif /* __DT_BINDINGS_CLOCK_ZX297520V3_H */
>
> --
> 2.53.0
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH] clk: rockchip: Use flexible array for clock table
From: Brian Masney @ 2026-05-11 16:06 UTC (permalink / raw)
To: Rosen Penev
Cc: linux-clk, Michael Turquette, Stephen Boyd, Heiko Stuebner,
moderated list:ARM/Rockchip SoC support,
open list:ARM/Rockchip SoC support, open list
In-Reply-To: <20260511032252.361906-1-rosenp@gmail.com>
Hi Rosen,
On Sun, May 10, 2026 at 08:22:52PM -0700, Rosen Penev wrote:
> Store the clock lookup table in the Rockchip clock provider
> allocation instead of allocating it separately.
>
> This ties the table lifetime directly to the provider and removes a
> separate allocation failure path while preserving the clk_onecell_data
> lookup interface.
>
> Assisted-by: Codex:GPT-5.5
> Signed-off-by: Rosen Penev <rosenp@gmail.com>
> ---
> drivers/clk/rockchip/clk.c | 17 ++++-------------
> drivers/clk/rockchip/clk.h | 2 ++
> 2 files changed, 6 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/clk/rockchip/clk.c b/drivers/clk/rockchip/clk.c
> index ee8c79b938d3..dbb4b6f33abb 100644
> --- a/drivers/clk/rockchip/clk.c
> +++ b/drivers/clk/rockchip/clk.c
> @@ -359,26 +359,21 @@ static struct rockchip_clk_provider *rockchip_clk_init_base(
> unsigned long nr_clks, bool has_late_clocks)
> {
> struct rockchip_clk_provider *ctx;
> - struct clk **clk_table;
> struct clk *default_clk_val;
> int i;
>
> default_clk_val = ERR_PTR(has_late_clocks ? -EPROBE_DEFER : -ENOENT);
>
> - ctx = kzalloc_obj(struct rockchip_clk_provider);
> + ctx = kzalloc_flex(*ctx, clk_table, nr_clks);
> if (!ctx)
> return ERR_PTR(-ENOMEM);
>
> - clk_table = kzalloc_objs(struct clk *, nr_clks);
> - if (!clk_table)
> - goto err_free;
> -
> for (i = 0; i < nr_clks; ++i)
> - clk_table[i] = default_clk_val;
> + ctx->clk_table[i] = default_clk_val;
>
> - ctx->reg_base = base;
> - ctx->clk_data.clks = clk_table;
> ctx->clk_data.clk_num = nr_clks;
> + ctx->clk_data.clks = ctx->clk_table;
Where's the __counted_by? Also struct clk_onecell_data is embedded
inside struct rockchip_clk_provider, and I'm not sure offhand how
that'll work.
Brian
> + ctx->reg_base = base;
> ctx->cru_node = np;
> spin_lock_init(&ctx->lock);
>
> @@ -388,10 +383,6 @@ static struct rockchip_clk_provider *rockchip_clk_init_base(
> "rockchip,grf");
>
> return ctx;
> -
> -err_free:
> - kfree(ctx);
> - return ERR_PTR(-ENOMEM);
> }
>
> struct rockchip_clk_provider *rockchip_clk_init(struct device_node *np,
> diff --git a/drivers/clk/rockchip/clk.h b/drivers/clk/rockchip/clk.h
> index 9e3503e2ffc2..d4033bf750f5 100644
> --- a/drivers/clk/rockchip/clk.h
> +++ b/drivers/clk/rockchip/clk.h
> @@ -604,6 +604,7 @@ struct rockchip_aux_grf {
> * @grf: regmap of the general-register-files syscon
> * @aux_grf_table: hashtable of auxiliary GRF regmaps, indexed by grf_type
> * @lock: maintains exclusion between callbacks for a given clock-provider.
> + * @clk_table: clock lookup table.
> */
> struct rockchip_clk_provider {
> void __iomem *reg_base;
> @@ -612,6 +613,7 @@ struct rockchip_clk_provider {
> struct regmap *grf;
> DECLARE_HASHTABLE(aux_grf_table, GRF_HASH_ORDER);
> spinlock_t lock;
> + struct clk *clk_table[];
> };
>
> struct rockchip_pll_rate_table {
> --
> 2.54.0
>
^ permalink raw reply
* [PATCH] tty: serial: atmel: Ignore chars when CREAD is cleared
From: Rakesh Alasyam @ 2026-05-11 15:56 UTC (permalink / raw)
To: gregkh
Cc: richard.genoud, jirislaby, nicolas.ferre, alexandre.belloni,
claudiu.beznea, linux-serial, linux-kernel, linux-arm-kernel,
Rakesh Alasyam
In-Reply-To: <2026051106-obliged-dismount-d85f@gregkh>
Ignore received characters when CREAD is cleared by adding RXRDY
to ignore_status_mask.
This replaces an existing TODO in the driver.
Tested on hardware.
Signed-off-by: Rakesh Alasyam <alasyamrakesh77@gmail.com>
---
v2:
- Add blank line before comment
- Tested on hardware
---
drivers/tty/serial/atmel_serial.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 5d8c1cfc1c60..5c756dc904b0 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -2184,7 +2184,8 @@ static void atmel_set_termios(struct uart_port *port,
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= ATMEL_US_OVRE;
}
- /* TODO: Ignore all characters if CREAD is set.*/
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= ATMEL_US_RXRDY;
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/3] dt-bindings: iio: adc: Add GPADC for Allwinner A523
From: Andre Przywara @ 2026-05-11 16:02 UTC (permalink / raw)
To: Michal Piekos, Jonathan Cameron, David Lechner, Nuno Sá,
Andy Shevchenko, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Chen-Yu Tsai, Jernej Skrabec, Samuel Holland, Maksim Kiselev
Cc: linux-iio, devicetree, linux-arm-kernel, linux-sunxi,
linux-kernel
In-Reply-To: <20260510-sunxi-a523-gpadc-v1-1-4f6b0f4000fb@mmpsystems.pl>
Hi Michal,
thanks for adding this!
On 5/10/26 14:57, Michal Piekos wrote:
> Add support for the GPADC for the Allwinner A523. It differs from the
> D1/T113s/R329/T507 by having two clocks.
>
> Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
> ---
> .../iio/adc/allwinner,sun20i-d1-gpadc.yaml | 37 +++++++++++++++++++++-
> 1 file changed, 36 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml b/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml
> index da605a051b94..89da96cd705f 100644
> --- a/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml
> +++ b/Documentation/devicetree/bindings/iio/adc/allwinner,sun20i-d1-gpadc.yaml
> @@ -17,6 +17,7 @@ properties:
> - items:
> - enum:
> - allwinner,sun50i-h616-gpadc
> + - allwinner,sun55i-a523-gpadc
> - const: allwinner,sun20i-d1-gpadc
As Jernej already mentioned, the A523 GPADC is not fully compatible,
since it adds another clock. The question to ask is: Can a driver only
knowing about the fallback device handle this new device? For which the
answer here is: No, it misses a clock.
So add just a single entry for the A523 (plus adding it to the driver).
So looking at this I wonder if we should add some property to describe
the number of supported channels, since they are slightly different
between the SoCs:
- The D1 manual mentions 2 channels.
- The T113s manual (same die as the D1?) describes 1 channel only.
- The T507 manual (same die as the H616) reports 4 channels.
- The A733 has 6 channels.
- The A133 has 1 channel, but it's channel 1, not 0.
So all of this is somewhat covered as channels are described as child
nodes, and have a reg property. Ideally non-existing channels just
wouldn't be listed, but I don't know if we want to rely on that.
So I am wondering if we should introduce a limit, or rather a mask (to
cover the A133 oddity)?
Either a DT property (channel-mask, as a single sell representing the
bit mask), or derived in the driver from the compatible string.
The former would avoid introducing different compatible strings just
because of that, though I think this type of property is somewhat
discouraged?
Any thoughts?
>
> "#io-channel-cells":
> @@ -29,7 +30,12 @@ properties:
> const: 0
>
> clocks:
> - maxItems: 1
> + minItems: 1
> + maxItems: 2
> +
> + clock-names:
> + minItems: 1
> + maxItems: 2
>
> interrupts:
> maxItems: 1
> @@ -40,6 +46,35 @@ properties:
> resets:
> maxItems: 1
>
> +allOf:
> + - if:
> + properties:
> + compatible:
> + items:
> + - const: allwinner,sun55i-a523-gpadc
> + - const: allwinner,sun20i-d1-gpadc
> + then:
> + properties:
> + clocks:
> + minItems: 2
> + maxItems: 2
> + items:
> + - description: Bus clock
> + - description: Module clock
I am not a YAML expert, but I think you can drop the min and max
properties, if you just enumerate the cases. Same for the names.
Cheers,
Andre
> + clock-names:
> + minItems: 2
> + maxItems: 2
> + items:
> + - const: bus
> + - const: mod
> + required:
> + - clock-names
> + else:
> + properties:
> + clocks:
> + maxItems: 1
> + clock-names: false
> +
> patternProperties:
> "^channel@[0-9a-f]+$":
> $ref: adc.yaml
>
^ permalink raw reply
* [PATCH v7 3/3] driver core: Avoid warning when removing a device while its supplier is unbinding
From: Herve Codina @ 2026-05-11 15:57 UTC (permalink / raw)
To: Andrew Lunn, Rob Herring, Saravana Kannan, Geert Uytterhoeven,
Kalle Niemi, Matti Vaittinen, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Wolfram Sang, Mark Brown,
Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Len Brown, Shawn Guo
Cc: Wolfram Sang, driver-core, linux-kernel, imx, linux-arm-kernel,
linux-i2c, devicetree, linux-spi, linux-acpi, Allan Nielsen,
Horatiu Vultur, Daniel Machon, Steen Hegelund, Luca Ceresoli,
Thomas Petazzoni, Herve Codina, Saravana Kannan
In-Reply-To: <20260511155755.34428-1-herve.codina@bootlin.com>
During driver removal, the following warning can appear:
WARNING: CPU: 1 PID: 139 at drivers/base/core.c:1497 __device_links_no_driver+0xcc/0xfc
...
Call trace:
__device_links_no_driver+0xcc/0xfc (P)
device_links_driver_cleanup+0xa8/0xf0
device_release_driver_internal+0x208/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
device_links_unbind_consumers+0xe0/0x108
device_release_driver_internal+0xec/0x23c
driver_detach+0xa0/0x12c
bus_remove_driver+0x6c/0xbc
driver_unregister+0x30/0x60
pci_unregister_driver+0x20/0x9c
lan966x_pci_driver_exit+0x18/0xa90 [lan966x_pci]
This warning is triggered when a consumer is removed because the links
status of its supplier is not DL_DEV_DRIVER_BOUND and the link flag
DL_FLAG_SYNC_STATE_ONLY is not set.
The topology in terms of consumers/suppliers used was the following
(consumer ---> supplier):
i2c -----------> OIC ----> PCI device
| ^
| |
+---> pinctrl ---+
When the PCI device is removed, the OIC (interrupt controller) has to be
removed. In order to remove the OIC, pinctrl and i2c need to be removed
and to remove pinctrl, i2c need to be removed. The removal order is:
1) i2c
2) pinctrl
3) OIC
4) PCI device
In details, the removal sequence is the following (with 0000:01:00.0 the
PCI device):
driver_detach: call device_release_driver_internal(0000:01:00.0)...
device_links_busy(0000:01:00.0):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(0000:01:00.0):
0000:01:00.0--oic link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(oic)...
device_links_busy(oic):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(oic):
oic--pinctrl link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(pinctrl)...
device_links_busy(pinctrl):
links->status = DL_DEV_UNBINDING
device_links_unbind_consumers(pinctrl):
pinctrl--i2c link->status = DL_STATE_SUPPLIER_UNBIND
call device_release_driver_internal(i2c)...
device_links_busy(i2c): links->status = DL_DEV_UNBINDING
__device_links_no_driver(i2c)...
pinctrl--i2c link->status is DL_STATE_SUPPLIER_UNBIND
oic--i2c link->status is DL_STATE_ACTIVE
oic--i2c link->supplier->links.status is DL_DEV_UNBINDING
The warning is triggered by the i2c removal because the OIC (supplier)
links status is not DL_DEV_DRIVER_BOUND. Its links status is indeed set
to DL_DEV_UNBINDING.
It is perfectly legit to have the links status set to DL_DEV_UNBINDING
in that case. Indeed we had started to unbind the OIC which triggered
the consumer unbinding and didn't finish yet when the i2c is unbound.
Avoid the warning when the supplier links status is set to
DL_DEV_UNBINDING and thus support this removal sequence without any
warnings.
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Reviewed-by: Rafael J. Wysocki <rafael@kernel.org>
Reviewed-by: Saravana Kannan <saravanak@google.com>
---
drivers/base/core.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 478aa3fbf1e8..934da2566c61 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1500,7 +1500,8 @@ static void __device_links_no_driver(struct device *dev)
if (link->supplier->links.status == DL_DEV_DRIVER_BOUND) {
WRITE_ONCE(link->status, DL_STATE_AVAILABLE);
} else {
- WARN_ON(!device_link_test(link, DL_FLAG_SYNC_STATE_ONLY));
+ WARN_ON(link->supplier->links.status != DL_DEV_UNBINDING &&
+ !device_link_test(link, DL_FLAG_SYNC_STATE_ONLY));
WRITE_ONCE(link->status, DL_STATE_DORMANT);
}
}
--
2.54.0
^ permalink raw reply related
* [PATCH v7 2/3] of: dynamic: Fix overlayed devices not probing because of fw_devlink
From: Herve Codina @ 2026-05-11 15:57 UTC (permalink / raw)
To: Andrew Lunn, Rob Herring, Saravana Kannan, Geert Uytterhoeven,
Kalle Niemi, Matti Vaittinen, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Wolfram Sang, Mark Brown,
Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Len Brown, Shawn Guo
Cc: Wolfram Sang, driver-core, linux-kernel, imx, linux-arm-kernel,
linux-i2c, devicetree, linux-spi, linux-acpi, Allan Nielsen,
Horatiu Vultur, Daniel Machon, Steen Hegelund, Luca Ceresoli,
Thomas Petazzoni, Saravana Kannan, Herve Codina
In-Reply-To: <20260511155755.34428-1-herve.codina@bootlin.com>
From: Saravana Kannan <saravanak@google.com>
When an overlay is applied, if the target device has already probed
successfully and bound to a device, then some of the fw_devlink logic
that ran when the device was probed needs to be rerun. This allows newly
created dangling consumers of the overlayed device tree nodes to be
moved to become consumers of the target device.
Fixes: 1a50d9403fb9 ("treewide: Fix probing of devices in DT overlays")
Reported-by: Herve Codina <herve.codina@bootlin.com>
Closes: https://lore.kernel.org/lkml/CAMuHMdXEnSD4rRJ-o90x4OprUacN_rJgyo8x6=9F9rZ+-KzjOg@mail.gmail.com/
Closes: https://lore.kernel.org/all/20240221095137.616d2aaa@bootlin.com/
Closes: https://lore.kernel.org/lkml/20240312151835.29ef62a0@bootlin.com/
Signed-off-by: Saravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/lkml/20240411235623.1260061-3-saravanak@google.com/
[Herve: Rebase on top of recent kernel]
[Herve: Add the call to driver_deferred_probe_trigger()]
[Herve: Use fwnode_test_flag() to test fwnode flags value]
Signed-off-by: Herve Codina <herve.codina@bootlin.com>
Tested-by: Kalle Niemi <kaleposti@gmail.com>
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
---
drivers/base/core.c | 83 +++++++++++++++++++++++++++++++++++++-----
drivers/of/overlay.c | 15 ++++++++
include/linux/fwnode.h | 1 +
3 files changed, 90 insertions(+), 9 deletions(-)
diff --git a/drivers/base/core.c b/drivers/base/core.c
index bd2ddf2aab50..478aa3fbf1e8 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -235,6 +235,79 @@ static void __fw_devlink_pickup_dangling_consumers(struct fwnode_handle *fwnode,
__fw_devlink_pickup_dangling_consumers(child, new_sup);
}
+static void fw_devlink_pickup_dangling_consumers(struct device *dev)
+{
+ struct fwnode_handle *child;
+
+ guard(mutex)(&fwnode_link_lock);
+
+ fwnode_for_each_available_child_node(dev->fwnode, child)
+ __fw_devlink_pickup_dangling_consumers(child, dev->fwnode);
+ __fw_devlink_link_to_consumers(dev);
+}
+
+/**
+ * fw_devlink_refresh_fwnode - Recheck the tree under this firmware node
+ * @fwnode: The fwnode under which the fwnode tree has changed
+ *
+ * This function is mainly meant to adjust the supplier/consumer dependencies
+ * after a fwnode tree overlay has occurred.
+ */
+void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode)
+{
+ struct device *dev;
+
+ /*
+ * Find the closest ancestor fwnode that has been converted to a device
+ * that can bind to a driver (bus device).
+ */
+ fwnode_handle_get(fwnode);
+ do {
+ if (fwnode_test_flag(fwnode, FWNODE_FLAG_NOT_DEVICE))
+ continue;
+
+ dev = get_dev_from_fwnode(fwnode);
+ if (!dev)
+ continue;
+
+ if (dev->bus)
+ break;
+
+ put_device(dev);
+ } while ((fwnode = fwnode_get_next_parent(fwnode)));
+
+ /*
+ * If none of the ancestor fwnodes have (yet) been converted to a device
+ * that can bind to a driver, there's nothing to fix up.
+ */
+ if (!fwnode)
+ return;
+
+ WARN(device_is_bound(dev) && dev->links.status != DL_DEV_DRIVER_BOUND,
+ "Don't multithread overlaying and probing the same device!\n");
+
+ /*
+ * If the device has already bound to a driver, then we need to redo
+ * some of the work that was done after the device was bound to a
+ * driver. If the device hasn't bound to a driver, running things too
+ * soon would incorrectly pick up consumers that it shouldn't.
+ */
+ if (dev->links.status == DL_DEV_DRIVER_BOUND) {
+ fw_devlink_pickup_dangling_consumers(dev);
+ /*
+ * Some of dangling consumers could have been put previously in
+ * the deferred probe list due to the unavailability of their
+ * suppliers. Those consumers have been picked up and some of
+ * their suppliers links have been updated. Time to re-try their
+ * probe sequence.
+ */
+ driver_deferred_probe_trigger();
+ }
+
+ put_device(dev);
+ fwnode_handle_put(fwnode);
+}
+
static DEFINE_MUTEX(device_links_lock);
DEFINE_STATIC_SRCU(device_links_srcu);
@@ -1312,16 +1385,8 @@ void device_links_driver_bound(struct device *dev)
* child firmware node.
*/
if (dev->fwnode && dev->fwnode->dev == dev) {
- struct fwnode_handle *child;
-
fwnode_links_purge_suppliers(dev->fwnode);
-
- guard(mutex)(&fwnode_link_lock);
-
- fwnode_for_each_available_child_node(dev->fwnode, child)
- __fw_devlink_pickup_dangling_consumers(child,
- dev->fwnode);
- __fw_devlink_link_to_consumers(dev);
+ fw_devlink_pickup_dangling_consumers(dev);
}
device_remove_file(dev, &dev_attr_waiting_for_supplier);
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index c1c5686fc7b1..4e45f3414c2c 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -185,6 +185,15 @@ static int overlay_notify(struct overlay_changeset *ovcs,
return 0;
}
+static void overlay_fw_devlink_refresh(struct overlay_changeset *ovcs)
+{
+ for (int i = 0; i < ovcs->count; i++) {
+ struct device_node *np = ovcs->fragments[i].target;
+
+ fw_devlink_refresh_fwnode(of_fwnode_handle(np));
+ }
+}
+
/*
* The values of properties in the "/__symbols__" node are paths in
* the ovcs->overlay_root. When duplicating the properties, the paths
@@ -951,6 +960,12 @@ static int of_overlay_apply(struct overlay_changeset *ovcs,
pr_err("overlay apply changeset entry notify error %d\n", ret);
/* notify failure is not fatal, continue */
+ /*
+ * Needs to happen after changeset notify to give the listeners a chance
+ * to finish creating all the devices they need to create.
+ */
+ overlay_fw_devlink_refresh(ovcs);
+
ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_APPLY);
if (ret_tmp)
if (!ret)
diff --git a/include/linux/fwnode.h b/include/linux/fwnode.h
index 80b38fbf2121..357592c5b375 100644
--- a/include/linux/fwnode.h
+++ b/include/linux/fwnode.h
@@ -250,6 +250,7 @@ int fwnode_link_add(struct fwnode_handle *con, struct fwnode_handle *sup,
u8 flags);
void fwnode_links_purge(struct fwnode_handle *fwnode);
void fw_devlink_purge_absent_suppliers(struct fwnode_handle *fwnode);
+void fw_devlink_refresh_fwnode(struct fwnode_handle *fwnode);
bool fw_devlink_is_strict(void);
#endif
--
2.54.0
^ permalink raw reply related
* [PATCH v7 0/3] lan966x pci device: Add support for SFPs, core part
From: Herve Codina @ 2026-05-11 15:57 UTC (permalink / raw)
To: Andrew Lunn, Rob Herring, Saravana Kannan, Geert Uytterhoeven,
Kalle Niemi, Matti Vaittinen, Greg Kroah-Hartman,
Rafael J. Wysocki, Danilo Krummrich, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Wolfram Sang, Mark Brown,
Andy Shevchenko, Daniel Scally, Heikki Krogerus, Sakari Ailus,
Len Brown, Shawn Guo
Cc: Wolfram Sang, driver-core, linux-kernel, imx, linux-arm-kernel,
linux-i2c, devicetree, linux-spi, linux-acpi, Allan Nielsen,
Horatiu Vultur, Daniel Machon, Steen Hegelund, Luca Ceresoli,
Thomas Petazzoni, Herve Codina
Hi,
Previously, I sent a big picture series adding support for SFP ports
available on the LAN966x PCI device [0].
In this series patches touch several parts and sub-system in the kernel.
Reviews have be done and it makes sense to split the series and send
parts separately.
This current series is the extraction of patches related to driver core
subsystem. It fixes devlink issues when a device-tree overlay is applied
and avoid a warning when a device is removed.
It has to be seen as a continuation of the big picture series but
related to this specific core part.
Patches 1 and 2 fixes fw_devlink when it is used with overlay. Those
patches were previously sent by Saravana [1].
I rebased them on top of v7.1-rc1 and I added a call to
driver_deferred_probe_trigger() in Saravana's patch (patch 2) to ensure
that probes are retried after the modification performed on the dangling
consumers. This allows to fix issues reported by Matti and Geert [2]
with the previous iteration patches.
Patch 3 avoids a warning on device removal.
Those 3 patches seem ready to land and so having them extracted in this
current series will help having them applied.
[0] https://lore.kernel.org/all/20260325143555.451852-1-herve.codina@bootlin.com/
[1] https://lore.kernel.org/lkml/20240411235623.1260061-1-saravanak@google.com/
[2] https://lore.kernel.org/all/072dde7c-a53c-4525-83ac-57ea38edc0b5@gmail.com/
Best regards,
Hervé
Changes:
v6 -> v7
Rebase on top v7.1-rc1
- Patch 1
Fix conflict due to commit f72e77c33e4b ("device property: Make
modifications of fwnode "flags" thread safe")
Add 'Acked-by: Rob Herring'
- Patch 2
Use fwnode_test_flag() to test fwnode flags value
Add 'Acked-by: Rob Herring'
- Patche 3
No changes
Older iterations:
Patches 1 to 3 in the big picture series
https://lore.kernel.org/all/20260325143555.451852-1-herve.codina@bootlin.com/
Herve Codina (1):
driver core: Avoid warning when removing a device while its supplier
is unbinding
Saravana Kannan (2):
Revert "treewide: Fix probing of devices in DT overlays"
of: dynamic: Fix overlayed devices not probing because of fw_devlink
drivers/base/core.c | 86 ++++++++++++++++++++++++++++++++++-----
drivers/bus/imx-weim.c | 6 ---
drivers/i2c/i2c-core-of.c | 5 ---
drivers/of/dynamic.c | 1 -
drivers/of/overlay.c | 15 +++++++
drivers/of/platform.c | 5 ---
drivers/spi/spi.c | 5 ---
include/linux/fwnode.h | 1 +
8 files changed, 92 insertions(+), 32 deletions(-)
--
2.54.0
^ permalink raw reply
* Re: [PATCH 1/1] clk: nuvoton: ma35d1: fix PLL frequency calculation
From: Brian Masney @ 2026-05-11 15:54 UTC (permalink / raw)
To: Joey Lu
Cc: mturquette, sboyd, ychuang3, schung, yclu4, linux-arm-kernel,
linux-clk, linux-kernel
In-Reply-To: <20260511031600.31929-2-a0987203069@gmail.com>
Hi Joey,
On Mon, May 11, 2026 at 11:15:59AM +0800, Joey Lu wrote:
> Fix four bugs in the MA35D1 PLL driver:
>
> 1. PLL_CTL1_FRAC was defined as GENMASK(31, 24) (8 bits), but the
> hardware fractional field spans bits [31:8] (24 bits). This caused
> wrong frequency calculation in fractional and spread-spectrum modes.
>
> 2. div_u64() does not modify its argument in-place; the quotient must
> be assigned from the return value. Both ma35d1_calc_smic_pll_freq()
> and ma35d1_calc_pll_freq() discarded the return value, leaving
> pll_freq undivided and orders of magnitude too high.
>
> 3. The fractional-mode calculation divided x by FIELD_MAX(PLL_CTL1_FRAC)
> to get 2 decimal digits. After correcting the mask to 24 bits, update
> the arithmetic to use 3 decimal digits with proper 24-bit fixed-point
> rounding.
>
> 4. ma35d1_clk_pll_determine_rate() called ma35d1_pll_find_closest()
> unconditionally before the switch, but then overwrote its result by
> reading the current hardware registers for every PLL type. Move the
> find_closest() call inside the configurable-PLL branch (APLL, EPLL,
> VPLL). CAPLL and DDRPLL do not support runtime rate changes and
> correctly return the current hardware rate.
>
> Fixes: 691521a367cf ("clk: nuvoton: Add clock driver for ma35d1 clock controller")
> Signed-off-by: Joey Lu <a0987203069@gmail.com>
Thanks for the patch, however this should really be broken up into more
patches. If possible, one patch for each of the fixes.
Brian
> ---
> drivers/clk/nuvoton/clk-ma35d1-pll.c | 34 +++++++++++++--------------
> 1 file changed, 17 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/clk/nuvoton/clk-ma35d1-pll.c b/drivers/clk/nuvoton/clk-ma35d1-pll.c
> index 4620acfe47e8..314b81e7727c 100644
> --- a/drivers/clk/nuvoton/clk-ma35d1-pll.c
> +++ b/drivers/clk/nuvoton/clk-ma35d1-pll.c
> @@ -48,7 +48,7 @@
> #define PLL_CTL1_PD BIT(0)
> #define PLL_CTL1_BP BIT(1)
> #define PLL_CTL1_OUTDIV GENMASK(6, 4)
> -#define PLL_CTL1_FRAC GENMASK(31, 24)
> +#define PLL_CTL1_FRAC GENMASK(31, 8)
> #define PLL_CTL2_SLOPE GENMASK(23, 0)
>
> #define INDIV_MIN 1
> @@ -92,7 +92,7 @@ static unsigned long ma35d1_calc_smic_pll_freq(u32 pll0_ctl0,
> p = FIELD_GET(SPLL0_CTL0_OUTDIV, pll0_ctl0);
> outdiv = 1 << p;
> pll_freq = (u64)parent_rate * n;
> - div_u64(pll_freq, m * outdiv);
> + pll_freq = div_u64(pll_freq, m * outdiv);
> return pll_freq;
> }
>
> @@ -110,12 +110,12 @@ static unsigned long ma35d1_calc_pll_freq(u8 mode, u32 *reg_ctl, unsigned long p
>
> if (mode == PLL_MODE_INT) {
> pll_freq = (u64)parent_rate * n;
> - div_u64(pll_freq, m * p);
> + pll_freq = div_u64(pll_freq, m * p);
> } else {
> x = FIELD_GET(PLL_CTL1_FRAC, reg_ctl[1]);
> - /* 2 decimal places floating to integer (ex. 1.23 to 123) */
> - n = n * 100 + ((x * 100) / FIELD_MAX(PLL_CTL1_FRAC));
> - pll_freq = div_u64(parent_rate * n, 100 * m * p);
> + /* x is 24-bit fractional part, convert to 3 decimal digits */
> + n = n * 1000 + (u32)(((u64)x * 1000 + 500) >> 24);
> + pll_freq = div_u64((u64)parent_rate * n, 1000 * m * p);
> }
> return pll_freq;
> }
> @@ -255,32 +255,32 @@ static int ma35d1_clk_pll_determine_rate(struct clk_hw *hw,
> if (req->best_parent_rate < PLL_FREF_MIN_FREQ || req->best_parent_rate > PLL_FREF_MAX_FREQ)
> return -EINVAL;
>
> - ret = ma35d1_pll_find_closest(pll, req->rate, req->best_parent_rate,
> - reg_ctl, &pll_freq);
> - if (ret < 0)
> - return ret;
> -
> switch (pll->id) {
> case CAPLL:
> + case DDRPLL:
> + /* Read-only PLLs: return current rate */
> reg_ctl[0] = readl_relaxed(pll->ctl0_base);
> - pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], req->best_parent_rate);
> + if (pll->id == CAPLL) {
> + pll_freq = ma35d1_calc_smic_pll_freq(reg_ctl[0], req->best_parent_rate);
> + } else {
> + reg_ctl[1] = readl_relaxed(pll->ctl1_base);
> + pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, req->best_parent_rate);
> + }
> req->rate = pll_freq;
> -
> return 0;
> - case DDRPLL:
> case APLL:
> case EPLL:
> case VPLL:
> - reg_ctl[0] = readl_relaxed(pll->ctl0_base);
> - reg_ctl[1] = readl_relaxed(pll->ctl1_base);
> - pll_freq = ma35d1_calc_pll_freq(pll->mode, reg_ctl, req->best_parent_rate);
> + /* Configurable PLLs: find closest achievable rate */
> + ret = ma35d1_pll_find_closest(pll, req->rate, req->best_parent_rate,
> + reg_ctl, &pll_freq);
> + if (ret < 0)
> + return ret;
> req->rate = pll_freq;
> -
> return 0;
> }
>
> req->rate = 0;
> -
> return 0;
> }
>
> --
> 2.49.0
^ permalink raw reply
* Re: [PATCH v3 0/5] arm_mpam: resctrl: Counter Assignment (ABMC)
From: Ben Horgan @ 2026-05-11 15:51 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jonathan.cameron, kobak,
lcherian, linux-arm-kernel, linux-kernel, peternewman,
punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
sdonthineni, tan.shaopeng, xhao, zengheng4, x86
In-Reply-To: <20260511154147.557481-1-ben.horgan@arm.com>
I forgot to say, the code can be found at:
https://gitlab.arm.com/linux-arm/linux-bh.git mpam_abmc_v3
On 5/11/26 16:41, Ben Horgan wrote:
> Removing the rfc tag as the resctrl precursors [1] have been queued in tip
> x86/cache. Due to that dependency, it would be good for this to also go through
> x86/cache.
>
> This series adds support for memory bandwidth monitoring.
>
> Please review and test.
>
> Changelogs in patches.
>
> [1] https://lore.kernel.org/all/20260506082855.3694761-1-ben.horgan@arm.com/
>
> Description from the initial cover letter:
>
> The MPAM counter assignment (ABMC emulation) changes that were dropped from
> the resctrl glue series due to some missing precursors in resctrl. Counter
> assignment enables bandwidth monitoring in systems that have fewer
> monitors than resctrl monitor groups.
>
> rfc v1: https://lore.kernel.org/lkml/20260225205436.3571756-1-ben.horgan@arm.com/
> rfc v2: https://lore.kernel.org/lkml/20260319165540.381410-1-ben.horgan@arm.com/
>
> Ben Horgan (2):
> arm_mpam: resctrl: Pre-allocate assignable monitors
> arm64: mpam: Add memory bandwidth usage (MBWU) documentation
>
> James Morse (3):
> arm_mpam: resctrl: Pick classes for use as mbm counters
> arm_mpam: resctrl: Add resctrl_arch_config_cntr() for ABMC use
> arm_mpam: resctrl: Add resctrl_arch_cntr_read() &
> resctrl_arch_reset_cntr()
>
> Documentation/arch/arm64/mpam.rst | 17 ++
> drivers/resctrl/mpam_internal.h | 6 +-
> drivers/resctrl/mpam_resctrl.c | 306 +++++++++++++++++++++++++++---
> 3 files changed, 306 insertions(+), 23 deletions(-)
>
^ permalink raw reply
* Re: [PATCH net-next v2 4/4] net: phy: Introduce Airoha AN8801/R Gigabit Ethernet PHY driver
From: Louis-Alexis Eyraud @ 2026-05-11 15:49 UTC (permalink / raw)
To: Andrew Lunn
Cc: Andrew Lunn, David S. Miller, Eric Dumazet, Jakub Kicinski,
Paolo Abeni, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
AngeloGioacchino Del Regno, Heiner Kallweit, Russell King,
kevin-kw.huang, macpaul.lin, matthias.bgg, kernel, netdev,
devicetree, linux-arm-kernel, linux-mediatek, linux-kernel
In-Reply-To: <27ca6b71-18df-4e47-9117-0e503f7e7d5f@lunn.ch>
Hi Andrew,
On Thu, 2026-05-07 at 23:43 +0200, Andrew Lunn wrote:
> > > > +static int an8801r_of_init_leds(struct phy_device *phydev, u8
> > > > *led_cfg)
> > > > +{
> > > > + struct device *dev = &phydev->mdio.dev;
> > > > + struct device_node *np = dev->of_node;
> > > > + struct device_node *leds;
> > > > + u32 function_enum_idx;
> > > > + int ret;
> > > > +
> > > > + if (!np)
> > > > + return 0;
> > > > +
> > > > + /* If devicetree is present, leds configuration is
> > > > required */
> > > > + leds = of_get_child_by_name(np, "leds");
> > > > + if (!leds)
> > > > + return 0;
> > > > +
> > > > + for_each_available_child_of_node_scoped(leds, led) {
> > > > + u32 led_idx;
> > > > +
> > > > + ret = of_property_read_u32(led, "reg",
> > > > &led_idx);
> > > > + if (ret)
> > > > + goto out;
> > > > +
> > > > + if (led_idx >= AN8801R_NUM_LEDS) {
> > > > + ret = -EINVAL;
> > > > + goto out;
> > > > + }
> > > > +
> > > > + ret = of_property_read_u32(led, "function-
> > > > enumerator",
> > > > +
> > > > &function_enum_idx);
> > > > + if (ret)
> > > > + function_enum_idx =
> > > > AN8801R_LED_FN_NONE;
> > > > +
> > >
> > > What is this doing? Is this documented in the binding?
> > The `function-enumerator` property is only documented in the led
> > common
> > dt-binding file. The an8801 dt-bindings inherits this property from
> > the
> > ethernet-phy dt-bindings.
> >
> > We aimed to have this PHY have its led behaviour (how many to
> > enable
> > and what their role shall be) configurable using devicetree and not
> > to
> > rely on a default configuration, hard-coded in the driver (like the
> > air_en8811h driver did) and also make use of the led hardware
> > offloading (for functions like 100/1000, activity blinking, and
> > others)
> > that this PHY is capable of.
>
> What other drivers do is leave the configuration with its reset
> default. They are often sensible. When the netdev trigger loads, it
> should ask the LED how it is configured, and the values in sysfs will
> reflect it. After that you can change it, via udev rules, etc.
When you say "reset default", do you mean the default PHY register
values, the ones that may have been set by the bootloader or by the
driver with a default hardcoded functional config?
>
> You have to be careful about what you put in DT. DT describes
> hardware, not configuration or policy. How the LED blinks is probably
> configuration, so it does not belong in DT.
I agree.
What I meant as configuration was only the leds node presence and the
led function properties, as the devicetree should describe what/how
many LED are connected to the PHY and they represent (or mean) for a
given board.
Parameters like off/on delay or trigger events are indeed not really
appropriate for devicetree and the AN8801 dt-bindings patch do not add
any such property.
And even, if technically the LEDs are reconfigurable with netdev or any
other LED trigger, the configuration is somehow hardware bound, because
the different colors of LEDs do kind-of bind a specific function to a
specific LED (amber vs green).
This is why the an8801r_of_init_leds function read those LED-related
properties (leds/led/function-enumerator) to set a default led config
behaviour (that can of course be overridden by an user with a led
trigger) rather than relying on bootloader or use a hardcoded led
register config in the driver.
What implementation would be preferred for this driver?
>
> > > > +static int an8801r_read_status(struct phy_device *phydev)
> > > > +{
> > > > + int prev_speed, ret;
> > > > + u32 val;
> > > > +
> > > > + prev_speed = phydev->speed;
> > > > +
> > > > + ret = genphy_read_status(phydev);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + if (phydev->link && prev_speed != phydev->speed) {
> > > > + val = phydev->speed == SPEED_1000 ?
> > > > + AN8801_BPBUS_LINK_MODE_1000 : 0;
> > > > +
> > > > + return an8801_buckpbus_reg_rmw(phydev,
> > > > +
> > > > AN8801_BPBUS_REG_LINK_MODE,
> > > > +
> > > > AN8801_BPBUS_LINK_MODE_1000,
> > > > + val);
> > > > + };
> > >
> > > This is unusual. What is it doing? Please add a comment.
> > This call is to ensure that the PHY switches to the expected 1Gbps
> > speed when available.
>
> So this is an errata workaround? Please add this in a patch of its
> own, described the problem in the commit message, list the errata
> etc.
>
OK, I'll add this in a separate patch in v3.
Best regards,
Louis-Alexis
> Andrew
^ permalink raw reply
* Re: [PATCH 05/10] clk: amlogic: PLL l_detect signal supports active-high configuration
From: Brian Masney @ 2026-05-11 15:47 UTC (permalink / raw)
To: jian.hu
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, Jerome Brunet, Xianwei Zhao,
Kevin Hilman, Martin Blumenstingl, linux-kernel, linux-clk,
devicetree, linux-amlogic, linux-arm-kernel
In-Reply-To: <20260511-b4-a9_clk-v1-5-41cb4071b7c9@amlogic.com>
On Mon, May 11, 2026 at 08:47:27PM +0800, Jian Hu via B4 Relay wrote:
> From: Jian Hu <jian.hu@amlogic.com>
>
> l_detect controls the enable/disable of the PLL lock-detect module.
>
> For A9, the l_detect signal is active-high:
> 0 -> Disable lock-detect module;
> 1 -> Enable lock-detect module.
>
> Here, a flag CLK_MESON_PLL_L_DETECT_ACTIVE_HIGH is added to handle cases
> like A9, where the signal is active-high.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
Reviewed-by: Brian Masney <bmasney@redhat.com>
^ permalink raw reply
* Re: [PATCH 10/10] clk: amlogic: Add A9 AO clock controller driver
From: Brian Masney @ 2026-05-11 15:45 UTC (permalink / raw)
To: jian.hu
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, Jerome Brunet, Xianwei Zhao,
Kevin Hilman, Martin Blumenstingl, linux-kernel, linux-clk,
devicetree, linux-amlogic, linux-arm-kernel
In-Reply-To: <20260511-b4-a9_clk-v1-10-41cb4071b7c9@amlogic.com>
Hi Jian,
On Mon, May 11, 2026 at 08:47:32PM +0800, Jian Hu via B4 Relay wrote:
> From: Jian Hu <jian.hu@amlogic.com>
>
> Add the Always-on clock controller driver for the Amlogic A9 SoC family.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
I'll only flag new things that I spot here that weren't mentioned in
the other patches I reviewed in this series.
> ---
> drivers/clk/meson/Makefile | 2 +-
> drivers/clk/meson/a9-aoclk.c | 494 +++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 495 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 2b5b67b14efc..91af609ce815 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -20,7 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
> obj-$(CONFIG_COMMON_CLK_A9_PLL) += a9-pll.o
> -obj-$(CONFIG_COMMON_CLK_A9_PERIPHERALS) += a9-peripherals.o
> +obj-$(CONFIG_COMMON_CLK_A9_PERIPHERALS) += a9-peripherals.o a9-aoclk.o
> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> diff --git a/drivers/clk/meson/a9-aoclk.c b/drivers/clk/meson/a9-aoclk.c
> new file mode 100644
> index 000000000000..3c42eaf585d2
> --- /dev/null
> +++ b/drivers/clk/meson/a9-aoclk.c
> @@ -0,0 +1,494 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +/*
> + * Copyright (C) 2026 Amlogic, Inc. All rights reserved
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +#include <dt-bindings/clock/amlogic,a9-aoclkc.h>
> +#include "clk-regmap.h"
> +#include "clk-dualdiv.h"
> +#include "meson-clkc-utils.h"
> +
> +#define AO_OSCIN_CTRL 0x00
> +#define AO_SYS_CLK0 0x04
> +#define AO_PWM_CLK_A_CTRL 0x1c
> +#define AO_PWM_CLK_B_CTRL 0x20
> +#define AO_PWM_CLK_C_CTRL 0x24
> +#define AO_PWM_CLK_D_CTRL 0x28
> +#define AO_PWM_CLK_E_CTRL 0x2c
> +#define AO_PWM_CLK_F_CTRL 0x30
> +#define AO_PWM_CLK_G_CTRL 0x34
> +#define AO_CEC_CTRL0 0x38
> +#define AO_CEC_CTRL1 0x3c
> +#define AO_RTC_BY_OSCIN_CTRL0 0x50
> +#define AO_RTC_BY_OSCIN_CTRL1 0x54
> +
> +#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata) \
> + MESON_COMP_SEL(a9_, _name, _reg, _shift, _mask, _pdata, NULL, 0, 0)
> +
> +#define A9_COMP_DIV(_name, _reg, _shift, _width) \
> + MESON_COMP_DIV(a9_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
> +
> +#define A9_COMP_GATE(_name, _reg, _bit) \
> + MESON_COMP_GATE(a9_, _name, _reg, _bit, CLK_SET_RATE_PARENT)
> +
> +static struct clk_regmap a9_ao_xtal_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = AO_OSCIN_CTRL,
> + .bit_idx = 3,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "ao_xtal_in",
> + .ops = &clk_regmap_gate_ops,
> + .parent_data = &(const struct clk_parent_data) {
> + .fw_name = "xtal",
> + },
> + .num_parents = 1,
> + /*
> + * It may be ao_sys's parent clock, its child clocks mark
> + * CLK_IS_CRITICAL, So mark CLK_IS_CRITICAL for it.
> + */
> + .flags = CLK_IS_CRITICAL,
> + },
> +};
> +
> +static struct clk_regmap a9_ao_xtal = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = AO_OSCIN_CTRL,
> + .mask = 0x1,
> + .shift = 0,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "ao_xtal",
> + .ops = &clk_regmap_mux_ops,
> + /* ext_32k is from external PAD, do not automatically reparent */
> + .parent_data = (const struct clk_parent_data []) {
> + { .hw = &a9_ao_xtal_in.hw },
> + { .fw_name = "ext_32k", },
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_RATE_NO_REPARENT,
> + },
> +};
> +
> +static struct clk_regmap a9_ao_sys = {
> + .data = &(struct clk_regmap_mux_data) {
> + .offset = AO_OSCIN_CTRL,
> + .mask = 0x1,
> + .shift = 1,
> + },
> + .hw.init = &(struct clk_init_data){
> + .name = "ao_sys",
> + .ops = &clk_regmap_mux_ops,
> + .parent_data = (const struct clk_parent_data []) {
> + { .hw = &a9_ao_xtal.hw },
> + { .fw_name = "sys", },
> + },
> + .num_parents = 2,
> + .flags = CLK_SET_PARENT_GATE,
> + },
> +};
> +
> +static const struct clk_parent_data a9_ao_pclk_parents = { .hw = &a9_ao_sys.hw };
> +
> +#define A9_AO_PCLK(_name, _bit, _flags) \
> + MESON_PCLK(a9_ao_sys_##_name, AO_SYS_CLK0, _bit, \
> + &a9_ao_pclk_parents, _flags)
> +
> +/*
> + * A9 integrates a low-power microprocessor (Always-on CPU: AOCPU). Some AO sys
> + * clocks control the AOCPU modules. Mark the AOCPU-related clocks with
> + * CLK_IS_CRITICAL to avoid them being disabled and impacting AOCPU functionality.
> + * AOCPU-related clocks list:
> + * - clktree
> + * - rst_ctrl
> + * - pad
> + * - irq
> + * - pwrctrl
> + * - aocpu
> + * - sram
> + */
> +static A9_AO_PCLK(i2c3, 0, 0);
> +static A9_AO_PCLK(rtc_reg, 1, 0);
> +static A9_AO_PCLK(clktree, 2, CLK_IS_CRITICAL);
> +static A9_AO_PCLK(rst_ctrl, 3, CLK_IS_CRITICAL);
> +static A9_AO_PCLK(pad, 4, CLK_IS_CRITICAL);
> +static A9_AO_PCLK(rtc_dig, 5, 0);
> +static A9_AO_PCLK(irq, 6, CLK_IS_CRITICAL);
> +static A9_AO_PCLK(pwrctrl, 7, CLK_IS_CRITICAL);
> +static A9_AO_PCLK(pwm_a, 8, 0);
> +static A9_AO_PCLK(pwm_b, 9, 0);
> +static A9_AO_PCLK(pwm_c, 10, 0);
> +static A9_AO_PCLK(pwm_d, 11, 0);
> +static A9_AO_PCLK(pwm_e, 12, 0);
> +static A9_AO_PCLK(pwm_f, 13, 0);
> +static A9_AO_PCLK(pwm_g, 14, 0);
> +static A9_AO_PCLK(i2c_a, 15, 0);
> +static A9_AO_PCLK(i2c_b, 16, 0);
> +static A9_AO_PCLK(i2c_c, 17, 0);
> +static A9_AO_PCLK(i2c_d, 18, 0);
> +static A9_AO_PCLK(sed, 19, 0);
> +static A9_AO_PCLK(ir_ctrl, 20, 0);
> +static A9_AO_PCLK(uart_b, 21, 0);
> +static A9_AO_PCLK(uart_c, 22, 0);
> +static A9_AO_PCLK(uart_d, 23, 0);
> +static A9_AO_PCLK(uart_e, 24, 0);
> +static A9_AO_PCLK(spisg_0, 25, 0);
> +static A9_AO_PCLK(rtc_secure, 26, 0);
> +static A9_AO_PCLK(cec, 27, 0);
> +static A9_AO_PCLK(aocpu, 28, CLK_IS_CRITICAL);
> +static A9_AO_PCLK(sram, 29, CLK_IS_CRITICAL);
> +static A9_AO_PCLK(spisg_1, 30, 0);
> +static A9_AO_PCLK(spisg_2, 31, 0);
> +
> +static const struct clk_parent_data a9_ao_pwm_parents[] = {
> + { .hw = &a9_ao_xtal.hw },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", }
> +};
> +
> +static A9_COMP_SEL(ao_pwm_a, AO_PWM_CLK_A_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(ao_pwm_a, AO_PWM_CLK_A_CTRL, 0, 8);
> +static A9_COMP_GATE(ao_pwm_a, AO_PWM_CLK_A_CTRL, 8);
> +
> +static A9_COMP_SEL(ao_pwm_b, AO_PWM_CLK_B_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(ao_pwm_b, AO_PWM_CLK_B_CTRL, 0, 8);
> +static A9_COMP_GATE(ao_pwm_b, AO_PWM_CLK_A_CTRL, 8);
Should this be AO_PWM_CLK_B_CTRL ?
> +
> +static A9_COMP_SEL(ao_pwm_c, AO_PWM_CLK_C_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(ao_pwm_c, AO_PWM_CLK_C_CTRL, 0, 8);
> +static A9_COMP_GATE(ao_pwm_c, AO_PWM_CLK_C_CTRL, 8);
> +
> +static A9_COMP_SEL(ao_pwm_d, AO_PWM_CLK_D_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(ao_pwm_d, AO_PWM_CLK_D_CTRL, 0, 8);
> +static A9_COMP_GATE(ao_pwm_d, AO_PWM_CLK_D_CTRL, 8);
> +
> +static A9_COMP_SEL(ao_pwm_e, AO_PWM_CLK_E_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(ao_pwm_e, AO_PWM_CLK_E_CTRL, 0, 8);
> +static A9_COMP_GATE(ao_pwm_e, AO_PWM_CLK_E_CTRL, 8);
> +
> +static A9_COMP_SEL(ao_pwm_f, AO_PWM_CLK_F_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(ao_pwm_f, AO_PWM_CLK_F_CTRL, 0, 8);
> +static A9_COMP_GATE(ao_pwm_f, AO_PWM_CLK_F_CTRL, 8);
> +
> +static A9_COMP_SEL(ao_pwm_g, AO_PWM_CLK_G_CTRL, 9, 0x7, a9_ao_pwm_parents);
> +static A9_COMP_DIV(ao_pwm_g, AO_PWM_CLK_G_CTRL, 0, 8);
> +static A9_COMP_GATE(ao_pwm_g, AO_PWM_CLK_G_CTRL, 8);
> +
> +static struct clk_regmap a9_ao_rtc_dualdiv_in = {
> + .data = &(struct clk_regmap_gate_data){
> + .offset = AO_RTC_BY_OSCIN_CTRL0,
> + .bit_idx = 31,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "ao_rtc_duandiv_in",
s/duandiv/dualdiv/ ?
Brian
^ permalink raw reply
* Re: [PATCH 09/10] clk: amlogic: Add A9 peripherals clock controller driver
From: Brian Masney @ 2026-05-11 15:42 UTC (permalink / raw)
To: jian.hu
Cc: Michael Turquette, Stephen Boyd, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Neil Armstrong, Jerome Brunet, Xianwei Zhao,
Kevin Hilman, Martin Blumenstingl, linux-kernel, linux-clk,
devicetree, linux-amlogic, linux-arm-kernel
In-Reply-To: <20260511-b4-a9_clk-v1-9-41cb4071b7c9@amlogic.com>
Hi Jian,
On Mon, May 11, 2026 at 08:47:31PM +0800, Jian Hu via B4 Relay wrote:
> From: Jian Hu <jian.hu@amlogic.com>
>
> Add the peripherals clock controller driver for the Amlogic A9 SoC family.
>
> Signed-off-by: Jian Hu <jian.hu@amlogic.com>
> ---
> drivers/clk/meson/Kconfig | 15 +
> drivers/clk/meson/Makefile | 1 +
> drivers/clk/meson/a9-peripherals.c | 2317 ++++++++++++++++++++++++++++++++++++
> 3 files changed, 2333 insertions(+)
>
> diff --git a/drivers/clk/meson/Kconfig b/drivers/clk/meson/Kconfig
> index 3549e67d6988..48a15a5e1323 100644
> --- a/drivers/clk/meson/Kconfig
> +++ b/drivers/clk/meson/Kconfig
> @@ -145,6 +145,21 @@ config COMMON_CLK_A9_PLL
> device, AKA A9. PLLs are required by most peripheral to operate.
> Say Y if you want A9 PLL clock controller to work.
>
> +config COMMON_CLK_A9_PERIPHERALS
> + tristate "Amlogic A9 SoC peripherals clock controller support"
> + depends on ARM64
depends on ARM64 || COMPILE_TEST
> + default ARCH_MESON
> + select COMMON_CLK_MESON_REGMAP
> + select COMMON_CLK_MESON_CLKC_UTILS
> + select COMMON_CLK_MESON_DUALDIV
> + select COMMON_CLK_MESON_VID_PLL_DIV
> + imply COMMON_CLK_SCMI
> + imply COMMON_CLK_A9_PLL
> + help
> + Support for the peripherals clock controller on Amlogic A311Y3 based
> + device, AKA A9. Peripherals are required by most peripheral to operate.
> + Say Y if you want A9 peripherals clock controller to work.
> +
> config COMMON_CLK_C3_PLL
> tristate "Amlogic C3 PLL clock controller"
> depends on ARM64
> diff --git a/drivers/clk/meson/Makefile b/drivers/clk/meson/Makefile
> index 77636033061f..2b5b67b14efc 100644
> --- a/drivers/clk/meson/Makefile
> +++ b/drivers/clk/meson/Makefile
> @@ -20,6 +20,7 @@ obj-$(CONFIG_COMMON_CLK_AXG_AUDIO) += axg-audio.o
> obj-$(CONFIG_COMMON_CLK_A1_PLL) += a1-pll.o
> obj-$(CONFIG_COMMON_CLK_A1_PERIPHERALS) += a1-peripherals.o
> obj-$(CONFIG_COMMON_CLK_A9_PLL) += a9-pll.o
> +obj-$(CONFIG_COMMON_CLK_A9_PERIPHERALS) += a9-peripherals.o
> obj-$(CONFIG_COMMON_CLK_C3_PLL) += c3-pll.o
> obj-$(CONFIG_COMMON_CLK_C3_PERIPHERALS) += c3-peripherals.o
> obj-$(CONFIG_COMMON_CLK_GXBB) += gxbb.o gxbb-aoclk.o
> diff --git a/drivers/clk/meson/a9-peripherals.c b/drivers/clk/meson/a9-peripherals.c
> new file mode 100644
> index 000000000000..338a91c473ea
> --- /dev/null
> +++ b/drivers/clk/meson/a9-peripherals.c
> @@ -0,0 +1,2317 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR MIT)
> +/*
> + * Copyright (C) 2026 Amlogic, Inc. All rights reserved
> + */
> +
> +#include <linux/clk-provider.h>
> +#include <linux/platform_device.h>
> +#include <dt-bindings/clock/amlogic,a9-peripherals-clkc.h>
> +#include "clk-regmap.h"
> +#include "clk-dualdiv.h"
> +#include "vid-pll-div.h"
> +#include "meson-clkc-utils.h"
Sort the headers.
> +
> +#define SYS_CLK_EN0_REG0 0x30
> +#define SYS_CLK_EN0_REG1 0x34
> +#define SYS_CLK_EN0_REG2 0x38
> +#define SYS_CLK_EN0_REG3 0x3c
> +#define SD_EMMC_CLK_CTRL0 0x90
> +#define SD_EMMC_CLK_CTRL1 0x94
> +#define PWM_CLK_H_CTRL 0xbc
> +#define PWM_CLK_I_CTRL 0xc0
> +#define PWM_CLK_J_CTRL 0xc4
> +#define PWM_CLK_K_CTRL 0xc8
> +#define PWM_CLK_L_CTRL 0xcc
> +#define PWM_CLK_M_CTRL 0xd0
> +#define PWM_CLK_N_CTRL 0xd4
> +#define SPISG_CLK_CTRL 0x100
> +#define SPISG_CLK_CTRL1 0x104
> +#define SAR_CLK_CTRL 0x150
> +#define AMFC_CLK_CTRL 0x154
> +#define NNA_CLK_CTRL 0x15c
> +#define USB_CLK_CTRL 0x160
> +#define PCIE_TL_CLK_CTRL 0x164
> +#define CMPR_CLK_CTRL 0x168
> +#define DEWARP_CLK_CTRL 0x16c
> +#define SC_CLK_CTRL 0x170
> +#define DPTX_CLK_CTRL 0x178
> +#define ISP_CLK_CTRL 0x17c
> +#define CVE_CLK_CTRL 0x180
> +#define PP_CLK_CTRL 0x184
> +#define GLB_CLK_CTRL 0x188
> +#define USB_CLK_CTRL0 0x18c
> +#define USB_CLK_CTRL1 0x190
> +#define CAN_CLK_CTRL 0x194
> +#define CAN_CLK_CTRL1 0x198
> +#define I3C_CLK_CTRL 0x19c
> +#define TS_CLK_CTRL 0x1a0
> +#define ETH_CLK_CTRL 0x1a4
> +#define GEN_CLK_CTRL 0x1a8
> +#define CLK12_24_CTRL 0x1ac
> +#define MALI_CLK_CTRL 0x200
> +#define MALI_STACK_CLK_CTRL 0x204
> +#define DSPA_CLK_CTRL 0x220
> +#define HEVCF_CLK_CTRL 0x240
> +#define HCODEC_CLK_CTRL 0x244
> +#define VPU_CLK_CTRL 0x260
> +#define VAPB_CLK_CTRL 0x268
> +#define VPU_CLKB_CTRL 0x280
> +#define HDMI_CLK_CTRL 0x284
> +#define HTX_CLK_CTRL 0x28c
> +#define HTX_CLK_CTRL1 0x290
> +#define HRX_CLK_CTRL 0x294
> +#define HRX_CLK_CTRL1 0x298
> +#define HRX_CLK_CTRL2 0x29c
> +#define HRX_CLK_CTRL3 0x2a0
> +#define VID_LOCK_CLK_CTRL 0x2a4
> +#define VDIN_MEAS_CLK_CTRL 0x2a8
> +#define VID_PLL_CLK_DIV 0x2b0
> +#define VID_CLK_CTRL 0x2c0
> +#define VID_CLK_CTRL2 0x2c4
> +#define VID_CLK_DIV 0x2c8
> +#define VIID_CLK_DIV 0x2cc
> +#define VIID_CLK_CTRL 0x2d0
> +#define MIPI_CSI_PHY_CLK_CTRL 0x2e0
> +#define DSI_MEAS_CLK_CTRL 0x2f4
> +
> +#define A9_COMP_SEL(_name, _reg, _shift, _mask, _pdata, _table) \
> + MESON_COMP_SEL(a9_, _name, _reg, _shift, _mask, _pdata, _table, 0, 0)
> +
> +#define A9_COMP_DIV(_name, _reg, _shift, _width) \
> + MESON_COMP_DIV(a9_, _name, _reg, _shift, _width, 0, CLK_SET_RATE_PARENT)
> +
> +#define A9_COMP_GATE(_name, _reg, _bit, _iflags) \
> + MESON_COMP_GATE(a9_, _name, _reg, _bit, CLK_SET_RATE_PARENT | (_iflags))
> +
> +static const struct clk_parent_data a9_sys_pclk_parents = { .fw_name = "sys" };
> +
> +#define A9_SYS_PCLK(_name, _reg, _bit) \
> + MESON_PCLK(a9_##_name, _reg, _bit, &a9_sys_pclk_parents, 0)
> +
> +static A9_SYS_PCLK(sys_am_axi, SYS_CLK_EN0_REG0, 0);
> +static A9_SYS_PCLK(sys_dos, SYS_CLK_EN0_REG0, 1);
> +static A9_SYS_PCLK(sys_mipi_dsi, SYS_CLK_EN0_REG0, 3);
> +static A9_SYS_PCLK(sys_eth_phy, SYS_CLK_EN0_REG0, 4);
> +static A9_SYS_PCLK(sys_amfc, SYS_CLK_EN0_REG0, 5);
> +static A9_SYS_PCLK(sys_mali, SYS_CLK_EN0_REG0, 6);
> +static A9_SYS_PCLK(sys_nna, SYS_CLK_EN0_REG0, 7);
> +static A9_SYS_PCLK(sys_eth_axi, SYS_CLK_EN0_REG0, 8);
> +static A9_SYS_PCLK(sys_dp_apb, SYS_CLK_EN0_REG0, 9);
> +static A9_SYS_PCLK(sys_edptx_apb, SYS_CLK_EN0_REG0, 10);
> +static A9_SYS_PCLK(sys_u3hsg, SYS_CLK_EN0_REG0, 11);
> +static A9_SYS_PCLK(sys_aucpu, SYS_CLK_EN0_REG0, 14);
> +static A9_SYS_PCLK(sys_glb, SYS_CLK_EN0_REG0, 15);
> +static A9_SYS_PCLK(sys_combo_dphy_apb, SYS_CLK_EN0_REG0, 17);
> +static A9_SYS_PCLK(sys_hdmirx_apb, SYS_CLK_EN0_REG0, 18);
> +static A9_SYS_PCLK(sys_hdmirx_pclk, SYS_CLK_EN0_REG0, 19);
> +static A9_SYS_PCLK(sys_mipi_dsi_phy, SYS_CLK_EN0_REG0, 20);
> +static A9_SYS_PCLK(sys_can0, SYS_CLK_EN0_REG0, 21);
> +static A9_SYS_PCLK(sys_can1, SYS_CLK_EN0_REG0, 22);
> +static A9_SYS_PCLK(sys_sd_emmc_a, SYS_CLK_EN0_REG0, 24);
> +static A9_SYS_PCLK(sys_sd_emmc_b, SYS_CLK_EN0_REG0, 25);
> +static A9_SYS_PCLK(sys_sd_emmc_c, SYS_CLK_EN0_REG0, 26);
> +static A9_SYS_PCLK(sys_sc, SYS_CLK_EN0_REG0, 27);
> +static A9_SYS_PCLK(sys_acodec, SYS_CLK_EN0_REG0, 28);
> +static A9_SYS_PCLK(sys_mipi_isp, SYS_CLK_EN0_REG0, 29);
> +static A9_SYS_PCLK(sys_msr, SYS_CLK_EN0_REG0, 30);
> +static A9_SYS_PCLK(sys_audio, SYS_CLK_EN0_REG1, 0);
> +static A9_SYS_PCLK(sys_mipi_dsi_b, SYS_CLK_EN0_REG1, 1);
> +static A9_SYS_PCLK(sys_mipi_dsi1_phy, SYS_CLK_EN0_REG1, 2);
> +static A9_SYS_PCLK(sys_eth, SYS_CLK_EN0_REG1, 3);
> +static A9_SYS_PCLK(sys_eth_1g_mac, SYS_CLK_EN0_REG1, 4);
> +static A9_SYS_PCLK(sys_uart_a, SYS_CLK_EN0_REG1, 5);
> +static A9_SYS_PCLK(sys_uart_f, SYS_CLK_EN0_REG1, 10);
> +static A9_SYS_PCLK(sys_ts_a55, SYS_CLK_EN0_REG1, 11);
> +static A9_SYS_PCLK(sys_eth_1g_axi, SYS_CLK_EN0_REG1, 12);
> +static A9_SYS_PCLK(sys_ts_dos, SYS_CLK_EN0_REG1, 13);
> +static A9_SYS_PCLK(sys_u3drd_b, SYS_CLK_EN0_REG1, 14);
> +static A9_SYS_PCLK(sys_ts_core, SYS_CLK_EN0_REG1, 15);
> +static A9_SYS_PCLK(sys_ts_pll, SYS_CLK_EN0_REG1, 16);
> +static A9_SYS_PCLK(sys_csi_dig_clkin, SYS_CLK_EN0_REG1, 18);
> +static A9_SYS_PCLK(sys_cve, SYS_CLK_EN0_REG1, 19);
> +static A9_SYS_PCLK(sys_ge2d, SYS_CLK_EN0_REG1, 20);
> +static A9_SYS_PCLK(sys_spisg, SYS_CLK_EN0_REG1, 21);
> +static A9_SYS_PCLK(sys_u3drd_1, SYS_CLK_EN0_REG1, 22);
> +static A9_SYS_PCLK(sys_u2h, SYS_CLK_EN0_REG1, 23);
> +static A9_SYS_PCLK(sys_pcie_mac_a, SYS_CLK_EN0_REG1, 24);
> +static A9_SYS_PCLK(sys_u3drd_a, SYS_CLK_EN0_REG1, 25);
> +static A9_SYS_PCLK(sys_u2drd, SYS_CLK_EN0_REG1, 26);
> +static A9_SYS_PCLK(sys_pcie_phy, SYS_CLK_EN0_REG1, 27);
> +static A9_SYS_PCLK(sys_pcie_mac_b, SYS_CLK_EN0_REG1, 28);
> +static A9_SYS_PCLK(sys_periph, SYS_CLK_EN0_REG1, 29);
> +static A9_SYS_PCLK(sys_pio, SYS_CLK_EN0_REG2, 0);
> +static A9_SYS_PCLK(sys_i3c, SYS_CLK_EN0_REG2, 1);
> +static A9_SYS_PCLK(sys_i2c_m_e, SYS_CLK_EN0_REG2, 2);
> +static A9_SYS_PCLK(sys_i2c_m_f, SYS_CLK_EN0_REG2, 3);
> +static A9_SYS_PCLK(sys_hdmitx_apb, SYS_CLK_EN0_REG2, 4);
> +static A9_SYS_PCLK(sys_i2c_m_i, SYS_CLK_EN0_REG2, 5);
> +static A9_SYS_PCLK(sys_i2c_m_g, SYS_CLK_EN0_REG2, 6);
> +static A9_SYS_PCLK(sys_i2c_m_h, SYS_CLK_EN0_REG2, 7);
> +static A9_SYS_PCLK(sys_hdmi20_aes, SYS_CLK_EN0_REG2, 9);
> +static A9_SYS_PCLK(sys_csi2_host, SYS_CLK_EN0_REG2, 16);
> +static A9_SYS_PCLK(sys_csi2_adapt, SYS_CLK_EN0_REG2, 17);
> +static A9_SYS_PCLK(sys_dspa, SYS_CLK_EN0_REG2, 21);
> +static A9_SYS_PCLK(sys_pp_dma, SYS_CLK_EN0_REG2, 22);
> +static A9_SYS_PCLK(sys_pp_wrapper, SYS_CLK_EN0_REG2, 23);
> +static A9_SYS_PCLK(sys_vpu_intr, SYS_CLK_EN0_REG2, 25);
> +static A9_SYS_PCLK(sys_csi2_phy, SYS_CLK_EN0_REG2, 27);
> +static A9_SYS_PCLK(sys_saradc, SYS_CLK_EN0_REG2, 28);
> +static A9_SYS_PCLK(sys_pwm_j, SYS_CLK_EN0_REG2, 30);
> +static A9_SYS_PCLK(sys_pwm_i, SYS_CLK_EN0_REG2, 31);
> +static A9_SYS_PCLK(sys_pwm_h, SYS_CLK_EN0_REG3, 0);
> +static A9_SYS_PCLK(sys_pwm_n, SYS_CLK_EN0_REG3, 8);
> +static A9_SYS_PCLK(sys_pwm_m, SYS_CLK_EN0_REG3, 9);
> +static A9_SYS_PCLK(sys_pwm_l, SYS_CLK_EN0_REG3, 10);
> +static A9_SYS_PCLK(sys_pwm_k, SYS_CLK_EN0_REG3, 11);
> +
> +/* Channel 5 is unconnected. */
> +static u32 a9_sd_emmc_parents_val_table[] = { 0, 1, 2, 3, 4, 6, 7 };
> +static const struct clk_parent_data a9_sd_emmc_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "gp1", },
> + { .fw_name = "gp0", }
> +};
> +
> +static A9_COMP_SEL(sd_emmc_a, SD_EMMC_CLK_CTRL0, 9, 0x7, a9_sd_emmc_parents,
> + a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_a, SD_EMMC_CLK_CTRL0, 0, 7);
> +static A9_COMP_GATE(sd_emmc_a, SD_EMMC_CLK_CTRL0, 8, 0);
> +
> +static A9_COMP_SEL(sd_emmc_b, SD_EMMC_CLK_CTRL0, 25, 0x7, a9_sd_emmc_parents,
> + a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_b, SD_EMMC_CLK_CTRL0, 16, 7);
> +static A9_COMP_GATE(sd_emmc_b, SD_EMMC_CLK_CTRL0, 24, 0);
> +
> +static A9_COMP_SEL(sd_emmc_c, SD_EMMC_CLK_CTRL1, 9, 0x7, a9_sd_emmc_parents,
> + a9_sd_emmc_parents_val_table);
> +static A9_COMP_DIV(sd_emmc_c, SD_EMMC_CLK_CTRL1, 0, 7);
> +static A9_COMP_GATE(sd_emmc_c, SD_EMMC_CLK_CTRL1, 8, 0);
> +
> +static const struct clk_parent_data a9_pwm_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", }
> +};
> +
> +static A9_COMP_SEL(pwm_h, PWM_CLK_H_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_h, PWM_CLK_H_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_h, PWM_CLK_H_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_i, PWM_CLK_I_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_i, PWM_CLK_I_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_i, PWM_CLK_I_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_j, PWM_CLK_J_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_j, PWM_CLK_J_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_j, PWM_CLK_J_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_k, PWM_CLK_K_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_k, PWM_CLK_K_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_k, PWM_CLK_K_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_l, PWM_CLK_L_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_l, PWM_CLK_L_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_l, PWM_CLK_L_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_m, PWM_CLK_M_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_m, PWM_CLK_M_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_m, PWM_CLK_M_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pwm_n, PWM_CLK_N_CTRL, 9, 0x7, a9_pwm_parents, NULL);
> +static A9_COMP_DIV(pwm_n, PWM_CLK_N_CTRL, 0, 8);
> +static A9_COMP_GATE(pwm_n, PWM_CLK_N_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_spisg_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "sys", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "gp0", }
> +};
> +
> +static A9_COMP_SEL(spisg, SPISG_CLK_CTRL, 9, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg, SPISG_CLK_CTRL, 0, 6);
> +static A9_COMP_GATE(spisg, SPISG_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(spisg1, SPISG_CLK_CTRL, 25, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg1, SPISG_CLK_CTRL, 16, 6);
> +static A9_COMP_GATE(spisg1, SPISG_CLK_CTRL, 24, 0);
> +
> +static A9_COMP_SEL(spisg2, SPISG_CLK_CTRL1, 9, 0x7, a9_spisg_parents, NULL);
> +static A9_COMP_DIV(spisg2, SPISG_CLK_CTRL1, 0, 6);
> +static A9_COMP_GATE(spisg2, SPISG_CLK_CTRL1, 8, 0);
> +
> +static const struct clk_parent_data a9_saradc_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "sys", }
> +};
> +
> +static A9_COMP_SEL(saradc, SAR_CLK_CTRL, 9, 0x7, a9_saradc_parents, NULL);
> +static A9_COMP_DIV(saradc, SAR_CLK_CTRL, 0, 8);
> +static A9_COMP_GATE(saradc, SAR_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_amfc_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "sys", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", }
> +};
> +
> +static A9_COMP_SEL(amfc, AMFC_CLK_CTRL, 9, 0x7, a9_amfc_parents, NULL);
> +static A9_COMP_DIV(amfc, AMFC_CLK_CTRL, 0, 6);
> +static A9_COMP_GATE(amfc, AMFC_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_nna_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "gp2", },
> + { .fw_name = "hifi", }
hifi isn't in the dt bindings. Should this be hifi0 and/or hifi1?
> +};
> +
> +static A9_COMP_SEL(nna, NNA_CLK_CTRL, 9, 0x7, a9_nna_parents, NULL);
> +static A9_COMP_DIV(nna, NNA_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(nna, NNA_CLK_CTRL, 8, 0);
> +
> +/* Channel 5 and 6 are unconnected. */
> +static u32 a9_usb_250m_parents_val_table[] = { 0, 1, 2, 3, 4, 7 };
> +static const struct clk_parent_data a9_usb_250m_parents[] = {
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "fdiv2p5", }
> +};
> +
> +static A9_COMP_SEL(usb_250m, USB_CLK_CTRL, 9, 0x7, a9_usb_250m_parents,
> + a9_usb_250m_parents_val_table);
> +static A9_COMP_DIV(usb_250m, USB_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(usb_250m, USB_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_usb_48m_pre_parents[] = {
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "fdiv2p5", }
> +};
> +
> +static A9_COMP_SEL(usb_48m_pre, USB_CLK_CTRL, 25, 0x7, a9_usb_48m_pre_parents,
> + NULL);
> +static A9_COMP_DIV(usb_48m_pre, USB_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(usb_48m_pre, USB_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_pcie_tl_parents[] = {
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "gp0", },
> + { .fw_name = "sys", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(pcie_tl, PCIE_TL_CLK_CTRL, 9, 0x7, a9_pcie_tl_parents,
> + NULL);
> +static A9_COMP_DIV(pcie_tl, PCIE_TL_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(pcie_tl, PCIE_TL_CLK_CTRL, 8, 0);
> +
> +static A9_COMP_SEL(pcie1_tl, PCIE_TL_CLK_CTRL, 25, 0x7, a9_pcie_tl_parents,
> + NULL);
> +static A9_COMP_DIV(pcie1_tl, PCIE_TL_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(pcie1_tl, PCIE_TL_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_cmpr_parents[] = {
> + { .fw_name = "xtal", },
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "gp1", }
> +};
> +
> +static A9_COMP_SEL(cmpr, CMPR_CLK_CTRL, 25, 0x7, a9_cmpr_parents, NULL);
> +static A9_COMP_DIV(cmpr, CMPR_CLK_CTRL, 16, 7);
> +static A9_COMP_GATE(cmpr, CMPR_CLK_CTRL, 24, 0);
> +
> +static const struct clk_parent_data a9_dewarpa_parents[] = {
> + { .fw_name = "fdiv2p5", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv4", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "fdiv7", },
> + { .fw_name = "gp0", },
> + { .fw_name = "hifi0", },
> + { .fw_name = "gp1", }
> +};
> +
> +static A9_COMP_SEL(dewarpa, DEWARP_CLK_CTRL, 9, 0x7, a9_dewarpa_parents, NULL);
> +static A9_COMP_DIV(dewarpa, DEWARP_CLK_CTRL, 0, 7);
> +static A9_COMP_GATE(dewarpa, DEWARP_CLK_CTRL, 8, 0);
> +
> +static const struct clk_parent_data a9_sc_parents[] = {
> + { .fw_name = "fdiv2", },
> + { .fw_name = "fdiv3", },
> + { .fw_name = "fdiv5", },
> + { .fw_name = "xtal", }
> +};
> +
> +static A9_COMP_SEL(sc_pre, SC_CLK_CTRL, 9, 0x7, a9_sc_parents, NULL);
> +static A9_COMP_DIV(sc_pre, SC_CLK_CTRL, 0, 8);
> +static A9_COMP_GATE(sc_pre, SC_CLK_CTRL, 8, 0);
> +
> +static struct clk_regmap a9_sc = {
> + .data = &(struct clk_regmap_div_data) {
> + .offset = SC_CLK_CTRL,
> + .shift = 16,
> + .width = 4,
> + },
> + .hw.init = &(struct clk_init_data) {
> + .name = "sc",
> + .ops = &clk_regmap_divider_ops,
> + .parent_hws = (const struct clk_hw *[]) {
> + &a9_sc_pre.hw
> + },
> + .num_parents = 1,
> + .flags = CLK_SET_RATE_PARENT,
> + },
You can use CLK_HW_INIT_HWS() here.
Brian
^ permalink raw reply
* [PATCH v3 5/5] arm64: mpam: Add memory bandwidth usage (MBWU) documentation
From: Ben Horgan @ 2026-05-11 15:41 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jonathan.cameron, kobak,
lcherian, linux-arm-kernel, linux-kernel, peternewman,
punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
sdonthineni, tan.shaopeng, xhao, zengheng4, x86
In-Reply-To: <20260511154147.557481-1-ben.horgan@arm.com>
Memory bandwidth monitoring make uses of MBWU monitors and is now exposed
to the user via resctrl. Add some documentation so the user knows what to
expect.
Co-developed-by: James Morse <james.morse@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Documentation/arch/arm64/mpam.rst | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/Documentation/arch/arm64/mpam.rst b/Documentation/arch/arm64/mpam.rst
index 570f51a8d4eb..208ff17068c4 100644
--- a/Documentation/arch/arm64/mpam.rst
+++ b/Documentation/arch/arm64/mpam.rst
@@ -65,6 +65,23 @@ The supported features are:
there is at least one CSU monitor on each MSC that makes up the L3 group.
Exposing CSU counters from other caches or devices is not supported.
+* Memory Bandwidth Usage (MBWU) on or after the L3 cache. resctrl uses the
+ L3 cache-id to identify where the memory bandwidth is measured. For this
+ reason the platform must have an L3 cache with cache-id's supplied by
+ firmware. (It doesn't need to support MPAM.)
+
+ Memory bandwidth monitoring makes use of MBWU monitors in each MSC that
+ makes up the L3 group. If the memory bandwidth monitoring is on the memory
+ rather than the L3 then there must be a single global L3 as otherwise it
+ is unknown which L3 the traffic came from.
+
+ To expose 'mbm_total_bytes', the topology of the group of MSC chosen must
+ match the topology of the L3 cache so that the cache-id's can be
+ repainted. For example: Platforms with Memory bandwidth monitors on
+ CPU-less NUMA nodes cannot expose 'mbm_total_bytes' as these nodes do not
+ have a corresponding L3 cache. 'mbm_local_bytes' is not exposed as MPAM
+ cannot distinguish local traffic from global traffic.
+
Reporting Bugs
==============
If you are not seeing the counters or controls you expect please share the
--
2.43.0
^ permalink raw reply related
* [PATCH v3 4/5] arm_mpam: resctrl: Add resctrl_arch_cntr_read() & resctrl_arch_reset_cntr()
From: Ben Horgan @ 2026-05-11 15:41 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jonathan.cameron, kobak,
lcherian, linux-arm-kernel, linux-kernel, peternewman,
punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
sdonthineni, tan.shaopeng, xhao, zengheng4, x86
In-Reply-To: <20260511154147.557481-1-ben.horgan@arm.com>
From: James Morse <james.morse@arm.com>
When used in 'mbm_event' mode, ABMC emulation, resctrl uses arch hooks to
read and reset the memory bandwidth utilization (MBWU) counters.
Add these.
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 __reset_mon() and reset_mon_cdp_safe() helpers here
support mbwu in __read_mon()
Mention mbm_event mode in commit message
---
drivers/resctrl/mpam_resctrl.c | 99 +++++++++++++++++++++++++++++-----
1 file changed, 86 insertions(+), 13 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 5e70b0f822c9..08eb05031ffc 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -121,19 +121,6 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d
{
}
-void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
- u32 closid, u32 rmid, int cntr_id,
- enum resctrl_event_id eventid)
-{
-}
-
-int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
- u32 unused, u32 rmid, int cntr_id,
- enum resctrl_event_id eventid, u64 *val)
-{
- return -EOPNOTSUPP;
-}
-
bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
{
return (r == &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res);
@@ -467,6 +454,14 @@ static int __read_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_c
/* Shift closid to account for CDP */
closid = resctrl_get_config_index(closid, cdp_type);
+ if (mon_idx == USE_PRE_ALLOCATED) {
+ int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
+ mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
+ if (mon_idx == -1)
+ return -ENOENT;
+ }
+
if (irqs_disabled()) {
/* Check if we can access this domain without an IPI */
return -EIO;
@@ -539,6 +534,84 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
closid, rmid, val);
}
+/* MBWU counters when in ABMC mode */
+int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ u32 closid, u32 rmid, int mon_idx,
+ enum resctrl_event_id eventid, u64 *val)
+{
+ struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+ struct mpam_resctrl_dom *l3_dom;
+ struct mpam_component *mon_comp;
+
+ if (!mpam_is_enabled())
+ return -EINVAL;
+
+ if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+ return -EINVAL;
+
+ l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+ mon_comp = l3_dom->mon_comp[eventid];
+
+ return read_mon_cdp_safe(mon, mon_comp, mpam_feat_msmon_mbwu, mon_idx,
+ closid, rmid, val);
+}
+
+static void __reset_mon(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+ int mon_idx,
+ enum resctrl_conf_type cdp_type, u32 closid, u32 rmid)
+{
+ struct mon_cfg cfg = { };
+
+ if (!mpam_is_enabled())
+ return;
+
+ /* Shift closid to account for CDP */
+ closid = resctrl_get_config_index(closid, cdp_type);
+
+ if (mon_idx == USE_PRE_ALLOCATED) {
+ int mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+
+ mon_idx = mon->mbwu_idx_to_mon[mbwu_idx];
+ }
+
+ if (mon_idx == -1)
+ return;
+ cfg.mon = mon_idx;
+ mpam_msmon_reset_mbwu(mon_comp, &cfg);
+}
+
+static void reset_mon_cdp_safe(struct mpam_resctrl_mon *mon, struct mpam_component *mon_comp,
+ int mon_idx, u32 closid, u32 rmid)
+{
+ if (cdp_enabled) {
+ __reset_mon(mon, mon_comp, mon_idx, CDP_CODE, closid, rmid);
+ __reset_mon(mon, mon_comp, mon_idx, CDP_DATA, closid, rmid);
+ } else {
+ __reset_mon(mon, mon_comp, mon_idx, CDP_NONE, closid, rmid);
+ }
+}
+
+/* Reset an assigned counter */
+void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ u32 closid, u32 rmid, int cntr_id,
+ enum resctrl_event_id eventid)
+{
+ struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[eventid];
+ struct mpam_resctrl_dom *l3_dom;
+ struct mpam_component *mon_comp;
+
+ if (!mpam_is_enabled())
+ return;
+
+ if (eventid == QOS_L3_OCCUP_EVENT_ID || !mon->class)
+ return;
+
+ l3_dom = container_of(d, struct mpam_resctrl_dom, resctrl_mon_dom);
+ mon_comp = l3_dom->mon_comp[eventid];
+
+ reset_mon_cdp_safe(mon, mon_comp, USE_PRE_ALLOCATED, closid, rmid);
+}
+
/*
* The rmid realloc threshold should be for the smallest cache exposed to
* resctrl.
--
2.43.0
^ permalink raw reply related
* [PATCH v3 3/5] arm_mpam: resctrl: Add resctrl_arch_config_cntr() for ABMC use
From: Ben Horgan @ 2026-05-11 15:41 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jonathan.cameron, kobak,
lcherian, linux-arm-kernel, linux-kernel, peternewman,
punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
sdonthineni, tan.shaopeng, xhao, zengheng4, x86
In-Reply-To: <20260511154147.557481-1-ben.horgan@arm.com>
From: James Morse <james.morse@arm.com>
ABMC, mbm_event mode, has a helper resctrl_arch_config_cntr() for changing
the mapping between 'cntr_id' and a CLOSID/RMID pair.
Add the helper.
For MPAM this is done by updating the mon->mbwu_idx_to_mon[] array, and as
usual CDP means it needs doing in three different ways.
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 new rfc:
Mention mbm_event mode in commit message
---
drivers/resctrl/mpam_resctrl.c | 43 +++++++++++++++++++++++++++++-----
1 file changed, 37 insertions(+), 6 deletions(-)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index cba295621f56..5e70b0f822c9 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -127,12 +127,6 @@ void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d
{
}
-void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
- enum resctrl_event_id evtid, u32 rmid, u32 closid,
- u32 cntr_id, bool assign)
-{
-}
-
int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
u32 unused, u32 rmid, int cntr_id,
enum resctrl_event_id eventid, u64 *val)
@@ -1080,6 +1074,43 @@ static void mpam_resctrl_pick_counters(void)
}
}
+static void __config_cntr(struct mpam_resctrl_mon *mon, u32 cntr_id,
+ enum resctrl_conf_type cdp_type, u32 closid, u32 rmid,
+ bool assign)
+{
+ u32 mbwu_idx, mon_idx = resctrl_get_config_index(cntr_id, cdp_type);
+
+ closid = resctrl_get_config_index(closid, cdp_type);
+ mbwu_idx = resctrl_arch_rmid_idx_encode(closid, rmid);
+ WARN_ON_ONCE(mon_idx > l3_num_allocated_mbwu);
+
+ if (assign)
+ mon->mbwu_idx_to_mon[mbwu_idx] = mon->assigned_counters[mon_idx];
+ else
+ mon->mbwu_idx_to_mon[mbwu_idx] = -1;
+}
+
+void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+ enum resctrl_event_id evtid, u32 rmid, u32 closid,
+ u32 cntr_id, bool assign)
+{
+ struct mpam_resctrl_mon *mon = &mpam_resctrl_counters[evtid];
+
+ if (!mon->mbwu_idx_to_mon || !mon->assigned_counters) {
+ pr_debug("monitor arrays not allocated\n");
+ return;
+ }
+
+ if (cdp_enabled) {
+ __config_cntr(mon, cntr_id, CDP_CODE, closid, rmid, assign);
+ __config_cntr(mon, cntr_id, CDP_DATA, closid, rmid, assign);
+ } else {
+ __config_cntr(mon, cntr_id, CDP_NONE, closid, rmid, assign);
+ }
+
+ resctrl_arch_reset_rmid(r, d, closid, rmid, evtid);
+}
+
static int mpam_resctrl_control_init(struct mpam_resctrl_res *res)
{
struct mpam_class *class = res->class;
--
2.43.0
^ permalink raw reply related
* [PATCH v3 2/5] arm_mpam: resctrl: Pre-allocate assignable monitors
From: Ben Horgan @ 2026-05-11 15:41 UTC (permalink / raw)
To: ben.horgan
Cc: amitsinght, baisheng.gao, baolin.wang, carl, dave.martin, david,
dfustini, fenghuay, gshan, james.morse, jonathan.cameron, kobak,
lcherian, linux-arm-kernel, linux-kernel, peternewman,
punit.agrawal, quic_jiles, reinette.chatre, rohit.mathew, scott,
sdonthineni, tan.shaopeng, xhao, zengheng4, x86
In-Reply-To: <20260511154147.557481-1-ben.horgan@arm.com>
MPAM is able to emulate ABMC, i.e. mbm_event mode, by making memory
bandwidth monitors assignable. Rather than supporting the 'default'
mbm_assign_mode always use 'mbm_event' mode even if there are sufficient
memory bandwidth monitors. The per monitor event configuration is only
provided by resctrl when in 'mbm_event' mode and so only allowing
'mbm_event' mode will make it easier to support per-monitor event
configuration for MPAM. For the moment, the only event supported is
mbm_total_event with no bandwidth type configuration. The 'mbm_assign_mode'
file will still show 'default' when there is no support for memory
bandwidth monitoring.
The monitors need to be allocated from the driver, and mapped to whichever
control/monitor group resctrl wants to use them with.
Add a second array to hold the monitor values indexed by resctrl's cntr_id.
When CDP is in use, two monitors are needed so the available number of
counters halves. Platforms with one monitor will have zero monitors when
CDP is in use.
Co-developed-by: James Morse <james.morse@arm.com>
Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Changes since rfc v1:
abmc enabled even if enough counters
Helpers from dropped free running commits
carry on with zero counters if using cdp
set config bits
use kmalloc_objs
drop tags for rework
Configure mbm_cntr_configurable, mbm_cntr_assign_fixed
Changes since rfc v2:
Don't set mon->assigned_counters to an error pointer
Fix mpam_resctrl_teardown_mon()
Remove free running check
Separate cleanup allocations, e.g. __free(), from the rest
Restrict scope on err in mpam_resctrl_monitor_init()
---
drivers/resctrl/mpam_internal.h | 6 +-
drivers/resctrl/mpam_resctrl.c | 138 +++++++++++++++++++++++++++++++-
2 files changed, 140 insertions(+), 4 deletions(-)
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 1914aefdcba9..7a166b395b5a 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -411,7 +411,11 @@ struct mpam_resctrl_res {
struct mpam_resctrl_mon {
struct mpam_class *class;
- /* per-class data that resctrl needs will live here */
+ /* Array of allocated MBWU monitors, indexed by (closid, rmid). */
+ int *mbwu_idx_to_mon;
+
+ /* Array of assigned MBWU monitors, indexed by idx argument. */
+ int *assigned_counters;
};
static inline int mpam_alloc_csu_mon(struct mpam_class *class)
diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index f70fa65d39e4..cba295621f56 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -75,6 +75,8 @@ static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
*/
static bool resctrl_enabled;
+static unsigned int l3_num_allocated_mbwu = ~0;
+
bool resctrl_arch_alloc_capable(void)
{
struct mpam_resctrl_res *res;
@@ -140,7 +142,7 @@ int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
{
- return false;
+ return (r == &mpam_resctrl_controls[RDT_RESOURCE_L3].resctrl_res);
}
int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
@@ -185,6 +187,22 @@ static void resctrl_reset_task_closids(void)
read_unlock(&tasklist_lock);
}
+static void mpam_resctrl_monitor_sync_abmc_vals(struct rdt_resource *l3)
+{
+ l3->mon.num_mbm_cntrs = l3_num_allocated_mbwu;
+ if (cdp_enabled)
+ l3->mon.num_mbm_cntrs /= 2;
+
+ /*
+ * Continue as normal even if there are zero counters to avoid giving
+ * resctrl mixed messages.
+ */
+ l3->mon.mbm_cntr_assignable = true;
+ l3->mon.mbm_assign_on_mkdir = true;
+ l3->mon.mbm_cntr_configurable = false;
+ l3->mon.mbm_cntr_assign_fixed = true;
+}
+
int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
{
u32 partid_i = RESCTRL_RESERVED_CLOSID, partid_d = RESCTRL_RESERVED_CLOSID;
@@ -244,6 +262,7 @@ int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
WRITE_ONCE(arm64_mpam_global_default, mpam_get_regval(current));
resctrl_reset_task_closids();
+ mpam_resctrl_monitor_sync_abmc_vals(l3);
for_each_possible_cpu(cpu)
mpam_set_cpu_defaults(cpu, partid_d, partid_i, 0, 0);
@@ -613,6 +632,9 @@ static bool class_has_usable_mbwu(struct mpam_class *class)
if (!mpam_has_feature(mpam_feat_msmon_mbwu, cprops))
return false;
+ if (!cprops->num_mbwu_mon)
+ return false;
+
return true;
}
@@ -935,6 +957,52 @@ static void mpam_resctrl_pick_mba(void)
}
}
+static void __free_mbwu_mon(struct mpam_class *class, int *array,
+ u16 num_mbwu_mon)
+{
+ for (int i = 0; i < num_mbwu_mon; i++) {
+ if (array[i] < 0)
+ continue;
+
+ mpam_free_mbwu_mon(class, array[i]);
+ array[i] = ~0;
+ }
+}
+
+static int __alloc_mbwu_mon(struct mpam_class *class, int *array,
+ u16 num_mbwu_mon)
+{
+ for (int i = 0; i < num_mbwu_mon; i++) {
+ int mbwu_mon = mpam_alloc_mbwu_mon(class);
+
+ if (mbwu_mon < 0) {
+ __free_mbwu_mon(class, array, num_mbwu_mon);
+ return mbwu_mon;
+ }
+ array[i] = mbwu_mon;
+ }
+
+ l3_num_allocated_mbwu = min(l3_num_allocated_mbwu, num_mbwu_mon);
+
+ return 0;
+}
+
+static int *__alloc_mbwu_array(struct mpam_class *class, u16 num_mbwu_mon)
+{
+ int err;
+
+ int *array __free(kfree) = kmalloc_objs(*array, num_mbwu_mon);
+ if (!array)
+ return ERR_PTR(-ENOMEM);
+
+ memset(array, -1, num_mbwu_mon * sizeof(*array));
+
+ err = __alloc_mbwu_mon(class, array, num_mbwu_mon);
+ if (err)
+ return ERR_PTR(err);
+ return_ptr(array);
+}
+
static void counter_update_class(enum resctrl_event_id evt_id,
struct mpam_class *class)
{
@@ -1089,6 +1157,38 @@ static int mpam_resctrl_pick_domain_id(int cpu, struct mpam_component *comp)
return comp->comp_id;
}
+/*
+ * This must run after all event counters have been picked so that any free
+ * running counters have already been allocated.
+ */
+static int mpam_resctrl_monitor_init_abmc(struct mpam_resctrl_mon *mon)
+{
+ struct mpam_resctrl_res *res = &mpam_resctrl_controls[RDT_RESOURCE_L3];
+ struct rdt_resource *l3 = &res->resctrl_res;
+ struct mpam_class *class = mon->class;
+ u16 num_mbwu_mon;
+ size_t num_rmid = resctrl_arch_system_num_rmid_idx();
+ int *cntrs;
+
+ int *rmid_array __free(kfree) = kmalloc_objs(*rmid_array, num_rmid);
+ if (!rmid_array) {
+ pr_debug("Failed to allocate RMID array\n");
+ return -ENOMEM;
+ }
+ memset(rmid_array, -1, num_rmid * sizeof(*rmid_array));
+
+ num_mbwu_mon = class->props.num_mbwu_mon;
+ cntrs = __alloc_mbwu_array(mon->class, num_mbwu_mon);
+ if (IS_ERR(cntrs))
+ return PTR_ERR(cntrs);
+ mon->assigned_counters = cntrs;
+ mon->mbwu_idx_to_mon = no_free_ptr(rmid_array);
+
+ mpam_resctrl_monitor_sync_abmc_vals(l3);
+
+ return 0;
+}
+
static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
enum resctrl_event_id type)
{
@@ -1133,8 +1233,21 @@ static int mpam_resctrl_monitor_init(struct mpam_resctrl_mon *mon,
*/
l3->mon.num_rmid = resctrl_arch_system_num_rmid_idx();
- if (resctrl_enable_mon_event(type, false, 0, NULL))
- l3->mon_capable = true;
+ if (type == QOS_L3_MBM_TOTAL_EVENT_ID) {
+ int err;
+
+ err = mpam_resctrl_monitor_init_abmc(mon);
+ if (err)
+ return err;
+
+ static_assert(MAX_EVT_CONFIG_BITS == 0x7f);
+ l3->mon.mbm_cfg_mask = MAX_EVT_CONFIG_BITS;
+ }
+
+ if (!resctrl_enable_mon_event(type, false, 0, NULL))
+ return -EINVAL;
+
+ l3->mon_capable = true;
return 0;
}
@@ -1697,6 +1810,23 @@ void mpam_resctrl_exit(void)
resctrl_exit();
}
+static void mpam_resctrl_teardown_mon(struct mpam_resctrl_mon *mon, struct mpam_class *class)
+{
+ u32 num_mbwu_mon = l3_num_allocated_mbwu;
+
+ if (mon->mbwu_idx_to_mon)
+ return;
+
+ if (mon->assigned_counters) {
+ __free_mbwu_mon(class, mon->assigned_counters, num_mbwu_mon);
+ kfree(mon->assigned_counters);
+ mon->assigned_counters = NULL;
+ }
+
+ kfree(mon->mbwu_idx_to_mon);
+ mon->mbwu_idx_to_mon = NULL;
+}
+
/*
* The driver is detaching an MSC from this class, if resctrl was using it,
* pull on resctrl_exit().
@@ -1719,6 +1849,8 @@ void mpam_resctrl_teardown_class(struct mpam_class *class)
for_each_mpam_resctrl_mon(mon, eventid) {
if (mon->class == class) {
mon->class = NULL;
+
+ mpam_resctrl_teardown_mon(mon, class);
break;
}
}
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox