Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 1/4] arm64: dts: ti: k3-am62a7-sk: Split r5f memory region
From: Markus Schneider-Pargmann (TI) @ 2026-04-29 13:22 UTC (permalink / raw)
  To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Suman Anna, Nishanth Menon,
	Vignesh Raghavendra, Tero Kristo
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-remoteproc, devicetree,
	linux-kernel, linux-arm-kernel, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260429-topic-am62a-ioddr-dt-v6-19-v4-0-fc27d6ac753c@baylibre.com>

Split the firmware memory region in more specific parts so it is better
described where to find which information. Specifically the LPM metadata
region is important as bootloader software like U-Boot has to know where
that data is to be able to read that data.

Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
 arch/arm64/boot/dts/ti/k3-am62a7-sk.dts | 40 +++++++++++++++++++++++++++++++--
 1 file changed, 38 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
index c1e9067b3bdd5ab0591541d4685bb17a5dac4f65..6f2ee93c7be141ee5ae3f1e3324d3a060db069f6 100644
--- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
@@ -59,9 +59,33 @@ wkup_r5fss0_core0_dma_memory_region: memory@9c800000 {
 			no-map;
 		};
 
-		wkup_r5fss0_core0_memory_region: memory@9c900000 {
+		wkup_r5fss0_core0_ipc_region: memory@9c900000 {
 			compatible = "shared-dma-pool";
-			reg = <0x00 0x9c900000 0x00 0xf00000>;
+			reg = <0x00 0x9c900000 0x00 0x100000>;
+			no-map;
+		};
+
+		wkup_r5fss0_core0_lpm_fs_stub_region: memory@9ca00000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0x9ca00000 0x00 0x8000>;
+			no-map;
+		};
+
+		wkup_r5fss0_core0_lpm_metadata_region: memory@9ca08000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0x9ca08000 0x00 0x1000>;
+			no-map;
+		};
+
+		wkup_r5fss0_core0_lpm_rest_region: memory@9ca09000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0x9ca09000 0x00 0x97000>;
+			no-map;
+		};
+
+		wkup_r5fss0_core0_dm_region: memory@9caa0000 {
+			compatible = "shared-dma-pool";
+			reg = <0x00 0x9caa0000 0x00 0xd60000>;
 			no-map;
 		};
 
@@ -933,3 +957,15 @@ &mcu_uart0 {
 };
 
 #include "k3-am62a-ti-ipc-firmware.dtsi"
+
+&wkup_r5fss0_core0 {
+	memory-region = <&wkup_r5fss0_core0_dma_memory_region>,
+			<&wkup_r5fss0_core0_ipc_region>,
+			<&wkup_r5fss0_core0_lpm_fs_stub_region>,
+			<&wkup_r5fss0_core0_lpm_metadata_region>,
+			<&wkup_r5fss0_core0_lpm_rest_region>,
+			<&wkup_r5fss0_core0_dm_region>;
+	memory-region-names = "dma", "ipc", "lpm-stub",
+			      "lpm-metadata", "lpm-context",
+			      "dm-firmware";
+};

-- 
2.53.0



^ permalink raw reply related

* [PATCH v4 4/4] arm64: dts: ti: k3-am62p5-sk: Add r5f nodes to pre-ram bootphase
From: Markus Schneider-Pargmann (TI) @ 2026-04-29 13:22 UTC (permalink / raw)
  To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Suman Anna, Nishanth Menon,
	Vignesh Raghavendra, Tero Kristo
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-remoteproc, devicetree,
	linux-kernel, linux-arm-kernel, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260429-topic-am62a-ioddr-dt-v6-19-v4-0-fc27d6ac753c@baylibre.com>

For IO+DDR the wkup_r5fss0_core0 and the
wkup_r5fss0_core0_lpm_metadata_region need to be accessed before RAM
setup is done. These are used to read the lpm metadata region in which
data is stored to resume. This needs to be done before RAM is in use to
avoid overwriting data.

Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
 arch/arm64/boot/dts/ti/k3-am62p5-sk.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
index e67489a178f2a2caedf1306e1c1c9dd6a95745e6..b4a4e427637bb4d5ca408d29234b95fe7e69d006 100644
--- a/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62p5-sk.dts
@@ -71,6 +71,7 @@ wkup_r5fss0_core0_lpm_metadata_region: memory@9ca08000 {
 			compatible = "shared-dma-pool";
 			reg = <0x00 0x9ca08000 0x00 0x1000>;
 			no-map;
+			bootph-pre-ram;
 		};
 
 		wkup_r5fss0_core0_lpm_rest_region: memory@9ca09000 {
@@ -879,4 +880,5 @@ &wkup_r5fss0_core0 {
 	memory-region-names = "dma", "ipc", "lpm-stub",
 			      "lpm-metadata", "lpm-context",
 			      "dm-firmware";
+	bootph-pre-ram;
 };

-- 
2.53.0



^ permalink raw reply related

* [PATCH v4 3/4] arm64: dts: ti: k3-am62a7-sk: Add r5f nodes to pre-ram bootphase
From: Markus Schneider-Pargmann (TI) @ 2026-04-29 13:22 UTC (permalink / raw)
  To: Bjorn Andersson, Mathieu Poirier, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Suman Anna, Nishanth Menon,
	Vignesh Raghavendra, Tero Kristo
  Cc: Vishal Mahaveer, Kevin Hilman, Dhruva Gole, Sebin Francis,
	Kendall Willis, Akashdeep Kaur, linux-remoteproc, devicetree,
	linux-kernel, linux-arm-kernel, Markus Schneider-Pargmann (TI)
In-Reply-To: <20260429-topic-am62a-ioddr-dt-v6-19-v4-0-fc27d6ac753c@baylibre.com>

For IO+DDR the wkup_r5fss0_core0 and the
wkup_r5fss0_core0_lpm_metadata_region need to be accessed before RAM
setup is done. These are used to read the lpm metadata region in which
data is stored to resume. This needs to be done before RAM is in use to
avoid overwriting data.

Signed-off-by: Markus Schneider-Pargmann (TI) <msp@baylibre.com>
---
 arch/arm64/boot/dts/ti/k3-am62a7-sk.dts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
index 6f2ee93c7be141ee5ae3f1e3324d3a060db069f6..5155f093437f35d815b2bf62429b57c9d8672290 100644
--- a/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
+++ b/arch/arm64/boot/dts/ti/k3-am62a7-sk.dts
@@ -75,6 +75,7 @@ wkup_r5fss0_core0_lpm_metadata_region: memory@9ca08000 {
 			compatible = "shared-dma-pool";
 			reg = <0x00 0x9ca08000 0x00 0x1000>;
 			no-map;
+			bootph-pre-ram;
 		};
 
 		wkup_r5fss0_core0_lpm_rest_region: memory@9ca09000 {
@@ -968,4 +969,5 @@ &wkup_r5fss0_core0 {
 	memory-region-names = "dma", "ipc", "lpm-stub",
 			      "lpm-metadata", "lpm-context",
 			      "dm-firmware";
+	bootph-pre-ram;
 };

-- 
2.53.0



^ permalink raw reply related

* Re: [PATCH v2] arm64: dts: ti: k3-j721s2-som-p0: add bootph-pre-ram property to PMIC-B
From: Kumar, Udit @ 2026-04-29 13:26 UTC (permalink / raw)
  To: Thomas Richard (TI), Nishanth Menon, Vignesh Raghavendra,
	Tero Kristo, Rob Herring, Krzysztof Kozlowski, Conor Dooley
  Cc: Thomas Petazzoni, linux-arm-kernel, devicetree, linux-kernel,
	gregory.clement, richard.genoud, a-kumar2
In-Reply-To: <20260429-k3-j721s2-som-bootph-pre-ram-pmic-4c-v2-1-31a0e7677216@bootlin.com>



On 4/29/2026 5:49 PM, Thomas Richard (TI) wrote:
> On j721s2, PMIC-B is needed to exit the DDR from retention after
> suspend-to-ram. Add bootph-pre-ram property to make PMIC-B available to
> the bootloader in the phase that sets up the DDR.
> 
> Signed-off-by: Thomas Richard (TI) <thomas.richard@bootlin.com>
> ---
> For the v2 I just updated the commit title and message to use PMIC-B
> instead of pmic@4c.
> ---
> Changes in v2:
> - replace pmic@4c by PMIC-B in commit message.
> - Link to v1: https://lore.kernel.org/r/20260428-k3-j721s2-som-bootph-pre-ram-pmic-4c-v1-1-e8202ce955a0@bootlin.com
> ---
>  arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi
> index 12a38dd1514b..a19e535f4946 100644
> --- a/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi
> +++ b/arch/arm64/boot/dts/ti/k3-j721s2-som-p0.dtsi
> @@ -250,6 +250,7 @@ buckb1: buck1 {
>  				regulator-max-microvolt = <1800000>;
>  				regulator-always-on;
>  				regulator-boot-on;
> +				bootph-pre-ram;

Reviewed-by: Udit Kumar <u-kumar1@ti.com>

>  			};
>  
>  			buckb2: buck2 {
> 
> ---
> base-commit: 59b04cb2325c07ddc1cc7d984bd8c8f89f161746
> change-id: 20260427-k3-j721s2-som-bootph-pre-ram-pmic-4c-744fb90b05a3
> 
> Best regards,



^ permalink raw reply

* Re: [RFC PATCH v2 1/4] security: ima: call ima_init() again at late_initcall_sync for defered TPM
From: Roberto Sassu @ 2026-04-29 13:33 UTC (permalink / raw)
  To: Paul Moore, Mimi Zohar
  Cc: Yeoreum Yun, roberto.sassu, Jonathan McDowell,
	linux-security-module, linux-kernel, linux-integrity,
	linux-arm-kernel, kvmarm, jmorris, serge, dmitry.kasatkin,
	eric.snowberg, jarkko, jgg, sudeep.holla, maz, oupton, joey.gouly,
	suzuki.poulose, yuzenghui, catalin.marinas, will, noodles,
	sebastianene
In-Reply-To: <CAHC9VhS_WgwhW_NDO91LoTeSzdieGqbwqnwPq8KpavH1_Lwi7g@mail.gmail.com>

On Mon, 2026-04-27 at 21:31 -0400, Paul Moore wrote:
> On Fri, Apr 24, 2026 at 6:49 PM Mimi Zohar <zohar@linux.ibm.com> wrote:
> > On Fri, 2026-04-24 at 18:10 -0400, Paul Moore wrote:
> > > (I'm assuming you meant initcall and not syscall above, but if you're
> > > talking about something else, please let me know.)
> > > 
> > > Saying that you aren't comfortable moving IMA initialization to
> > > late-sync is inconsistent with allowing IMA initialization to be
> > > deferred to late-sync.  Either it is okay to initialize IMA in
> > > late-sync or it isn't.  You must pick one.
> > 
> > Yes, we're discussing late_initcall and late_initcall_sync.
> > 
> > I prefer to look at it as being pragmatic. I'd rather err on the side of caution
> > and not move the syscall to late_initcall_sync, than move it.
> 
> If you were truly erring on the side of caution you wouldn't allow
> late-sync initialization without knowing if it was safe or not.
> Determine whether IMA initialization is safe at late-sync.  If it is
> safe, move the init to late-sync; if not, keep it at late and figure
> out another mechanism to sync with the TPM availability.  If needed,
> you could probably use the LSM notifier to enable the TPM driver to
> signal when it is up and running.

Yes, I agree with you, or transition or not.

However, all of this looks very fragile and easy to be broken. If we
want to be on the safe side, we can use any notification mechanism that
is suitable, but at the same time from IMA side we need to deny any
file access that would require a measurement until the TPM comes up.

If you accept this, I don't have any problem to move to late_sync.

Roberto



^ permalink raw reply

* Re: [DONOTAPPLY RFC PATCH v2 0/4] WiFi support for samsung,coreprimevelte
From: Francesco Dolcini @ 2026-04-29 13:40 UTC (permalink / raw)
  To: Karel Balej
  Cc: Francesco Dolcini, Brian Norris, Johannes Berg, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Duje Mihanović,
	Andrew Lunn, Gregory Clement, Sebastian Hesselbarth, Ulf Hansson,
	Frank Li, linux-wireless, devicetree, linux-kernel,
	linux-arm-kernel, linux-mmc, ~postmarketos/upstreaming,
	phone-devel, Jeff Chen, Peng Fan, david
In-Reply-To: <DI5O432AFZVX.3VGKJP31AZX97@matfyz.cz>

On Wed, Apr 29, 2026 at 03:20:28PM +0200, Karel Balej wrote:
> Francesco Dolcini, 2026-04-29T13:22:32+02:00:
> > On Wed, Apr 29, 2026 at 12:55:23PM +0200, Karel Balej wrote:
> >> without the firmware being in linux-firmware?
> >
> > What's the license of this firmware? Am I wrong saying that if
> > the license allows it, you could just send a patch to have it integrated
> > to the linux-firmware repository? Is there any history or documentation
> > on the topic (please apologize if this is a well known topic, just
> > answer RTFM if this is the case).
> 
> that's one of the issues, the license is not specified explicitly
> anywhere as far as I know.
That's enough to be blocked.

> As far as I know, even if I was to submit the firmware myself, it would
> still require a sign-off from someone from NXP [1].

And this is clearly there to avoid situation that are problematic from
a legal point of view.

I do not see any way forward without NXP.

Francesco

> [1] https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/about/#signed-off-by-requirement


^ permalink raw reply

* Re: [PATCH v4 11/15] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
From: Kevin Brodsky @ 2026-04-29 10:54 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-arm-kernel
  Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel,
	Ryan Roberts, Anshuman Khandual, Liz Prucka, Seth Jenkins,
	Kees Cook, Mike Rapoport, David Hildenbrand, Andrew Morton,
	linux-mm, linux-hardening
In-Reply-To: <20260427153416.2103979-28-ardb+git@google.com>

On 27/04/2026 17:34, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Now that the DRAM mapping routines respect existing table mappings and
> contiguous block and page mappings, it is no longer needed to fiddle
> with the memblock tables to set and clear the NOMAP attribute in order
> to omit text and rodata when creating the linear map.
>
> Instead, map the kernel text and rodata alias first with the desired
> attributes, so that they will not be remapped later with different
> attributes when mapping the memblocks.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  arch/arm64/mm/mmu.c | 24 +++++++-------------
>  1 file changed, 8 insertions(+), 16 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 5e2348b15783..1a4b4337d29a 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1148,12 +1148,15 @@ static void __init map_mem(void)
>  		flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
>  
>  	/*
> -	 * Take care not to create a writable alias for the
> -	 * read-only text and rodata sections of the kernel image.
> -	 * So temporarily mark them as NOMAP to skip mappings in
> -	 * the following for-loop
> +	 * Map the linear alias of the [_text, __init_begin) interval
> +	 * as non-executable now, and remove the write permission in
> +	 * mark_linear_text_alias_ro() above (which will be called after
> +	 * alternative patching has completed). This makes the contents
> +	 * of the region accessible to subsystems such as hibernate,
> +	 * but protects it from inadvertent modification or execution.
>  	 */
> -	memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
> +	__map_memblock(kernel_start, kernel_end, pgprot_tagged(PAGE_KERNEL),

Is it now necessary for that mapping to be tagged? If so, it should
probably be called out in the commit message.

- Kevin

> +		       flags);
>  
>  	/* map all the memory banks */
>  	for_each_mem_range(i, &start, &end) {
> @@ -1165,17 +1168,6 @@ static void __init map_mem(void)
>  		__map_memblock(start, end, pgprot_tagged(PAGE_KERNEL),
>  			       flags);
>  	}
> -
> -	/*
> -	 * Map the linear alias of the [_text, __init_begin) interval
> -	 * as non-executable now, and remove the write permission in
> -	 * mark_linear_text_alias_ro() below (which will be called after
> -	 * alternative patching has completed). This makes the contents
> -	 * of the region accessible to subsystems such as hibernate,
> -	 * but protects it from inadvertent modification or execution.
> -	 */
> -	__map_memblock(kernel_start, kernel_end, PAGE_KERNEL, 0);
> -	memblock_clear_nomap(kernel_start, kernel_end - kernel_start);
>  }
>  
>  void mark_rodata_ro(void)


^ permalink raw reply

* Re: [PATCH v4 10/15] arm64: Move fixmap page tables to end of kernel image
From: Kevin Brodsky @ 2026-04-29 13:52 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-arm-kernel
  Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel,
	Ryan Roberts, Anshuman Khandual, Liz Prucka, Seth Jenkins,
	Kees Cook, Mike Rapoport, David Hildenbrand, Andrew Morton,
	linux-mm, linux-hardening
In-Reply-To: <20260427153416.2103979-27-ardb+git@google.com>

On 27/04/2026 17:34, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> Move the fixmap page tables out of the BSS section, and place them at
> the end of the image, right before the init_pg_dir section where some of
> the other statically allocated page tables live.
>
> These page tables are currently the only data objects in vmlinux that
> are meant to be accessed via the kernel image's linear alias, and so
> placing them together allows the remainder of the data/bss section to be
> remapped read-only or unmapped entirely.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>

Reviewed-by: Kevin Brodsky <kevin.brodsky@arm.com>

> ---
>  arch/arm64/kernel/vmlinux.lds.S | 5 +++++
>  arch/arm64/mm/fixmap.c          | 7 ++++---
>  2 files changed, 9 insertions(+), 3 deletions(-)
>
> diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
> index e1ac876200a3..2dca18574619 100644
> --- a/arch/arm64/kernel/vmlinux.lds.S
> +++ b/arch/arm64/kernel/vmlinux.lds.S
> @@ -353,6 +353,11 @@ SECTIONS
>  	__pi___bss_start = __bss_start;
>  
>  	. = ALIGN(PAGE_SIZE);
> +	.fixmap_pgdir : {
> +		__fixmap_pgdir_start = .;
> +		*(.fixmap_bss)
> +	}
> +
>  	__pi_init_pg_dir = .;
>  	. += INIT_DIR_SIZE;
>  	__pi_init_pg_end = .;
> diff --git a/arch/arm64/mm/fixmap.c b/arch/arm64/mm/fixmap.c
> index c5c5425791da..b649ea1a46e4 100644
> --- a/arch/arm64/mm/fixmap.c
> +++ b/arch/arm64/mm/fixmap.c
> @@ -31,9 +31,10 @@ static_assert(NR_BM_PMD_TABLES == 1);
>  
>  #define BM_PTE_TABLE_IDX(addr)	__BM_TABLE_IDX(addr, PMD_SHIFT)
>  
> -static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __page_aligned_bss;
> -static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss __maybe_unused;
> -static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss __maybe_unused;
> +#define __fixmap_bss	__section(".fixmap_bss") __aligned(PAGE_SIZE)
> +static pte_t bm_pte[NR_BM_PTE_TABLES][PTRS_PER_PTE] __fixmap_bss;
> +static pmd_t bm_pmd[PTRS_PER_PMD] __fixmap_bss __maybe_unused;
> +static pud_t bm_pud[PTRS_PER_PUD] __fixmap_bss __maybe_unused;
>  
>  static inline pte_t *fixmap_pte(unsigned long addr)
>  {


^ permalink raw reply

* Re: [PATCH v4 12/15] arm64: mm: Map the kernel data/bss read-only in the linear map
From: Kevin Brodsky @ 2026-04-29 13:54 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-arm-kernel
  Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel,
	Ryan Roberts, Anshuman Khandual, Liz Prucka, Seth Jenkins,
	Kees Cook, Mike Rapoport, David Hildenbrand, Andrew Morton,
	linux-mm, linux-hardening
In-Reply-To: <20260427153416.2103979-29-ardb+git@google.com>

On 27/04/2026 17:34, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> On systems where the bootloader adheres to the original arm64 boot
> protocol, the placement of the kernel in the physical address space is
> highly predictable, and this makes the placement of its linear alias in
> the kernel virtual address space equally predictable, given the lack of
> randomization of the linear map.
>
> The linear aliases of the kernel text and rodata regions are already
> mapped read-only, but the kernel data and bss are mapped read-write in
> this region. This is not needed, so map them read-only as well.
>
> Note that the statically allocated kernel page tables do need to be
> modifiable via the linear map, so leave these mapped read-write.
>
> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  arch/arm64/include/asm/sections.h |  1 +
>  arch/arm64/mm/mmu.c               | 16 ++++++++++++++--
>  2 files changed, 15 insertions(+), 2 deletions(-)
>
> diff --git a/arch/arm64/include/asm/sections.h b/arch/arm64/include/asm/sections.h
> index 51b0d594239e..32ec21af0823 100644
> --- a/arch/arm64/include/asm/sections.h
> +++ b/arch/arm64/include/asm/sections.h
> @@ -23,6 +23,7 @@ extern char __irqentry_text_start[], __irqentry_text_end[];
>  extern char __mmuoff_data_start[], __mmuoff_data_end[];
>  extern char __entry_tramp_text_start[], __entry_tramp_text_end[];
>  extern char __relocate_new_kernel_start[], __relocate_new_kernel_end[];
> +extern char __fixmap_pgdir_start[];
>  
>  static inline size_t entry_tramp_text_size(void)
>  {
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 1a4b4337d29a..9361b7efb848 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1122,7 +1122,9 @@ static void __init map_mem(void)
>  {
>  	static const u64 direct_map_end = _PAGE_END(VA_BITS_MIN);
>  	phys_addr_t kernel_start = __pa_symbol(_text);
> -	phys_addr_t kernel_end = __pa_symbol(__init_begin);
> +	phys_addr_t init_begin = __pa_symbol(__init_begin);
> +	phys_addr_t init_end = __pa_symbol(__init_end);
> +	phys_addr_t kernel_end = __pa_symbol(__fixmap_pgdir_start);

Using fixmap_pgdir as an anchor seems a bit arbitrary... Couldn't we use
__bss_end instead?

It could also be helpful to add comments in vmlinux.lds.S clarifying
which sections are RO/RW in the linear map, it's getting pretty
difficult to follow.

>  	phys_addr_t start, end;
>  	int flags = NO_EXEC_MAPPINGS;
>  	u64 i;
> @@ -1155,7 +1157,11 @@ static void __init map_mem(void)
>  	 * of the region accessible to subsystems such as hibernate,
>  	 * but protects it from inadvertent modification or execution.
>  	 */
> -	__map_memblock(kernel_start, kernel_end, pgprot_tagged(PAGE_KERNEL),
> +	__map_memblock(kernel_start, init_begin, pgprot_tagged(PAGE_KERNEL),
> +		       flags);
> +
> +	/* Map the kernel data/bss so it can be remapped later */
> +	__map_memblock(init_end, kernel_end, pgprot_tagged(PAGE_KERNEL),

Maybe I'm missing something obvious, but considering patch 3/4 couldn't
we directly map the range RO here?

- Kevin

>  		       flags);
>  
>  	/* map all the memory banks */
> @@ -1168,6 +1174,12 @@ static void __init map_mem(void)
>  		__map_memblock(start, end, pgprot_tagged(PAGE_KERNEL),
>  			       flags);
>  	}
> +
> +	/* Map the kernel data/bss read-only in the linear map */
> +	__map_memblock(init_end, kernel_end, pgprot_tagged(PAGE_KERNEL_RO),
> +		       flags);
> +	flush_tlb_kernel_range((unsigned long)lm_alias(__init_end),
> +			       (unsigned long)lm_alias(__fixmap_pgdir_start));
>  }
>  
>  void mark_rodata_ro(void)


^ permalink raw reply

* Re: [PATCH v4 13/15] arm64: mm: Unmap kernel data/bss entirely from the linear map
From: Kevin Brodsky @ 2026-04-29 13:55 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-arm-kernel
  Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel,
	Ryan Roberts, Anshuman Khandual, Liz Prucka, Seth Jenkins,
	Kees Cook, Mike Rapoport, David Hildenbrand, Andrew Morton,
	linux-mm, linux-hardening
In-Reply-To: <20260427153416.2103979-30-ardb+git@google.com>

On 27/04/2026 17:34, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
>
> The linear aliases of the kernel text and rodata are mapped read-only in
> the linear map as well. Given that the contents of these regions are
> mostly identical to the version in the loadable image, mapping them
> read-only and leaving their contents visible is a reasonable hardening
> measure.
>
> Data and bss, however, are now also mapped read-only but the contents of
> these regions are more likely to contain data that we'd rather not leak.

That sounds like a good rationale but I wonder, is there anything
stopping us from unmapping text/rodata as well?

> So let's unmap these entirely in the linear map when the kernel is
> running normally.
>
> When going into hibernation or waking up from it, these regions need to
> be mapped, so map the region initially, and toggle the valid bit so
> map/unmap the region as needed.

Doesn't safe_copy_page() already handle that? I suppose this is an
optimisation to avoid modifying the linear map for every page, but if so
it would be good to spell it out.

> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
> ---
>  arch/arm64/mm/mmu.c | 44 ++++++++++++++++----
>  1 file changed, 37 insertions(+), 7 deletions(-)
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 9361b7efb848..a464f3d2d2df 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -24,6 +24,7 @@
>  #include <linux/mm.h>
>  #include <linux/vmalloc.h>
>  #include <linux/set_memory.h>
> +#include <linux/suspend.h>
>  #include <linux/kfence.h>
>  #include <linux/pkeys.h>
>  #include <linux/mm_inline.h>
> @@ -1040,6 +1041,31 @@ static void __init __map_memblock(phys_addr_t start, phys_addr_t end,
>  				 end - start, prot, early_pgtable_alloc, flags);
>  }
>  
> +static void remap_linear_data_alias(bool unmap)
> +{
> +	set_memory_valid((unsigned long)lm_alias(__init_end),
> +			 (unsigned long)(__fixmap_pgdir_start - __init_end) / PAGE_SIZE,
> +			 !unmap);
> +}
> +
> +static int arm64_hibernate_pm_notify(struct notifier_block *nb,
> +				     unsigned long mode, void *unused)
> +{
> +	switch (mode) {
> +	default:
> +		break;
> +	case PM_POST_HIBERNATION:
> +	case PM_POST_RESTORE:
> +		remap_linear_data_alias(true);
> +		break;
> +	case PM_HIBERNATION_PREPARE:
> +	case PM_RESTORE_PREPARE:
> +		remap_linear_data_alias(false);
> +		break;
> +	}
> +	return 0;
> +}
> +
>  void __init mark_linear_text_alias_ro(void)
>  {
>  	/*
> @@ -1048,6 +1074,16 @@ void __init mark_linear_text_alias_ro(void)
>  	update_mapping_prot(__pa_symbol(_text), (unsigned long)lm_alias(_text),
>  			    (unsigned long)__init_begin - (unsigned long)_text,
>  			    pgprot_tagged(PAGE_KERNEL_RO));
> +
> +	remap_linear_data_alias(true);

It's really hard to know what this does without looking at the function.
How about mark_linear_data_alias_valid(false)?

> +
> +	if (IS_ENABLED(CONFIG_HIBERNATION)) {
> +		static struct notifier_block nb = {
> +			.notifier_call = arm64_hibernate_pm_notify
> +		};
> +
> +		register_pm_notifier(&nb);
> +	}
>  }
>  
>  #ifdef CONFIG_KFENCE
> @@ -1162,7 +1198,7 @@ static void __init map_mem(void)
>  
>  	/* Map the kernel data/bss so it can be remapped later */
>  	__map_memblock(init_end, kernel_end, pgprot_tagged(PAGE_KERNEL),
> -		       flags);
> +		       flags | NO_BLOCK_MAPPINGS);

Might be an obvious question but why do we need this?

- Kevin

>  
>  	/* map all the memory banks */
>  	for_each_mem_range(i, &start, &end) {
> @@ -1174,12 +1210,6 @@ static void __init map_mem(void)
>  		__map_memblock(start, end, pgprot_tagged(PAGE_KERNEL),
>  			       flags);
>  	}
> -
> -	/* Map the kernel data/bss read-only in the linear map */
> -	__map_memblock(init_end, kernel_end, pgprot_tagged(PAGE_KERNEL_RO),
> -		       flags);
> -	flush_tlb_kernel_range((unsigned long)lm_alias(__init_end),
> -			       (unsigned long)lm_alias(__fixmap_pgdir_start));
>  }
>  
>  void mark_rodata_ro(void)


^ permalink raw reply

* Re: [PATCH v2 01/12] clk: add new flag CLK_ROUNDING_NOOP
From: Brian Masney @ 2026-04-29 13:55 UTC (permalink / raw)
  To: Stephen Boyd
  Cc: Michael Turquette, linux-clk, linux-kernel, Sudeep Holla,
	Abel Vesa, Andrea della Porta, Baolin Wang, Bjorn Andersson,
	Chanwoo Choi, Frank Li, Geert Uytterhoeven, Krzysztof Kozlowski,
	Orson Zhai, Sascha Hauer, Sylwester Nawrocki, Tudor Ambarus,
	Alim Akhtar, arm-scmi, Chunyan Zhang, Cristian Marussi,
	Fabio Estevam, imx, linux-arm-kernel, linux-arm-msm,
	linux-renesas-soc, linux-samsung-soc, Peng Fan,
	Pengutronix Kernel Team
In-Reply-To: <177742893645.5403.3938693995862346406@localhost.localdomain>

On Tue, Apr 28, 2026 at 07:15:36PM -0700, Stephen Boyd wrote:
> Quoting Brian Masney (2026-03-09 07:38:40)
> > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> > index fd418dc988b1c60c49e3ac9c0c44aa132dd5da28..1187e5b1dbc123d2d2c1f43690d7dcf75a7c4ac3 100644
> > --- a/drivers/clk/clk.c
> > +++ b/drivers/clk/clk.c
> > @@ -1673,7 +1690,7 @@ EXPORT_SYMBOL_GPL(clk_hw_forward_rate_request);
> >  
> >  static bool clk_core_can_round(struct clk_core * const core)
> >  {
> > -       return core->ops->determine_rate;
> > +       return core->ops->determine_rate || clk_is_rounding_noop(core);
> >  }
> >  
> >  static int clk_core_round_rate_nolock(struct clk_core *core,
> > @@ -3528,6 +3545,7 @@ static const struct {
> >         ENTRY(CLK_IS_CRITICAL),
> >         ENTRY(CLK_OPS_PARENT_ENABLE),
> >         ENTRY(CLK_DUTY_CYCLE_PARENT),
> > +       ENTRY(CLK_ROUNDING_NOOP),
> >  #undef ENTRY
> >  };
> >  
> > @@ -3906,13 +3924,19 @@ static int __clk_core_init(struct clk_core *core)
> >  
> >         /* check that clk_ops are sane.  See Documentation/driver-api/clk.rst */
> >         if (core->ops->set_rate && !core->ops->determine_rate &&
> > -             core->ops->recalc_rate) {
> > +             core->ops->recalc_rate && !clk_is_rounding_noop(core)) {
> >                 pr_err("%s: %s must implement .determine_rate in addition to .recalc_rate\n",
> >                        __func__, core->name);
> >                 ret = -EINVAL;
> >                 goto out;
> >         }
> >  
> > +       if (clk_is_rounding_noop(core) && core->ops->determine_rate) {
> > +               pr_err("%s: %s cannot implement both .determine_rate and CLK_ROUNDING_NOOP\n",
> > +                      __func__, core->name);
> > +               goto out;
> > +       }
> > +
> 
> This hunk has me irked. I'd rather we export some function like
> clk_determine_rate_noop() that just returns 0 instead of adding another
> flag. The chance that someone can get it wrong goes down and you can
> naturally grep for any clks that are using determine_rate() without
> having to also include this flag in the grep. It makes it easier to
> reason about as well because we can have code that just checks for
> determine_rate presence instead of both (i.e. clk_core_can_round() isn't
> changed). Plus a clk_ops structure is more self-contained because it
> doesn't rely on the clk flags to go with it.

I also like the clk_determine_rate_noop() approach much better as well.
I'll send a new version.

Thanks,
Brian



^ permalink raw reply

* Re: [PATCH v4 14/15] arm64: mm: Generalize manipulation code of read-only descriptors
From: Kevin Brodsky @ 2026-04-29 13:57 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-arm-kernel
  Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel,
	Ryan Roberts, Anshuman Khandual, Liz Prucka, Seth Jenkins,
	Kees Cook, Mike Rapoport, David Hildenbrand, Andrew Morton,
	linux-mm, linux-hardening
In-Reply-To: <20260427153416.2103979-31-ardb+git@google.com>

On 27/04/2026 17:34, Ard Biesheuvel wrote:
> [...]
>
> -void noinstr set_swapper_pgd(pgd_t *pgdp, pgd_t pgd)
> +void noinstr set_rodata_pte(pte_t *ptep, pte_t pte)
>  {
> -	pgd_t *fixmap_pgdp;
> +	pte_t *fixmap_ptep;
>  
>  	/*
> -	 * Don't bother with the fixmap if swapper_pg_dir is still mapped
> -	 * writable in the kernel mapping.
> +	 * Don't bother with the fixmap if rodata is still mapped
> +	 * writable in the kernel and linear mappings.
>  	 */
>  	if (rodata_is_rw) {
> -		WRITE_ONCE(*pgdp, pgd);
> +		WRITE_ONCE(*ptep, pte);
>  		dsb(ishst);
>  		isb();
>  		return;
>  	}
>  
> -	spin_lock(&swapper_pgdir_lock);
> -	fixmap_pgdp = pgd_set_fixmap(__pa_symbol(pgdp));
> -	WRITE_ONCE(*fixmap_pgdp, pgd);
> +	spin_lock(&rodata_pgdir_lock);
> +	fixmap_ptep = pte_set_fixmap(__pa_nodebug(ptep));

I don't know much about the fixmap but it strikes me as odd that we
would now use pte_set_fixmap() at all levels. I suppose the question is
whether swapper_pg_dir could be written concurrently with fixmap page
tables at PMD level or above? I'm also wondering if those fixmap page
tables are ever written to.

- Kevin

> +	WRITE_ONCE(*fixmap_ptep, pte);
>  	/*
>  	 * We need dsb(ishst) here to ensure the page-table-walker sees
>  	 * our new entry before set_p?d() returns. The fixmap's
>  	 * flush_tlb_kernel_range() via clear_fixmap() does this for us.
>  	 */
> -	pgd_clear_fixmap();
> -	spin_unlock(&swapper_pgdir_lock);
> +	pte_clear_fixmap();
> +	spin_unlock(&rodata_pgdir_lock);
>  }
>
> [...]


^ permalink raw reply

* [PATCH] arm64: dts: imx8mp-frdm: add support for SD-card
From: Alexandru Ardelean @ 2026-04-29 13:57 UTC (permalink / raw)
  To: imx, linux-arm-kernel, linux-kernel, devicetree
  Cc: festevam, kernel, s.hauer, Frank.Li, conor+dt, krzk+dt, robh,
	Alexandru Ardelean, Xiaofeng Wei

The i.MX8MP FRDM board also has an SD-card slot, which is useful during.
development.
This change picks it up from NXP's BSP repo:
  https://github.com/nxp-imx-support/meta-imx-frdm

Adding Xiaofeng Wei's as he is the original author of the DT.

Signed-off-by: Xiaofeng Wei <xiaofeng.wei@nxp.com>
Signed-off-by: Alexandru Ardelean <aardelean@deviqon.com>
---
 arch/arm64/boot/dts/freescale/imx8mp-frdm.dts | 72 +++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mp-frdm.dts b/arch/arm64/boot/dts/freescale/imx8mp-frdm.dts
index 55690f5e53d7e..84034b0ccb12d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mp-frdm.dts
+++ b/arch/arm64/boot/dts/freescale/imx8mp-frdm.dts
@@ -42,6 +42,17 @@ memory@40000000 {
 		reg = <0x0 0x40000000 0 0xc0000000>,
 		      <0x1 0x00000000 0 0x40000000>;
 	};
+
+	reg_usdhc2_vmmc: regulator-usdhc2 {
+		compatible = "regulator-fixed";
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_reg_usdhc2_vmmc>;
+		regulator-name = "VSD_3V3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		gpio = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+		enable-active-high;
+	};
 };
 
 &A53_0 {
@@ -237,6 +248,19 @@ &uart3 {
 	status = "okay";
 };
 
+&usdhc2 {
+	assigned-clocks = <&clk IMX8MP_CLK_USDHC2>;
+	assigned-clock-rates = <400000000>;
+	pinctrl-names = "default", "state_100mhz", "state_200mhz";
+	pinctrl-0 = <&pinctrl_usdhc2>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-1 = <&pinctrl_usdhc2_100mhz>, <&pinctrl_usdhc2_gpio>;
+	pinctrl-2 = <&pinctrl_usdhc2_200mhz>, <&pinctrl_usdhc2_gpio>;
+	cd-gpios = <&gpio2 12 GPIO_ACTIVE_LOW>;
+	vmmc-supply = <&reg_usdhc2_vmmc>;
+	bus-width = <4>;
+	status = "okay";
+};
+
 &usdhc3 {
 	assigned-clocks = <&clk IMX8MP_CLK_USDHC3>;
 	assigned-clock-rates = <400000000>;
@@ -289,6 +313,12 @@ MX8MP_IOMUXC_SD1_STROBE__GPIO2_IO11	0x146
 		>;
 	};
 
+	pinctrl_reg_usdhc2_vmmc: regusdhc2vmmcgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_RESET_B__GPIO2_IO19	0x40
+		>;
+	};
+
 	pinctrl_uart2: uart2grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_UART2_RXD__UART2_DCE_RX	0x140
@@ -305,6 +335,48 @@ MX8MP_IOMUXC_ECSPI1_MISO__UART3_DCE_CTS	0x140
 		>;
 	};
 
+	pinctrl_usdhc2: usdhc2grp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x190
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d0
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d0
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d0
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d0
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d0
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT	0xc0
+		>;
+	};
+
+	pinctrl_usdhc2_100mhz: usdhc2-100mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x194
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d4
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d4
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d4
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d4
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d4
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
+		>;
+	};
+
+	pinctrl_usdhc2_200mhz: usdhc2-200mhzgrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CLK__USDHC2_CLK	0x196
+			MX8MP_IOMUXC_SD2_CMD__USDHC2_CMD	0x1d6
+			MX8MP_IOMUXC_SD2_DATA0__USDHC2_DATA0	0x1d6
+			MX8MP_IOMUXC_SD2_DATA1__USDHC2_DATA1	0x1d6
+			MX8MP_IOMUXC_SD2_DATA2__USDHC2_DATA2	0x1d6
+			MX8MP_IOMUXC_SD2_DATA3__USDHC2_DATA3	0x1d6
+			MX8MP_IOMUXC_GPIO1_IO04__USDHC2_VSELECT 0xc0
+		>;
+	};
+
+	pinctrl_usdhc2_gpio: usdhc2gpiogrp {
+		fsl,pins = <
+			MX8MP_IOMUXC_SD2_CD_B__GPIO2_IO12	0x1c4
+		>;
+	};
+
 	pinctrl_usdhc3: usdhc3grp {
 		fsl,pins = <
 			MX8MP_IOMUXC_NAND_WE_B__USDHC3_CLK	0x190
-- 
2.43.0



^ permalink raw reply related

* Re: [PATCH v4 15/15] arm64: mm: Remap linear aliases of the fixmap page tables read-only
From: Kevin Brodsky @ 2026-04-29 13:57 UTC (permalink / raw)
  To: Ard Biesheuvel, linux-arm-kernel
  Cc: linux-kernel, will, catalin.marinas, mark.rutland, Ard Biesheuvel,
	Ryan Roberts, Anshuman Khandual, Liz Prucka, Seth Jenkins,
	Kees Cook, Mike Rapoport, David Hildenbrand, Andrew Morton,
	linux-mm, linux-hardening
In-Reply-To: <20260427153416.2103979-32-ardb+git@google.com>

On 27/04/2026 17:34, Ard Biesheuvel wrote:
> [...]
>
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 84d81bae07a7..e76fe5b0c5fe 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1076,6 +1076,11 @@ void __init mark_linear_text_alias_ro(void)
>  			    (unsigned long)__init_begin - (unsigned long)_text,
>  			    pgprot_tagged(PAGE_KERNEL_RO));
>  
> +	/* Map the fixmap PTE table at __fixmap_pgdir_start R/O in linear map too */
> +	update_mapping_prot(__pa_symbol(__fixmap_pgdir_start),
> +			    (unsigned long)lm_alias(__fixmap_pgdir_start),
> +			    PAGE_SIZE, pgprot_tagged(PAGE_KERNEL_RO));

Is that definitely just one page?

> +
>  	remap_linear_data_alias(true);
>  
>  	if (IS_ENABLED(CONFIG_HIBERNATION)) {


^ permalink raw reply

* Re: [PATCH 7/7] arm64: dts: renesas: r8a779md: Add support for R-Car M3Le R8A779MD Geist
From: Geert Uytterhoeven @ 2026-04-29 13:59 UTC (permalink / raw)
  To: Marek Vasut
  Cc: linux-arm-kernel, Nguyen Tran, Conor Dooley, David Airlie,
	Kieran Bingham, Krzysztof Kozlowski, Kuninori Morimoto,
	Laurent Pinchart, Magnus Damm, Maxime Ripard, Michael Turquette,
	Rob Herring, Simona Vetter, Stephen Boyd, Thomas Zimmermann,
	Tomi Valkeinen, devicetree, dri-devel, linux-clk, linux-kernel,
	linux-renesas-soc
In-Reply-To: <20260419193718.133174-8-marek.vasut+renesas@mailbox.org>

Hi Marek,

Thanks for your patch!

On Sun, 19 Apr 2026 at 21:38, Marek Vasut
<marek.vasut+renesas@mailbox.org> wrote:
> From: Nguyen Tran <nguyen.tran.pz@bp.renesas.com>
>
> Add support for the Geist board based on the Renesas R-Car R8A779MD (M3Le)
> SoC, a register-compatible variant of the R8A77965 (M3-N) with reduced set
> of peripherals. The Geist board design references the Renesas Salvator-X/XS
> boards, adapting their configuration for the R8A779MD SoC.

The latter is only true for the panel overlay, which should IMHO be
a separate patch.

> Signed-off-by: Nguyen Tran <nguyen.tran.pz@bp.renesas.com>
> Signed-off-by: Marek Vasut <marek.vasut+renesas@mailbox.org>

> --- a/arch/arm64/boot/dts/renesas/Makefile
> +++ b/arch/arm64/boot/dts/renesas/Makefile
> @@ -60,6 +60,9 @@ r8a77965-salvator-xs-panel-aa104xd12-dtbs := r8a77965-salvator-xs.dtb salvator-p
>  dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-salvator-xs-panel-aa104xd12.dtb
>  dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-ulcb.dtb
>  dtb-$(CONFIG_ARCH_R8A77965) += r8a77965-ulcb-kf.dtb
> +dtb-$(CONFIG_ARCH_R8A77965) += r8a779md-geist.dtb
> +r8a779md-geist-panel-aa104xd12-dtbs := r8a779md-geist.dtb geist-panel-aa104xd12.dtbo
> +dtb-$(CONFIG_ARCH_R8A77965) += r8a779md-geist-panel-aa104xd12.dtb
>
>  dtb-$(CONFIG_ARCH_R8A77970) += r8a77970-eagle.dtb
>  dtb-$(CONFIG_ARCH_R8A77970) += r8a77970-eagle-function-expansion.dtbo
> diff --git a/arch/arm64/boot/dts/renesas/geist-panel-aa104xd12.dtso b/arch/arm64/boot/dts/renesas/geist-panel-aa104xd12.dtso
> new file mode 100644
> index 0000000000000..c8e39811eb051
> --- /dev/null
> +++ b/arch/arm64/boot/dts/renesas/geist-panel-aa104xd12.dtso
> @@ -0,0 +1,17 @@
> +// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
> +/*
> + * Device Tree overlay for the AA104XD12 panel connected to LVDS0 on a Geist board
> + *
> + * Copyright 2026 Marek Vasut
> + */
> +
> +/dts-v1/;
> +/plugin/;
> +
> +#include <dt-bindings/gpio/gpio.h>

This include is not needed?

> +
> +#include "salvator-panel-aa104xd12.dtso"
> +
> +&{/panel} {
> +       data-mapping = "jeida-24";

Is there any specific reason Geist needs "jeida-24", while all other
boards use "jeida-18"?

It looks like the major difference between Salvator-X(S) and Geist vs.
Draak and Ebisu is that the former connect to lvds0, and the latter to lvds1.
So what about renaming
salvator-panel-aa104xd12.dtso to lvds0-panel-aa104xd12.dtso, and
draak-ebisu-panel-aa104xd12.dtso to lvds1-panel-aa104xd12.dtso?

> +};

> --- /dev/null
> +++ b/arch/arm64/boot/dts/renesas/r8a779md-geist.dts
> @@ -0,0 +1,832 @@
> +// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +/*
> + * Device Tree Source for the Geist board with R-Car M3Le
> + *
> + * Copyright (C) 2025-2026 Renesas Electronics Corp.
> + */
> +
> +/dts-v1/;
> +#include <dt-bindings/gpio/gpio.h>
> +#include <dt-bindings/input/input.h>
> +#include "r8a779md.dtsi"
> +
> +/ {
> +       model = "Renesas Geist board based on r8a779md";
> +       compatible = "renesas,geist", "renesas,r8a779md", "renesas,r8a77965";
> +
> +       aliases {
> +               serial0 = &scif2;
> +               serial1 = &hscif1;
> +               ethernet0 = &avb;
> +               mmc0 = &sdhi2;
> +               mmc1 = &sdhi0;
> +       };
> +
> +       chosen {
> +               bootargs = "ignore_loglevel rw root=/dev/nfs ip=on";
> +               stdout-path = "serial0:115200n8";
> +       };
> +
> +       memory@48000000 {
> +               device_type = "memory";
> +               /* first 128MB is reserved for secure area. */
> +               reg = <0x0 0x48000000 0x0 0x78000000>;

MT53E1G32D2FW-046 is a 32 Gib part, so there should be 4 GiB of RAM
in total.

> +       };
> +
> +       reserved-memory {
> +               #address-cells = <2>;
> +               #size-cells = <2>;
> +               ranges;
> +
> +               /* Device specific region for Lossy Decompression */
> +               lossy_decompress: linux,lossy_decompress@54000000 {
> +                       no-map;
> +                       reg = <0x00000000 0x54000000 0x0 0x03000000>;
> +               };

Please drop this node.  It should be added by the firmware stack
when needed.

> +       };
> +
> +       audio_clkout: audio-clkout {

Please sort nodes without unit address by name (everywhere).

> +               /*
> +                * FIXME

Please drop the literal "FIXME".

> +                * This is same as <&rcar_sound 0>
> +                * but needed to avoid cs2500/rcar_sound probe dead-lock
> +                */
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <12288000>;
> +       };
> +
> +       backlight: backlight {
> +               compatible = "pwm-backlight";
> +               pwms = <&pwm1 0 50000>;
> +
> +               brightness-levels = <256 128 64 16 8 4 0>;
> +               default-brightness-level = <6>;
> +
> +               power-supply = <&reg_12v>;
> +               enable-gpios = <&gpio6 7 GPIO_ACTIVE_HIGH>;
> +       };
> +
> +       cvbs-in {
> +               compatible = "composite-video-connector";
> +               label = "CVBS IN";
> +
> +               port {
> +                       cvbs_con: endpoint {
> +                               remote-endpoint = <&adv7482_ain7>;
> +                       };
> +               };
> +       };
> +
> +       hdmi-in {
> +               compatible = "hdmi-connector";
> +               label = "HDMI IN";
> +               type = "a";
> +
> +               port {
> +                       hdmi_in_con: endpoint {
> +                               remote-endpoint = <&adv7482_hdmi>;
> +                       };
> +               };
> +       };
> +
> +       keys {
> +               compatible = "gpio-keys";
> +
> +               pinctrl-0 = <&keys_pins>;
> +               pinctrl-names = "default";
> +
> +               key-1 {
> +                       gpios = <&gpio5 17 GPIO_ACTIVE_LOW>;
> +                       linux,code = <KEY_1>;
> +                       label = "SW4-1";
> +                       wakeup-source;
> +                       debounce-interval = <20>;
> +               };
> +
> +               key-2 {
> +                       gpios = <&gpio5 20 GPIO_ACTIVE_LOW>;
> +                       linux,code = <KEY_2>;
> +                       label = "SW4-2";
> +                       wakeup-source;
> +                       debounce-interval = <20>;
> +               };
> +
> +               key-3 {
> +                       gpios = <&gpio5 22 GPIO_ACTIVE_LOW>;
> +                       linux,code = <KEY_3>;
> +                       label = "SW4-3";
> +                       wakeup-source;
> +                       debounce-interval = <20>;
> +               };
> +
> +               key-4 {
> +                       gpios = <&gpio5 23 GPIO_ACTIVE_LOW>;
> +                       linux,code = <KEY_4>;
> +                       label = "SW4-4";
> +                       wakeup-source;
> +                       debounce-interval = <20>;
> +               };
> +
> +               key-a {
> +                       gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
> +                       linux,code = <KEY_A>;
> +                       label = "TSW0";
> +                       wakeup-source;
> +                       debounce-interval = <20>;
> +               };
> +
> +               key-b {
> +                       gpios = <&gpio6 12 GPIO_ACTIVE_LOW>;
> +                       linux,code = <KEY_B>;
> +                       label = "TSW1";
> +                       wakeup-source;
> +                       debounce-interval = <20>;
> +               };
> +
> +               key-c {
> +                       gpios = <&gpio6 13 GPIO_ACTIVE_LOW>;
> +                       linux,code = <KEY_C>;
> +                       label = "TSW2";
> +                       wakeup-source;
> +                       debounce-interval = <20>;
> +               };
> +       };
> +
> +       reg_1p8v: regulator0 {

Please no indexed regulators (everywhere), as they cause conflicts:
regulator-1p8v.

> +               compatible = "regulator-fixed";
> +               regulator-name = "fixed-1.8V";
> +               regulator-min-microvolt = <1800000>;
> +               regulator-max-microvolt = <1800000>;
> +               regulator-boot-on;
> +               regulator-always-on;
> +       };
> +
> +       reg_3p3v: regulator1 {
> +               compatible = "regulator-fixed";
> +               regulator-name = "fixed-3.3V";
> +               regulator-min-microvolt = <3300000>;
> +               regulator-max-microvolt = <3300000>;
> +               regulator-boot-on;
> +               regulator-always-on;
> +       };
> +
> +       reg_12v: regulator2 {
> +               compatible = "regulator-fixed";
> +               regulator-name = "fixed-12V";
> +               regulator-min-microvolt = <12000000>;
> +               regulator-max-microvolt = <12000000>;
> +               regulator-boot-on;
> +               regulator-always-on;
> +       };
> +
> +       sound_card: sound {
> +               compatible = "audio-graph-card";
> +
> +               label = "rcar-sound";
> +               dais = <&rsnd_port0>; /* AK4619 Audio Codec */
> +       };
> +
> +       vbus0_usb2: regulator-vbus0-usb2 {
> +               compatible = "regulator-fixed";
> +
> +               regulator-name = "USB20_VBUS0";
> +               regulator-min-microvolt = <5000000>;
> +               regulator-max-microvolt = <5000000>;
> +
> +               gpio = <&gpio6 16 GPIO_ACTIVE_HIGH>;
> +               enable-active-high;
> +       };
> +
> +       vcc_sdhi0: regulator-vcc-sdhi0 {
> +               compatible = "regulator-fixed";
> +
> +               regulator-name = "SDHI0 Vcc";
> +               regulator-min-microvolt = <3300000>;
> +               regulator-max-microvolt = <3300000>;
> +
> +               gpio = <&gpio5 2 GPIO_ACTIVE_HIGH>;
> +               enable-active-high;
> +       };
> +
> +       vccq_sdhi0: regulator-vccq-sdhi0 {
> +               compatible = "regulator-gpio";
> +
> +               regulator-name = "SDHI0 VccQ";
> +               regulator-min-microvolt = <1800000>;
> +               regulator-max-microvolt = <3300000>;
> +
> +               gpios = <&gpio5 1 GPIO_ACTIVE_HIGH>;
> +               gpios-states = <1>;
> +               states = <3300000 1>, <1800000 0>;
> +       };
> +
> +       vga {
> +               compatible = "vga-connector";
> +
> +               port {
> +                       vga_in: endpoint {
> +                               remote-endpoint = <&adv7123_out>;
> +                       };
> +               };
> +       };
> +
> +       vga-encoder {
> +               compatible = "adi,adv7123";
> +
> +               ports {
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +
> +                       port@0 {
> +                               reg = <0>;
> +                               adv7123_in: endpoint {
> +                                       remote-endpoint = <&du_out_rgb>;
> +                               };
> +                       };
> +                       port@1 {
> +                               reg = <1>;
> +                               adv7123_out: endpoint {
> +                                       remote-endpoint = <&vga_in>;
> +                               };
> +                       };
> +               };
> +       };
> +
> +       x12_clk: x12 {

x12-clock

> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <24576000>;
> +       };
> +
> +       /* External DU dot clocks */
> +       x21_clk: x21-clock {
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <33000000>;
> +       };
> +
> +       x22_clk: x22-clock {
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <33000000>;
> +       };

X22 is not wired to anything; should we keep it?

> +
> +       x23_clk: x23-clock {
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <25000000>;
> +       };
> +
> +       x3013_clk: x3013-clock {
> +               compatible = "fixed-clock";
> +               #clock-cells = <0>;
> +               clock-frequency = <25000000>;
> +       };
> +};
> +
> +&audio_clk_a {
> +       clock-frequency = <22579200>;
> +};
> +
> +&avb {
> +       pinctrl-0 = <&avb_pins>;
> +       pinctrl-names = "default";
> +       phy-handle = <&phy0>;
> +       tx-internal-delay-ps = <2000>;
> +       status = "okay";
> +
> +       phy0: ethernet-phy@0 {

compatible = "ethernet-phy-id0022.1622";

> +               rxc-skew-ps = <1500>;
> +               reg = <0>;
> +               interrupt-parent = <&gpio2>;
> +               interrupts = <11 IRQ_TYPE_LEVEL_LOW>;

interrupts-extended = <&gpio2 11 IRQ_TYPE_LEVEL_LOW>;

> +               reset-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
> +               reset-assert-us = <100>;
> +               reset-deassert-us = <100>;

Do we need these two? We don't have them in e.g.
arch/arm64/boot/dts/renesas/salvator-common.dtsi

> +       };
> +};
> +
> +&csi40 {
> +       status = "okay";
> +
> +       ports {
> +               port@0 {
> +                       csi40_in: endpoint {
> +                               clock-lanes = <0>;
> +                               data-lanes = <1 2 3 4>;
> +                               remote-endpoint = <&adv7482_txa>;
> +                       };
> +               };
> +       };
> +};
> +
> +&du {
> +       pinctrl-0 = <&du_pins>;
> +       pinctrl-names = "default";
> +       clocks = <&cpg CPG_MOD 724>,
> +                <&cpg CPG_MOD 723>,
> +                <&cpg CPG_MOD 721>,
> +                <&versaclock5 1>,
> +                <&x21_clk>,
> +                <&versaclock5 2>;
> +       clock-names = "du.0", "du.1", "du.3",
> +                     "dclkin.0", "dclkin.1", "dclkin.3";
> +       status = "okay";
> +
> +       ports {
> +               port@0 {
> +                       du_out_rgb: endpoint {
> +                               remote-endpoint = <&adv7123_in>;
> +                       };
> +               };
> +       };
> +};
> +
> +&ehci0 {
> +       dr_mode = "otg";
> +       status = "okay";
> +};
> +
> +&ehci1 {
> +       status = "okay";
> +};

R-Car M3Le does not have the second USB2 channel.

> +
> +&extalr_clk {
> +       clock-frequency = <32768>;
> +};
> +
> +&extal_clk {
> +       clock-frequency = <16666666>;
> +};
> +
> +&hscif1 {
> +       pinctrl-0 = <&hscif1_pins>;
> +       pinctrl-names = "default";
> +
> +       uart-has-rtscts;
> +       /* Please only enable hscif1 or scif1 */
> +       status = "okay";
> +};
> +
> +&hsusb {
> +       dr_mode = "otg";
> +       status = "okay";
> +};
> +
> +&i2c2 {
> +       pinctrl-0 = <&i2c2_pins>;
> +       pinctrl-names = "default";
> +       clock-frequency = <100000>;
> +       status = "okay";
> +
> +       ak4619: codec@10 {
> +               compatible = "asahi-kasei,ak4619";
> +               reg = <0x10>;
> +               clocks = <&rcar_sound 3>;
> +               clock-names = "mclk";
> +               #sound-dai-cells = <0>;
> +
> +               port {
> +                       ak4619_endpoint: endpoint {
> +                               remote-endpoint = <&rsnd_endpoint0>;
> +                       };
> +               };
> +       };
> +
> +       /* Pin-to-pin, register map, and control compatible with CS2000 and CS2200 */
> +       cs2500: clk_multiplier@4f {

clock-controller

> +               #clock-cells = <0>;
> +               compatible = "cirrus,cs2500-cp", "cirrus,cs2000-cp";

probably the "-cp" should be dropped from the first compatible value,
cfr. my comment on the DT bindings patch.

> +               reg = <0x4f>;
> +               clocks = <&audio_clkout>, <&x12_clk>;
> +               clock-names = "clk_in", "ref_clk";
> +
> +               assigned-clocks = <&cs2500>;
> +               assigned-clock-rates = <24576000>; /* 1/1 divide */
> +       };
> +};
> +
> +&i2c4 {
> +       clock-frequency = <400000>;
> +       status = "okay";
> +
> +       versaclock3: clock-generator@68 {

clock-controller?

> +               compatible = "renesas,5p35023";
> +               reg = <0x68>;
> +               #clock-cells = <1>;
> +               clocks = <&x3013_clk>;
> +               assigned-clocks = <&versaclock3 4>, <&versaclock3 5>;
> +               assigned-clock-rates = <100000000>, <100000000>;
> +       };
> +
> +       versaclock5: clock-generator@6a {

clock-controller?

> +               compatible = "idt,5p49v5923";
> +               reg = <0x6a>;
> +               #clock-cells = <1>;
> +               clocks = <&x23_clk>;
> +               clock-names = "xin";
> +       };
> +
> +       video-receiver@70 {
> +               compatible = "adi,adv7482";
> +               reg = <0x70 0x71 0x72 0x73 0x74 0x75
> +                      0x60 0x61 0x62 0x63 0x64 0x65>;
> +               reg-names = "main", "dpll", "cp", "hdmi", "edid", "repeater",
> +                           "infoframe", "cbus", "cec", "sdp", "txa", "txb" ;
> +
> +               interrupt-parent = <&gpio6>;
> +               interrupts = <30 IRQ_TYPE_LEVEL_LOW>,
> +                            <31 IRQ_TYPE_LEVEL_LOW>;

interrupts-extended = <&gpio6 30 IRQ_TYPE_LEVEL_LOW>,
                      <&gpio6 31 IRQ_TYPE_LEVEL_LOW>;

> +               interrupt-names = "intrq1", "intrq2";
> +
> +               ports {
> +                       #address-cells = <1>;
> +                       #size-cells = <0>;
> +
> +                       port@7 {
> +                               reg = <7>;
> +
> +                               adv7482_ain7: endpoint {
> +                                       remote-endpoint = <&cvbs_con>;
> +                               };
> +                       };
> +
> +                       port@8 {
> +                               reg = <8>;
> +
> +                               adv7482_hdmi: endpoint {
> +                                       remote-endpoint = <&hdmi_in_con>;
> +                               };
> +                       };
> +
> +                       port@a {
> +                               reg = <10>;
> +
> +                               adv7482_txa: endpoint {
> +                                       clock-lanes = <0>;
> +                                       data-lanes = <1 2 3 4>;
> +                                       remote-endpoint = <&csi40_in>;
> +                               };
> +                       };
> +               };
> +       };
> +
> +       csa_vdd: adc@7c {
> +               compatible = "maxim,max9611";
> +               reg = <0x7c>;
> +
> +               shunt-resistor-micro-ohms = <5000>;
> +       };
> +
> +       csa_dvfs: adc@7f {
> +               compatible = "maxim,max9611";
> +               reg = <0x7f>;
> +
> +               shunt-resistor-micro-ohms = <5000>;
> +       };
> +};
> +
> +&i2c_dvfs {
> +       status = "okay";
> +
> +       clock-frequency = <400000>;
> +
> +       eeprom@50 {
> +               compatible = "rohm,br24t01", "atmel,24c01";
> +               reg = <0x50>;
> +               pagesize = <8>;
> +       };
> +};
> +
> +&ohci0 {
> +       dr_mode = "otg";
> +       status = "okay";
> +};
> +
> +&ohci1 {
> +       status = "okay";
> +};

R-Car M3Le does not have the second USB2 channel.

> +
> +&pcie_bus_clk {
> +       status = "disabled";
> +};
> +
> +&pciec0 {
> +       clocks = <&cpg CPG_MOD 319>, <&versaclock3 4>;
> +       status = "okay";
> +};
> +
> +&pciec0_rp {
> +       clocks = <&versaclock3 5>;
> +};
> +
> +&pfc {
> +       pinctrl-0 = <&scif_clk_pins>;
> +       pinctrl-names = "default";
> +
> +       avb_pins: avb {
> +               mux {
> +                       groups = "avb_link", "avb_mdio", "avb_mii";
> +                       function = "avb";
> +               };
> +
> +               pins_mdio {
> +                       groups = "avb_mdio";
> +                       drive-strength = <24>;
> +               };
> +
> +               pins_mii_tx {
> +                       pins = "PIN_AVB_TX_CTL", "PIN_AVB_TXC", "PIN_AVB_TD0",
> +                              "PIN_AVB_TD1", "PIN_AVB_TD2", "PIN_AVB_TD3";
> +                       drive-strength = <12>;
> +               };
> +       };
> +
> +       du_pins: du {
> +               groups = "du_rgb888", "du_sync", "du_oddf", "du_clk_out_0";
> +               function = "du";
> +       };
> +
> +       hscif1_pins: hscif1 {
> +               groups = "hscif1_data_a", "hscif1_ctrl_a";
> +               function = "hscif1";
> +       };
> +
> +       i2c2_pins: i2c2 {
> +               groups = "i2c2_a";
> +               function = "i2c2";
> +       };
> +
> +       irq0_pins: irq0 {
> +               groups = "intc_ex_irq0";
> +               function = "intc_ex";
> +       };
> +
> +       keys_pins: keys {
> +               pins = "GP_5_17", "GP_5_20", "GP_5_22";
> +               bias-pull-up;
> +       };
> +
> +       pwm1_pins: pwm1 {
> +               groups = "pwm1_a";
> +               function = "pwm1";
> +       };
> +
> +       pwm2_pins: pwm2 {
> +               groups = "pwm2_a";
> +               function = "pwm2";
> +       };

What is pwm2 used for?

> +
> +       scif1_pins: scif1 {
> +               groups = "scif1_data_a", "scif1_ctrl";
> +               function = "scif1";
> +       };
> +
> +       scif2_pins: scif2 {
> +               groups = "scif2_data_a";
> +               function = "scif2";
> +       };
> +
> +       scif_clk_pins: scif_clk {
> +               groups = "scif_clk_a";
> +               function = "scif_clk";
> +       };
> +
> +       sdhi0_pins: sd0 {
> +               groups = "sdhi0_data4", "sdhi0_ctrl";
> +               function = "sdhi0";
> +               power-source = <3300>;
> +       };
> +
> +       sdhi0_pins_uhs: sd0_uhs {
> +               groups = "sdhi0_data4", "sdhi0_ctrl";
> +               function = "sdhi0";
> +               power-source = <1800>;
> +       };
> +
> +       sdhi2_pins: sd2 {
> +               groups = "sdhi2_data8", "sdhi2_ctrl", "sdhi2_ds";
> +               function = "sdhi2";
> +               power-source = <1800>;
> +       };
> +
> +       sound_pins: sound {
> +               groups = "ssi01239_ctrl", "ssi0_data", "ssi1_data_a";
> +               function = "ssi";
> +       };
> +
> +       sound_clk_pins: sound_clk {
> +               groups = "audio_clk_a_a", "audio_clk_b_a", "audio_clk_c_a",
> +                        "audio_clkout_a", "audio_clkout3_a";
> +               function = "audio_clk";
> +       };
> +
> +       usb0_pins: usb0 {
> +               groups = "usb0";
> +               function = "usb0";
> +       };
> +
> +       usb1_pins: usb1 {
> +               mux {
> +                       groups = "usb1";
> +                       function = "usb1";
> +               };
> +
> +               ovc {
> +                       pins = "GP_6_27";
> +                       bias-pull-up;
> +               };
> +
> +               pwen {
> +                       pins = "GP_6_26";
> +                       bias-pull-down;
> +               };
> +       };

R-Car M3Le does not have the second USB2 channel.

> +};
> +
> +&pwm1 {
> +       pinctrl-0 = <&pwm1_pins>;
> +       pinctrl-names = "default";
> +
> +       status = "okay";
> +};
> +
> +&pwm2 {
> +       pinctrl-0 = <&pwm2_pins>;
> +       pinctrl-names = "default";
> +
> +       status = "okay";
> +};

What is pwm2 used for?

> +
> +&rcar_sound {
> +       pinctrl-0 = <&sound_pins>, <&sound_clk_pins>;
> +       pinctrl-names = "default";
> +
> +       /* Single DAI */
> +       #sound-dai-cells = <0>;
> +
> +       /* audio_clkout0/1/2/3 */
> +       #clock-cells = <1>;
> +       clock-frequency = <12288000 11289600>;
> +
> +       status = "okay";
> +
> +       /* update <audio_clk_b> to <cs2500> */
> +       clocks = <&cpg CPG_MOD 1005>,
> +                <&cpg CPG_MOD 1006>, <&cpg CPG_MOD 1007>,
> +                <&cpg CPG_MOD 1008>, <&cpg CPG_MOD 1009>,
> +                <&cpg CPG_MOD 1010>, <&cpg CPG_MOD 1011>,
> +                <&cpg CPG_MOD 1012>, <&cpg CPG_MOD 1013>,
> +                <&cpg CPG_MOD 1014>, <&cpg CPG_MOD 1015>,
> +                <&cpg CPG_MOD 1022>, <&cpg CPG_MOD 1023>,
> +                <&cpg CPG_MOD 1024>, <&cpg CPG_MOD 1025>,
> +                <&cpg CPG_MOD 1026>, <&cpg CPG_MOD 1027>,
> +                <&cpg CPG_MOD 1028>, <&cpg CPG_MOD 1029>,
> +                <&cpg CPG_MOD 1030>, <&cpg CPG_MOD 1031>,
> +                <&cpg CPG_MOD 1020>, <&cpg CPG_MOD 1021>,
> +                <&cpg CPG_MOD 1020>, <&cpg CPG_MOD 1021>,
> +                <&cpg CPG_MOD 1019>, <&cpg CPG_MOD 1018>,
> +                <&audio_clk_a>, <&cs2500>,
> +                <&audio_clk_c>,
> +                <&cpg CPG_MOD 922>;
> +
> +       ports {
> +               #address-cells = <1>;
> +               #size-cells = <0>;
> +
> +               rsnd_port0: port {

port@0 {
        reg = <0>;

> +                       rsnd_endpoint0: endpoint {
> +                               remote-endpoint = <&ak4619_endpoint>;
> +                               dai-format = "left_j";
> +                               bitclock-master = <&rsnd_endpoint0>;
> +                               frame-master = <&rsnd_endpoint0>;
> +                               playback = <&ssi0>, <&src0>, <&dvc0>;
> +                               capture = <&ssi1>, <&src1>, <&dvc1>;
> +                       };
> +               };
> +       };
> +};
> +
> +&rwdt {
> +       timeout-sec = <60>;
> +       status = "okay";
> +};
> +
> +&scif1 {
> +       pinctrl-0 = <&scif1_pins>;
> +       pinctrl-names = "default";
> +
> +       uart-has-rtscts;
> +       /* Please only enable hscif1 or scif1 */
> +       /* status = "okay"; */
> +};
> +
> +&scif2 {
> +       pinctrl-0 = <&scif2_pins>;
> +       pinctrl-names = "default";
> +
> +       status = "okay";
> +};
> +
> +&scif_clk {
> +       clock-frequency = <14745600>;
> +};
> +
> +&sdhi0 {
> +       pinctrl-0 = <&sdhi0_pins>;
> +       pinctrl-1 = <&sdhi0_pins_uhs>;
> +       pinctrl-names = "default", "state_uhs";
> +
> +       vmmc-supply = <&vcc_sdhi0>;
> +       vqmmc-supply = <&vccq_sdhi0>;
> +       cd-gpios = <&gpio3 12 GPIO_ACTIVE_LOW>;
> +       wp-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
> +       bus-width = <4>;
> +       sd-uhs-sdr50;
> +       sd-uhs-sdr104;
> +       status = "okay";
> +};
> +
> +&sdhi2 {
> +       /* used for on-board 8bit eMMC */
> +       pinctrl-0 = <&sdhi2_pins>;
> +       pinctrl-1 = <&sdhi2_pins>;
> +       pinctrl-names = "default", "state_uhs";
> +
> +       iommus = <&ipmmu_ds1 34>;

This belongs in the .dtsi file, and it is already there.

> +
> +       vmmc-supply = <&reg_3p3v>;
> +       vqmmc-supply = <&reg_1p8v>;
> +       bus-width = <8>;
> +       mmc-hs200-1_8v;
> +       no-sd;
> +       no-sdio;
> +       non-removable;
> +       fixed-emmc-driver-type = <1>;
> +       full-pwr-cycle-in-suspend;
> +       status = "okay";
> +};
> +
> +&ssi1 {
> +       shared-pin;
> +};
> +
> +&usb_extal_clk {
> +       clock-frequency = <50000000>;
> +};
> +
> +&usb2_phy0 {
> +       pinctrl-0 = <&usb0_pins>;
> +       pinctrl-names = "default";
> +
> +       vbus-supply = <&vbus0_usb2>;
> +       status = "okay";
> +};
> +
> +&usb2_phy1 {
> +       pinctrl-0 = <&usb1_pins>;
> +       pinctrl-names = "default";
> +
> +       status = "okay";
> +};

R-Car M3Le does not have the second USB2 channel.


Gr{oetje,eeting}s,

                        Geert

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

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


^ permalink raw reply

* [PATCH] drm/ipv3: add CONFIG_OF dependency for DRM_OF_DISPLAY_MODE_BRIDGE
From: Arnd Bergmann @ 2026-04-29 14:00 UTC (permalink / raw)
  To: Philipp Zabel, Maarten Lankhorst, Maxime Ripard,
	Thomas Zimmermann, David Airlie, Simona Vetter, Frank Li,
	Sascha Hauer, Luca Ceresoli, Damon Ding
  Cc: Arnd Bergmann, Pengutronix Kernel Team, Fabio Estevam, dri-devel,
	imx, linux-arm-kernel, linux-kernel

From: Arnd Bergmann <arnd@arndb.de>

Without this, not all dependencies are met here.

  Depends on [n]: HAS_IOMEM [=y] && DRM [=y] && DRM_BRIDGE [=y] && OF [=n]
  Selected by [y]:
  - DRM_IMX_PARALLEL_DISPLAY [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_IMX [=y]
  - DRM_IMX_LDB [=y] && HAS_IOMEM [=y] && DRM [=y] && DRM_IMX [=y] && COMMON_CLK [=y]

Fixes: ba2db93cf3d5 ("drm/bridge: Move legacy bridge driver out of imx directory for multi-platform use")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/gpu/drm/imx/ipuv3/Kconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/gpu/drm/imx/ipuv3/Kconfig b/drivers/gpu/drm/imx/ipuv3/Kconfig
index 351dc65913eb..3ca237515e46 100644
--- a/drivers/gpu/drm/imx/ipuv3/Kconfig
+++ b/drivers/gpu/drm/imx/ipuv3/Kconfig
@@ -13,6 +13,7 @@ config DRM_IMX
 config DRM_IMX_PARALLEL_DISPLAY
 	tristate "Support for parallel displays"
 	depends on DRM_IMX
+	depends on OF
 	select DRM_BRIDGE
 	select DRM_BRIDGE_CONNECTOR
 	select DRM_DISPLAY_HELPER
@@ -33,6 +34,7 @@ config DRM_IMX_LDB
 	tristate "Support for LVDS displays"
 	depends on DRM_IMX
 	depends on COMMON_CLK
+	depends on OF
 	select MFD_SYSCON
 	select DRM_BRIDGE
 	select DRM_BRIDGE_CONNECTOR
-- 
2.39.5



^ permalink raw reply related

* Re: [DONOTAPPLY RFC PATCH v2 0/4] WiFi support for samsung,coreprimevelte
From: Karel Balej @ 2026-04-29 13:47 UTC (permalink / raw)
  To: Francesco Dolcini
  Cc: Brian Norris, Johannes Berg, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Duje Mihanović, Andrew Lunn, Gregory Clement,
	Sebastian Hesselbarth, Ulf Hansson, Frank Li, linux-wireless,
	devicetree, linux-kernel, linux-arm-kernel, linux-mmc,
	~postmarketos/upstreaming, phone-devel, Jeff Chen, Peng Fan,
	david
In-Reply-To: <20260429134011.GA73482@francesco-nb>

Francesco Dolcini, 2026-04-29T15:40:11+02:00:
> I do not see any way forward without NXP.

Probably not for the firmware, no. That's why I'm asking Brian if it
would be possible to get the kernel support in without it as in the
Apple case, or whether there are any other options.

Karel


^ permalink raw reply

* Re: [PATCH v4 15/15] arm64: mm: Remap linear aliases of the fixmap page tables read-only
From: Ard Biesheuvel @ 2026-04-29 14:08 UTC (permalink / raw)
  To: Kevin Brodsky, Ard Biesheuvel, linux-arm-kernel
  Cc: linux-kernel, Will Deacon, Catalin Marinas, Mark Rutland,
	Ryan Roberts, Anshuman Khandual, Liz Prucka, Seth Jenkins,
	Kees Cook, Mike Rapoport, David Hildenbrand, Andrew Morton,
	linux-mm, linux-hardening
In-Reply-To: <21a547ae-7121-4cd1-b203-4d8182eb7cc9@arm.com>

Hi Ard,

On Wed, 29 Apr 2026, at 15:57, Kevin Brodsky wrote:
> On 27/04/2026 17:34, Ard Biesheuvel wrote:
>> [...]
>>
>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>> index 84d81bae07a7..e76fe5b0c5fe 100644
>> --- a/arch/arm64/mm/mmu.c
>> +++ b/arch/arm64/mm/mmu.c
>> @@ -1076,6 +1076,11 @@ void __init mark_linear_text_alias_ro(void)
>>  			    (unsigned long)__init_begin - (unsigned long)_text,
>>  			    pgprot_tagged(PAGE_KERNEL_RO));
>>  
>> +	/* Map the fixmap PTE table at __fixmap_pgdir_start R/O in linear map too */
>> +	update_mapping_prot(__pa_symbol(__fixmap_pgdir_start),
>> +			    (unsigned long)lm_alias(__fixmap_pgdir_start),
>> +			    PAGE_SIZE, pgprot_tagged(PAGE_KERNEL_RO));
>
> Is that definitely just one page?
>

No it most definitely is not - thanks for spotting that :-)


^ permalink raw reply

* [PATCH 0/5] arm_mpam: Add MPAM-Fb firmware support
From: Andre Przywara @ 2026-04-29 14:13 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
	Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
	Ben Horgan, Reinette Chatre, Fenghua Yu
  Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel

The Arm MPAM specification defines Memory System Components (MSCs),
which are devices that are programmed through an MMIO register frame. In
some occasions this turned out to be too limiting: the MSC might be
located behind a separate bus system (for instance inside an on-board
controller), it might be mapped secure-only, or in a different processor
socket without direct MMIO mapping. Also the MMIO access might be too slow
or it would need to be filtered or otherwise access controlled. Finally
there might be bugs in the MSC integration, which require a mediating
firmware to be accessible.

To accommodate all those different use cases, the MPAM-Fb specification
[1] describes an alternative way to access MSCs. Accesses to an MSC
would be wrapped in a message and communicated to the system using a
shared-memory/mailbox system mostly mimicking the Arm SCMI spec.
For ACPI systems, this would be abstracted through an ACPI PCC channel,
which provides the shared-memory region and the mailbox trigger. We can
lean on existing ACPI parsing code to register with these two
subsystems, but cannot rely on the existing SCMI code in the kernel.
This means we somewhat need to open code a very simplified SCMI handler,
which just provides enough functionality for the very basic subset of
SCMI that the MPAM-Fb spec requires.

Patch 1/5 adds more ACPI parsing code, to be able to learn all the
information we need.
Patch 2/5 solves a nasty problem: At the moment we protect stateful MSC
register accesses (mon_sel) through a spinlock. Unfortunately the mailbox
subsystem and the slow nature of the communication through this channel
forbid MPAM-Fb access in atomic context. So this patch splits the lock
in two: the "outer" one is a mutex, and only the inner one is a
spinlock, which would need to be taken when programming MSCs inside an
interrupt handler, for instance. We just deny the latter when using
MPAM-Fb, ideally we wouldn't need that (no need to IPI another core when
the MSC access does not need to be local to one particular core), or we
simply deny that part of the functionality (access through perf).
Patch 3/5 adds the code to redirect MSC accesses through the
shmem/mailbox system.
Patch 4/5 avoids the error IRQ handler to do an MSC access when using
MPAM_Fb, since those accesses cannot run in atomic context.
The final patch 5/5 then adds the code to detect and store the PCC
channel information from the ACPI tables, and eventually enables
MPAM-Fb accesses.

This would enable systems where some MSCs are not accessible via MMIO to
use those components anyway.

Please have a look and test!

Cheers,
Andre

[1] https://developer.arm.com/documentation/den0144/latest

Andre Przywara (3):
  arm_mpam: add MPAM-Fb MSC firmware access support
  arm_mpam: prevent MPAM-Fb accesses inside IRQ handler
  arm_mpam: detect and enable MPAM-Fb PCC support

James Morse (2):
  arm_mpam: Parse the rest of the ACPI table
  arm_mpam: Split the locking around the mon_sel registers

 drivers/acpi/arm64/mpam.c       |  93 ++++++++++++++++++-
 drivers/resctrl/Makefile        |   2 +-
 drivers/resctrl/mpam_devices.c  | 148 ++++++++++++++++++++++++------
 drivers/resctrl/mpam_fb.c       | 158 ++++++++++++++++++++++++++++++++
 drivers/resctrl/mpam_fb.h       |  17 ++++
 drivers/resctrl/mpam_internal.h |  72 +++++++++++----
 include/linux/arm_mpam.h        |   2 +-
 7 files changed, 439 insertions(+), 53 deletions(-)
 create mode 100644 drivers/resctrl/mpam_fb.c
 create mode 100644 drivers/resctrl/mpam_fb.h

-- 
2.43.0



^ permalink raw reply

* [PATCH 2/5] arm_mpam: Split the locking around the mon_sel registers
From: Andre Przywara @ 2026-04-29 14:13 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
	Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
	Ben Horgan, Reinette Chatre, Fenghua Yu
  Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260429141339.3171205-1-andre.przywara@arm.com>

From: James Morse <james.morse@arm.com>

The MSC MON_SEL register needs to be accessed from hardirq for the overflow
interrupt, and when taking an IPI to access these registers on platforms
where MSC are not accesible from every CPU. This makes an irqsave
spinlock the obvious lock to protect these registers. On systems with SCMI
mailboxes it must be able to sleep, meaning a mutex must be used. The
SCMI platforms can't support an overflow interrupt.

Clearly these two can't exist for one MSC at the same time.

Split the existing helper into a raw spinlock and a mutex, named inner
and outer. The outer lock must be taken in an a pre-emptible context
befroe the inner lock can be taken. On systems with SCMI mailboxes
where the MON_SEL accesses must sleep - the inner lock will fail tobe
taken if the caller is unable to sleep.
This will allow callers to fail withuot having to explicitly check
the interface type of each MSC.

Signed-off-by: James Morse <james.morse@arm.com>
---
 drivers/resctrl/mpam_devices.c  | 56 ++++++++++++++++++++-------
 drivers/resctrl/mpam_internal.h | 67 ++++++++++++++++++++++++---------
 2 files changed, 91 insertions(+), 32 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 41b14344b16f..3be09b0c46ae 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -735,7 +735,7 @@ static bool _mpam_ris_hw_probe_hw_nrdy(struct mpam_msc_ris *ris, u32 mon_reg)
 	bool can_set, can_clear;
 	struct mpam_msc *msc = ris->vmsc->msc;
 
-	if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc)))
+	if (WARN_ON_ONCE(!mpam_mon_sel_inner_lock(msc)))
 		return false;
 
 	mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, 0) |
@@ -749,7 +749,7 @@ static bool _mpam_ris_hw_probe_hw_nrdy(struct mpam_msc_ris *ris, u32 mon_reg)
 	_mpam_write_monsel_reg(msc, mon_reg, 0);
 	now = _mpam_read_monsel_reg(msc, mon_reg);
 	can_clear = !(now & MSMON___NRDY);
-	mpam_mon_sel_unlock(msc);
+	mpam_mon_sel_inner_unlock(msc);
 
 	return (!can_set || !can_clear);
 }
@@ -873,7 +873,9 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
 					mpam_set_feature(mpam_feat_msmon_csu_xcl, props);
 
 				/* Is NRDY hardware managed? */
+				mpam_mon_sel_outer_lock(msc);
 				hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, CSU);
+				mpam_mon_sel_outer_unlock(msc);
 				if (hw_managed)
 					mpam_set_feature(mpam_feat_msmon_csu_hw_nrdy, props);
 			}
@@ -907,7 +909,9 @@ static void mpam_ris_hw_probe(struct mpam_msc_ris *ris)
 				}
 
 				/* Is NRDY hardware managed? */
+				mpam_mon_sel_outer_lock(msc);
 				hw_managed = mpam_ris_hw_probe_hw_nrdy(ris, MBWU);
+				mpam_mon_sel_outer_unlock(msc);
 				if (hw_managed)
 					mpam_set_feature(mpam_feat_msmon_mbwu_hw_nrdy, props);
 
@@ -1201,7 +1205,7 @@ static void __ris_msmon_read(void *arg)
 	struct mpam_msc *msc = m->ris->vmsc->msc;
 	u32 mon_sel, ctl_val, flt_val, cur_ctl, cur_flt;
 
-	if (!mpam_mon_sel_lock(msc)) {
+	if (!mpam_mon_sel_inner_lock(msc)) {
 		m->err = -EIO;
 		return;
 	}
@@ -1301,7 +1305,7 @@ static void __ris_msmon_read(void *arg)
 	default:
 		m->err = -EINVAL;
 	}
-	mpam_mon_sel_unlock(msc);
+	mpam_mon_sel_inner_unlock(msc);
 
 	if (nrdy)
 		m->err = -EBUSY;
@@ -1323,6 +1327,7 @@ static int _msmon_read(struct mpam_component *comp, struct mon_read *arg)
 		struct mpam_msc *msc = vmsc->msc;
 		struct mpam_msc_ris *ris;
 
+		mpam_mon_sel_outer_lock(msc);
 		list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list,
 					 srcu_read_lock_held(&mpam_srcu)) {
 			arg->ris = ris;
@@ -1341,6 +1346,7 @@ static int _msmon_read(struct mpam_component *comp, struct mon_read *arg)
 			if (err)
 				any_err = err;
 		}
+		mpam_mon_sel_outer_unlock(msc);
 	}
 
 	return any_err;
@@ -1423,18 +1429,20 @@ void mpam_msmon_reset_mbwu(struct mpam_component *comp, struct mon_cfg *ctx)
 			continue;
 
 		msc = vmsc->msc;
+		mpam_mon_sel_outer_lock(msc);
 		list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list,
 					 srcu_read_lock_held(&mpam_srcu)) {
 			if (!mpam_has_feature(mpam_feat_msmon_mbwu, &ris->props))
 				continue;
 
-			if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc)))
+			if (WARN_ON_ONCE(!mpam_mon_sel_inner_lock(msc)))
 				continue;
 
 			ris->mbwu_state[ctx->mon].correction = 0;
 			ris->mbwu_state[ctx->mon].reset_on_next_read = true;
-			mpam_mon_sel_unlock(msc);
+			mpam_mon_sel_inner_unlock(msc);
 		}
+		mpam_mon_sel_outer_unlock(msc);
 	}
 }
 
@@ -1635,8 +1643,11 @@ static int mpam_restore_mbwu_state(void *_ris)
 	u64 val;
 	struct mon_read mwbu_arg;
 	struct mpam_msc_ris *ris = _ris;
+	struct mpam_msc *msc = ris->vmsc->msc;
 	struct mpam_class *class = ris->vmsc->comp->class;
 
+	mpam_mon_sel_outer_lock(msc);
+
 	for (i = 0; i < ris->props.num_mbwu_mon; i++) {
 		if (ris->mbwu_state[i].enabled) {
 			mwbu_arg.ris = ris;
@@ -1648,10 +1659,12 @@ static int mpam_restore_mbwu_state(void *_ris)
 		}
 	}
 
+	mpam_mon_sel_outer_unlock(msc);
+
 	return 0;
 }
 
-/* Call with MSC cfg_lock held */
+/* Call with MSC cfg_lock and outer mon_sel lock held */
 static int mpam_save_mbwu_state(void *arg)
 {
 	int i;
@@ -1666,7 +1679,7 @@ static int mpam_save_mbwu_state(void *arg)
 		mbwu_state = &ris->mbwu_state[i];
 		cfg = &mbwu_state->cfg;
 
-		if (WARN_ON_ONCE(!mpam_mon_sel_lock(msc)))
+		if (WARN_ON_ONCE(!mpam_mon_sel_inner_lock(msc)))
 			return -EIO;
 
 		mon_sel = FIELD_PREP(MSMON_CFG_MON_SEL_MON_SEL, i) |
@@ -1691,7 +1704,7 @@ static int mpam_save_mbwu_state(void *arg)
 		cfg->partid = FIELD_GET(MSMON_CFG_x_FLT_PARTID, cur_flt);
 		mbwu_state->correction += val;
 		mbwu_state->enabled = FIELD_GET(MSMON_CFG_x_CTL_EN, cur_ctl);
-		mpam_mon_sel_unlock(msc);
+		mpam_mon_sel_inner_unlock(msc);
 	}
 
 	return 0;
@@ -1773,6 +1786,7 @@ static void mpam_reprogram_msc(struct mpam_msc *msc)
 	mpam_assert_partid_sizes_fixed();
 
 	mutex_lock(&msc->cfg_lock);
+	mpam_mon_sel_outer_lock(msc);
 	list_for_each_entry_srcu(ris, &msc->ris, msc_list,
 				 srcu_read_lock_held(&mpam_srcu)) {
 		if (!mpam_is_enabled() && !ris->in_reset_state) {
@@ -1797,6 +1811,7 @@ static void mpam_reprogram_msc(struct mpam_msc *msc)
 		if (mpam_has_feature(mpam_feat_msmon_mbwu, &ris->props))
 			mpam_touch_msc(msc, &mpam_restore_mbwu_state, ris);
 	}
+	mpam_mon_sel_outer_unlock(msc);
 	mutex_unlock(&msc->cfg_lock);
 }
 
@@ -1886,6 +1901,7 @@ static int mpam_cpu_offline(unsigned int cpu)
 			struct mpam_msc_ris *ris;
 
 			mutex_lock(&msc->cfg_lock);
+			mpam_mon_sel_outer_lock(msc);
 			list_for_each_entry_srcu(ris, &msc->ris, msc_list,
 						 srcu_read_lock_held(&mpam_srcu)) {
 				mpam_touch_msc(msc, &mpam_reset_ris, ris);
@@ -1899,6 +1915,7 @@ static int mpam_cpu_offline(unsigned int cpu)
 				if (mpam_is_enabled())
 					mpam_touch_msc(msc, &mpam_save_mbwu_state, ris);
 			}
+			mpam_mon_sel_outer_unlock(msc);
 			mutex_unlock(&msc->cfg_lock);
 		}
 	}
@@ -2589,11 +2606,13 @@ static void __destroy_component_cfg(struct mpam_component *comp)
 	list_for_each_entry(vmsc, &comp->vmsc, comp_list) {
 		msc = vmsc->msc;
 
-		if (mpam_mon_sel_lock(msc)) {
+		mpam_mon_sel_outer_lock(msc);
+		if (mpam_mon_sel_inner_lock(msc)) {
 			list_for_each_entry(ris, &vmsc->ris, vmsc_list)
 				add_to_garbage(ris->mbwu_state);
-			mpam_mon_sel_unlock(msc);
+			mpam_mon_sel_inner_unlock(msc);
 		}
+		mpam_mon_sel_outer_unlock(msc);
 	}
 }
 
@@ -2640,6 +2659,7 @@ static int __allocate_component_cfg(struct mpam_component *comp)
 	mpam_reset_component_cfg(comp);
 
 	list_for_each_entry(vmsc, &comp->vmsc, comp_list) {
+		int err = 0;
 		struct mpam_msc *msc;
 		struct mpam_msc_ris *ris;
 		struct msmon_mbwu_state *mbwu_state;
@@ -2648,6 +2668,7 @@ static int __allocate_component_cfg(struct mpam_component *comp)
 			continue;
 
 		msc = vmsc->msc;
+		mpam_mon_sel_outer_lock(msc);
 		list_for_each_entry(ris, &vmsc->ris, vmsc_list) {
 			if (!ris->props.num_mbwu_mon)
 				continue;
@@ -2656,16 +2677,21 @@ static int __allocate_component_cfg(struct mpam_component *comp)
 						  ris->props.num_mbwu_mon);
 			if (!mbwu_state) {
 				__destroy_component_cfg(comp);
-				return -ENOMEM;
+				err = -ENOMEM;
+				break;
 			}
 
 			init_garbage(&mbwu_state[0].garbage);
 
-			if (mpam_mon_sel_lock(msc)) {
+			if (mpam_mon_sel_inner_lock(msc)) {
 				ris->mbwu_state = mbwu_state;
-				mpam_mon_sel_unlock(msc);
+				mpam_mon_sel_inner_unlock(msc);
 			}
 		}
+		mpam_mon_sel_outer_unlock(msc);
+
+		if (err)
+			return err;
 	}
 
 	return 0;
@@ -2918,12 +2944,14 @@ int mpam_apply_config(struct mpam_component *comp, u16 partid,
 		msc = vmsc->msc;
 
 		mutex_lock(&msc->cfg_lock);
+		mpam_mon_sel_outer_lock(msc);
 		list_for_each_entry_srcu(ris, &vmsc->ris, vmsc_list,
 					 srcu_read_lock_held(&mpam_srcu)) {
 			arg.ris = ris;
 			mpam_touch_msc(msc, __write_config, &arg);
 			ris->in_reset_state = false;
 		}
+		mpam_mon_sel_outer_unlock(msc);
 		mutex_unlock(&msc->cfg_lock);
 	}
 
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 1914aefdcba9..80213af10a64 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -116,16 +116,20 @@ struct mpam_msc {
 	/*
 	 * mon_sel_lock protects access to the MSC hardware registers that are
 	 * affected by MPAMCFG_MON_SEL, and the mbwu_state.
-	 * Access to mon_sel is needed from both process and interrupt contexts,
-	 * but is complicated by firmware-backed platforms that can't make any
-	 * access unless they can sleep.
-	 * Always use the mpam_mon_sel_lock() helpers.
-	 * Accesses to mon_sel need to be able to fail if they occur in the wrong
-	 * context.
+	 * Both the 'inner' and 'outer' must be taken.
+	 * For real MMIO MSC, the outer lock is unnecessary - but keeps the
+	 * code common with:
+	 * Firmware backed MSC need to sleep when accessing the MSC, which
+	 * means some code-paths will always fail. For these MSC the outer
+	 * lock is providing the protection, and the inner lock fails to
+	 * be taken if the task is unable to sleep.
+	 *
 	 * If needed, take msc->probe_lock first.
 	 */
-	raw_spinlock_t		_mon_sel_lock;
-	unsigned long		_mon_sel_flags;
+	struct mutex		outer_mon_sel_lock;
+	bool			outer_lock_held;
+	raw_spinlock_t		inner_mon_sel_lock;
+	unsigned long		inner_mon_sel_flags;
 
 	void __iomem		*mapped_hwpage;
 	size_t			mapped_hwpage_sz;
@@ -137,29 +141,56 @@ struct mpam_msc {
 };
 
 /* Returning false here means accesses to mon_sel must fail and report an error. */
-static inline bool __must_check mpam_mon_sel_lock(struct mpam_msc *msc)
+static inline bool __must_check mpam_mon_sel_inner_lock(struct mpam_msc *msc)
 {
-	/* Locking will require updating to support a firmware backed interface */
-	if (WARN_ON_ONCE(msc->iface != MPAM_IFACE_MMIO))
-		return false;
+	/*
+	 * The outer lock may be taken by a CPU that then issues an IPI to run
+	 * a helper that takes the inner lock. lockdep can't help us here.
+	 */
+	WARN_ON_ONCE(!READ_ONCE(msc->outer_lock_held));
+
+	if (msc->iface == MPAM_IFACE_MMIO) {
+		raw_spin_lock_irqsave(&msc->inner_mon_sel_lock, msc->inner_mon_sel_flags);
+		return true;
+	}
+
+	/* Accesses must fail if we are not pre-emptible */
+	return !!preemptible();
+}
 
-	raw_spin_lock_irqsave(&msc->_mon_sel_lock, msc->_mon_sel_flags);
-	return true;
+static inline void mpam_mon_sel_inner_unlock(struct mpam_msc *msc)
+{
+	WARN_ON_ONCE(!READ_ONCE(msc->outer_lock_held));
+
+	if (msc->iface == MPAM_IFACE_MMIO)
+		raw_spin_unlock_irqrestore(&msc->inner_mon_sel_lock, msc->inner_mon_sel_flags);
+}
+
+static inline void mpam_mon_sel_outer_lock(struct mpam_msc *msc)
+{
+	mutex_lock(&msc->outer_mon_sel_lock);
+	msc->outer_lock_held = true;
 }
 
-static inline void mpam_mon_sel_unlock(struct mpam_msc *msc)
+static inline void mpam_mon_sel_outer_unlock(struct mpam_msc *msc)
 {
-	raw_spin_unlock_irqrestore(&msc->_mon_sel_lock, msc->_mon_sel_flags);
+	msc->outer_lock_held = false;
+	mutex_unlock(&msc->outer_mon_sel_lock);
 }
 
 static inline void mpam_mon_sel_lock_held(struct mpam_msc *msc)
 {
-	lockdep_assert_held_once(&msc->_mon_sel_lock);
+	WARN_ON_ONCE(!READ_ONCE(msc->outer_lock_held));
+	if (msc->iface == MPAM_IFACE_MMIO)
+		lockdep_assert_held_once(&msc->inner_mon_sel_lock);
+	else
+		lockdep_assert_preemption_enabled();
 }
 
 static inline void mpam_mon_sel_lock_init(struct mpam_msc *msc)
 {
-	raw_spin_lock_init(&msc->_mon_sel_lock);
+	raw_spin_lock_init(&msc->inner_mon_sel_lock);
+	mutex_init(&msc->outer_mon_sel_lock);
 }
 
 /* Bits for mpam features bitmaps */
-- 
2.43.0



^ permalink raw reply related

* [PATCH 1/5] arm_mpam: Parse the rest of the ACPI table
From: Andre Przywara @ 2026-04-29 14:13 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
	Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
	Ben Horgan, Reinette Chatre, Fenghua Yu
  Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260429141339.3171205-1-andre.przywara@arm.com>

From: James Morse <james.morse@arm.com>

The MPAM ACPI table lists the MPAM MSCs and indicates which resources
in the system they control. Not everything this table can describe is
supported by resctrl, e.g. memory-side-caches.

Add the additional table parsing to avoid reporting these as 'unknown'
to the MPAM driver. This allows class+component hierarchys to be built.

Until resctrl has support for any of these resources, users would be
in-kernel managers of a resource/PARTID or perf to query bandwidth
counters on a resource resctrl is unaware of.

Signed-off-by: James Morse <james.morse@arm.com>
Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 drivers/acpi/arm64/mpam.c | 91 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 88 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/arm64/mpam.c b/drivers/acpi/arm64/mpam.c
index 84963a20c3e7..99c2bdbb3314 100644
--- a/drivers/acpi/arm64/mpam.c
+++ b/drivers/acpi/arm64/mpam.c
@@ -95,17 +95,51 @@ static void acpi_mpam_parse_irqs(struct platform_device *pdev,
 		res[(*res_idx)++] = DEFINE_RES_IRQ_NAMED(irq, "error");
 }
 
-static int acpi_mpam_parse_resource(struct mpam_msc *msc,
+#define UUID_MPAM_INTERCONNECT_TABLE		"fe2bd645-033b-49e6-9479-2e0b8b21d1cd"
+
+struct acpi_mpam_interconnect_descriptor_table {
+	u8	type_uuid[16];
+	u32	num_descriptors;
+};
+
+struct acpi_mpam_interconnect_descriptor {
+	u32	source_id;
+	u32	destination_id;
+	u8	link_type;
+	u8	reserved[3];
+};
+
+static int acpi_mpam_parse_resource(struct acpi_mpam_msc_node *tbl_msc,
+				    struct mpam_msc *msc,
 				    struct acpi_mpam_resource_node *res)
 {
+	struct acpi_mpam_interconnect_descriptor_table *tbl_int_tbl;
+	struct acpi_mpam_interconnect_descriptor *tbl_int;
+	guid_t int_tbl_uuid, spec_uuid;
 	int level, nid;
 	u32 cache_id;
+	off_t offset;
 
+	/*
+	 * Class IDs are somewhat arbitrary, but need to be co-ordinated.
+	 * 0-N are caches,
+	 * 64, 65: Interconnect, but ideally these would appear between the
+	 *     classes the controls are adjacent to.
+	 * 128: SMMU,
+	 * 192-192+level: Memory Side Caches, nothing checks that N is a
+	 *                small number.
+	 * 255: Memory Controllers
+	 *
+	 * ACPI devices would need a class id allocated based on the _HID.
+	 *
+	 * Classes that the mpam driver can't currently plumb into resctrl
+	 * are registered as UNKNOWN.
+	 */
 	switch (res->locator_type) {
 	case ACPI_MPAM_LOCATION_TYPE_PROCESSOR_CACHE:
 		cache_id = res->locator.cache_locator.cache_reference;
 		level = find_acpi_cache_level_from_id(cache_id);
-		if (level <= 0) {
+		if (level <= 0 || level >= 64) {
 			pr_err_once("Bad level (%d) for cache with id %u\n", level, cache_id);
 			return -EINVAL;
 		}
@@ -120,6 +154,57 @@ static int acpi_mpam_parse_resource(struct mpam_msc *msc,
 		}
 		return mpam_ris_create(msc, res->ris_index, MPAM_CLASS_MEMORY,
 				       MPAM_CLASS_ID_DEFAULT, nid);
+	case ACPI_MPAM_LOCATION_TYPE_SMMU:
+		return mpam_ris_create(msc, res->ris_index, MPAM_CLASS_UNKNOWN,
+				       128, res->locator.smmu_locator.smmu_interface);
+	case ACPI_MPAM_LOCATION_TYPE_MEMORY_CACHE:
+		cache_id = res->locator.mem_cache_locator.reference;
+		level = res->locator.mem_cache_locator.level;
+		if (192 + level >= 255) {
+			pr_err_once("Bad level for memory side cache with reference %u\n",
+				    cache_id);
+			return -EINVAL;
+		}
+
+		return mpam_ris_create(msc, res->ris_index, MPAM_CLASS_CACHE,
+				       192 + level, cache_id);
+
+	case ACPI_MPAM_LOCATION_TYPE_INTERCONNECT:
+		/* Find the descriptor table, and check it lands in the parent msc */
+		offset = res->locator.interconnect_ifc_locator.inter_connect_desc_tbl_off;
+		if (offset >= tbl_msc->length) {
+			pr_err_once("Bad offset for interconnect descriptor on msc %u\n",
+				    tbl_msc->identifier);
+			return -EINVAL;
+		}
+		tbl_int_tbl = ACPI_ADD_PTR(struct acpi_mpam_interconnect_descriptor_table,
+					   tbl_msc, offset);
+		guid_parse(UUID_MPAM_INTERCONNECT_TABLE, &spec_uuid);
+		import_guid(&int_tbl_uuid, tbl_int_tbl->type_uuid);
+		if (guid_equal(&spec_uuid, &int_tbl_uuid)) {
+			pr_err_once("Bad UUID for interconnect descriptor on msc %u\n",
+				    tbl_msc->identifier);
+			return -EINVAL;
+		}
+
+		offset += sizeof(*tbl_int_tbl);
+		offset += tbl_int_tbl->num_descriptors * sizeof(*tbl_int);
+		if (offset >= tbl_msc->length) {
+			pr_err_once("Bad num_descriptors for interconnect descriptor on msc %u\n",
+				    tbl_msc->identifier);
+			return -EINVAL;
+		}
+
+		tbl_int = ACPI_ADD_PTR(struct acpi_mpam_interconnect_descriptor,
+				       tbl_int_tbl, sizeof(*tbl_int_tbl));
+		cache_id = tbl_int->source_id;
+
+		/* Unknown link type? */
+		if (tbl_int->link_type != 0 && tbl_int->link_type == 1)
+			return 0;
+
+		return mpam_ris_create(msc, res->ris_index, MPAM_CLASS_UNKNOWN,
+				       64 + tbl_int->link_type, cache_id);
 	default:
 		/* These get discovered later and are treated as unknown */
 		return 0;
@@ -150,7 +235,7 @@ int acpi_mpam_parse_resources(struct mpam_msc *msc,
 			return -EINVAL;
 		}
 
-		err = acpi_mpam_parse_resource(msc, resource);
+		err = acpi_mpam_parse_resource(tbl_msc, msc, resource);
 		if (err)
 			return err;
 
-- 
2.43.0



^ permalink raw reply related

* [PATCH 3/5] arm_mpam: add MPAM-Fb MSC firmware access support
From: Andre Przywara @ 2026-04-29 14:13 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
	Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
	Ben Horgan, Reinette Chatre, Fenghua Yu
  Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260429141339.3171205-1-andre.przywara@arm.com>

The Arm MPAM Firmware-backed (Fb) Profile document[1] describes an
alternative way of accessing the "Memory System Components" (MSC) in an
MPAM enabled system.
Normally the MSCs are MMIO mapped, but in some implementations this
might not be possible (MSC located outside of the local socket, MSC
mapped secure-only) or desirable (direct MMIO access too slow or needs
to be mediated through a control processor). MPAM-fb standardises a
protocol to abstract MSC accesses, building on the SCMI protocol.

Add functions that do an MSC read or write access by redirecting the
request through a firmware interface. For now this done via an ACPI
PCC shared memory and mailbox combination.

Since the protocol used is only a small subset of the full SCMI spec,
and the SCMI protocol has no full ACPI support anyway, open-code the
SCMI message generation and handshake, for just the fields we need.

[1] https://developer.arm.com/documentation/den0144/latest

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 drivers/resctrl/Makefile        |   2 +-
 drivers/resctrl/mpam_devices.c  |  16 +++-
 drivers/resctrl/mpam_fb.c       | 158 ++++++++++++++++++++++++++++++++
 drivers/resctrl/mpam_fb.h       |  17 ++++
 drivers/resctrl/mpam_internal.h |   5 +
 include/linux/arm_mpam.h        |   2 +-
 6 files changed, 196 insertions(+), 4 deletions(-)
 create mode 100644 drivers/resctrl/mpam_fb.c
 create mode 100644 drivers/resctrl/mpam_fb.h

diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
index 4f6d0e81f9b8..097c036724e9 100644
--- a/drivers/resctrl/Makefile
+++ b/drivers/resctrl/Makefile
@@ -1,5 +1,5 @@
 obj-$(CONFIG_ARM64_MPAM_DRIVER)			+= mpam.o
-mpam-y						+= mpam_devices.o
+mpam-y						+= mpam_devices.o mpam_fb.o
 mpam-$(CONFIG_ARM64_MPAM_RESCTRL_FS)		+= mpam_resctrl.o
 
 ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)	+= -DDEBUG
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 3be09b0c46ae..90b49bfd5caa 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -28,6 +28,7 @@
 #include <linux/workqueue.h>
 
 #include "mpam_internal.h"
+#include "mpam_fb.h"
 
 /* Values for the T241 errata workaround */
 #define T241_CHIPS_MAX			4
@@ -175,6 +176,13 @@ static u32 __mpam_read_reg(struct mpam_msc *msc, u16 reg)
 {
 	WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility));
 
+	if (msc->iface == MPAM_IFACE_PCC) {
+		u32 ret;
+
+		mpam_fb_send_read_request(msc, reg, &ret);
+		return ret;
+	}
+
 	return readl_relaxed(msc->mapped_hwpage + reg);
 }
 
@@ -188,10 +196,14 @@ static inline u32 _mpam_read_partsel_reg(struct mpam_msc *msc, u16 reg)
 
 static void __mpam_write_reg(struct mpam_msc *msc, u16 reg, u32 val)
 {
-	WARN_ON_ONCE(reg + sizeof(u32) > msc->mapped_hwpage_sz);
 	WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility));
 
-	writel_relaxed(val, msc->mapped_hwpage + reg);
+	if (msc->iface == MPAM_IFACE_PCC) {
+		mpam_fb_send_write_request(msc, reg, val);
+	} else {
+		WARN_ON_ONCE(reg + sizeof(u32) > msc->mapped_hwpage_sz);
+		writel_relaxed(val, msc->mapped_hwpage + reg);
+	}
 }
 
 static inline void _mpam_write_partsel_reg(struct mpam_msc *msc, u16 reg, u32 val)
diff --git a/drivers/resctrl/mpam_fb.c b/drivers/resctrl/mpam_fb.c
new file mode 100644
index 000000000000..bfb5798c74b0
--- /dev/null
+++ b/drivers/resctrl/mpam_fb.c
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2024 Arm Ltd.
+
+#include <linux/arm_mpam.h>
+#include <linux/cleanup.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/iopoll.h>
+#include <linux/list.h>
+#include <linux/mailbox_client.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/processor.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <acpi/pcc.h>
+
+#include <asm/mpam.h>
+
+#include "mpam_fb.h"
+
+#define MPAM_FB_PROTOCOL_ID	0x1a
+#define MPAM_MSC_ATTRIBUTES_CMD	0x3
+#define MPAM_MSC_READ_CMD	0x4
+#define MPAM_MSC_WRITE_CMD	0x5
+
+#define MPAM_MSC_PROT_ID_MASK	GENMASK(17, 10)
+#define MPAM_MSC_TOKEN_MASK	GENMASK(27, 18)
+
+#define SCMI_CHAN_RSVD_OFS	0x00
+#define SCMI_CHAN_STATUS_OFS	0x04
+#define SCMI_CHAN_STATUS_FREE_BIT	BIT(0)
+#define SCMI_CHAN_FLAGS_OFS	0x10
+#define SCMI_CHAN_FLAGS_IRQ		BIT(0)
+#define SCMI_MSG_LENGTH_OFS	0x14
+#define SCMI_MSG_HEADER_OFS	0x18
+#define SCMI_MSG_PAYLOAD_OFS	0x1c
+
+#define MPAM_READ_MSG_SIZE	(SCMI_MSG_PAYLOAD_OFS + 3 * sizeof(u32))
+#define MPAM_WRITE_MSG_SIZE	(SCMI_MSG_PAYLOAD_OFS + 4 * sizeof(u32))
+
+static atomic_t mpam_fb_token = ATOMIC_INIT(0);
+
+static int mpam_fb_build_read_message(int msc_id, int reg, unsigned int token,
+				      void __iomem *msg_buf)
+{
+	writel_relaxed(SCMI_CHAN_FLAGS_IRQ, msg_buf + SCMI_CHAN_FLAGS_OFS);
+	writel_relaxed(MPAM_READ_MSG_SIZE, msg_buf + SCMI_MSG_LENGTH_OFS);
+	writel_relaxed(MPAM_MSC_READ_CMD |
+		       FIELD_PREP(MPAM_MSC_TOKEN_MASK, token) |
+		       FIELD_PREP(MPAM_MSC_PROT_ID_MASK, MPAM_FB_PROTOCOL_ID),
+		       msg_buf + SCMI_MSG_HEADER_OFS);
+
+	writel_relaxed(cpu_to_le32(msc_id), msg_buf + SCMI_MSG_PAYLOAD_OFS);
+	writel_relaxed(0, msg_buf + SCMI_MSG_PAYLOAD_OFS + 0x4);
+	writel_relaxed(cpu_to_le32(reg), msg_buf + SCMI_MSG_PAYLOAD_OFS + 0x8);
+
+	return MPAM_READ_MSG_SIZE;
+}
+
+static int mpam_fb_build_write_message(int msc_id, int reg, u32 val,
+				       unsigned int token,
+				       void __iomem *msg_buf)
+{
+	writel_relaxed(MPAM_WRITE_MSG_SIZE, msg_buf + SCMI_MSG_LENGTH_OFS);
+	writel_relaxed(MPAM_MSC_WRITE_CMD |
+		       FIELD_PREP(MPAM_MSC_TOKEN_MASK, token) |
+		       FIELD_PREP(MPAM_MSC_PROT_ID_MASK, MPAM_FB_PROTOCOL_ID),
+		       msg_buf + SCMI_MSG_HEADER_OFS);
+
+	writel_relaxed(cpu_to_le32(msc_id), msg_buf + SCMI_MSG_PAYLOAD_OFS);
+	writel_relaxed(0, msg_buf + SCMI_MSG_PAYLOAD_OFS + 0x4);
+	writel_relaxed(cpu_to_le32(reg), msg_buf + SCMI_MSG_PAYLOAD_OFS + 0x8);
+	writel_relaxed(cpu_to_le32(val), msg_buf + SCMI_MSG_PAYLOAD_OFS + 0xc);
+
+	return MPAM_WRITE_MSG_SIZE;
+}
+
+#define SCMI_CHANNEL_FREE	true
+#define SCMI_CHANNEL_BUSY	false
+static int mpam_fb_wait_for_channel(struct pcc_mbox_chan *chan,
+				    bool free)
+{
+	u32 status = free ? SCMI_CHAN_STATUS_FREE_BIT : 0;
+	u32 val;
+
+	/*
+	 * The channel should really be free always at this point, as we take
+	 * a lock for every read or write request. Check the free bit anyway,
+	 * for good measure and to catch corner cases.
+	 */
+	return readl_poll_timeout(chan->shmem + SCMI_CHAN_STATUS_OFS, val,
+				  (val & SCMI_CHAN_STATUS_FREE_BIT) == status,
+				  1, 10000);
+}
+
+static int mpam_fb_send_request(struct mpam_msc *msc, u16 reg, u32 *result,
+				bool is_write)
+{
+	unsigned int token = atomic_inc_return(&mpam_fb_token);
+	struct pcc_mbox_chan *chan = msc->pcc_chan;
+	u32 status;
+	int ret;
+
+	guard(mutex)(&msc->pcc_chan_lock);
+	ret = mpam_fb_wait_for_channel(chan, SCMI_CHANNEL_FREE);
+	if (ret < 0)
+		return ret;
+
+	/* Clear error bit and mark the channel as belonging to the callee */
+	writel(0, chan->shmem + SCMI_CHAN_STATUS_OFS);
+
+	if (is_write)
+		ret = mpam_fb_build_write_message(msc->mpam_fb_msc_id, reg,
+						  *result, token, chan->shmem);
+	else
+		ret = mpam_fb_build_read_message(msc->mpam_fb_msc_id, reg,
+						 token, chan->shmem);
+	if (ret < 0)
+		return ret;
+
+	ret = mbox_send_message(chan->mchan, NULL);
+	if (ret < 0)
+		return ret;
+
+	ret = mpam_fb_wait_for_channel(chan, SCMI_CHANNEL_FREE);
+	if (ret)
+		return ret;
+
+	status = readl(chan->shmem + SCMI_MSG_HEADER_OFS);
+	if (FIELD_GET(MPAM_MSC_TOKEN_MASK, status) != token)
+		return -ETIMEDOUT;
+
+	ret = readl(chan->shmem + SCMI_MSG_PAYLOAD_OFS + 0x0);
+	if (ret < 0)
+		return ret;
+
+	if (!is_write)
+		*result = readl(chan->shmem + SCMI_MSG_PAYLOAD_OFS + 0x4);
+
+	return 0;
+}
+
+int mpam_fb_send_read_request(struct mpam_msc *msc, u16 reg, u32 *result)
+{
+	return mpam_fb_send_request(msc, reg, result, false);
+}
+
+int mpam_fb_send_write_request(struct mpam_msc *msc, u16 reg, u32 value)
+{
+	return mpam_fb_send_request(msc, reg, &value, true);
+}
diff --git a/drivers/resctrl/mpam_fb.h b/drivers/resctrl/mpam_fb.h
new file mode 100644
index 000000000000..c3d1a239e16f
--- /dev/null
+++ b/drivers/resctrl/mpam_fb.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+// Copyright (C) 2024-2025 Arm Ltd.
+
+#ifndef MPAM_FB_H_
+#define MPAM_FB_H_
+
+#include <linux/types.h>
+#include "mpam_internal.h"
+
+#define SCMI_MSG_PAYLOAD_OFS	0x1c
+#define MPAM_WRITE_MSG_SIZE	(SCMI_MSG_PAYLOAD_OFS + 4 * sizeof(u32))
+#define MPAM_FB_MAX_MSG_SIZE	MPAM_WRITE_MSG_SIZE
+
+int mpam_fb_send_read_request(struct mpam_msc *msc, u16 reg, u32 *result);
+int mpam_fb_send_write_request(struct mpam_msc *msc, u16 reg, u32 value);
+
+#endif
diff --git a/drivers/resctrl/mpam_internal.h b/drivers/resctrl/mpam_internal.h
index 80213af10a64..3f524cd4fc81 100644
--- a/drivers/resctrl/mpam_internal.h
+++ b/drivers/resctrl/mpam_internal.h
@@ -11,6 +11,7 @@
 #include <linux/io.h>
 #include <linux/jump_label.h>
 #include <linux/llist.h>
+#include <linux/mailbox_client.h>
 #include <linux/mutex.h>
 #include <linux/resctrl.h>
 #include <linux/spinlock.h>
@@ -66,6 +67,10 @@ struct mpam_msc {
 
 	/* Not modified after mpam_is_enabled() becomes true */
 	enum mpam_msc_iface	iface;
+	struct mbox_client	pcc_cl;
+	struct pcc_mbox_chan	*pcc_chan;
+	struct mutex		pcc_chan_lock; /* only one message at a time */
+	int			mpam_fb_msc_id;	/* in its own name space */
 	u32			nrdy_usec;
 	cpumask_t		accessibility;
 	bool			has_extd_esr;
diff --git a/include/linux/arm_mpam.h b/include/linux/arm_mpam.h
index f92a36187a52..002f56e15362 100644
--- a/include/linux/arm_mpam.h
+++ b/include/linux/arm_mpam.h
@@ -12,7 +12,7 @@ struct mpam_msc;
 
 enum mpam_msc_iface {
 	MPAM_IFACE_MMIO,	/* a real MPAM MSC */
-	MPAM_IFACE_PCC,		/* a fake MPAM MSC */
+	MPAM_IFACE_PCC,		/* using the MPAM-Fb firmware redirection */
 };
 
 enum mpam_class_types {
-- 
2.43.0



^ permalink raw reply related

* [PATCH 5/5] arm_mpam: detect and enable MPAM-Fb PCC support
From: Andre Przywara @ 2026-04-29 14:13 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
	Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
	Ben Horgan, Reinette Chatre, Fenghua Yu
  Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260429141339.3171205-1-andre.przywara@arm.com>

The Arm MPAM-Fb specification [1] describes a protocol to access MSC
registers through a firmware interface. This requires a shared memory
region to hold the message, and a mailbox to trigger the access.
For ACPI this is wrapped as a PCC channel, described using existing
ACPI abstractions.

Add code to parse those PCC table descriptions associated with an MSC,
and store the parsed information in the MSC struct.
This will be used by the MPAM-Fb access wrapper code.

[1] https://developer.arm.com/documentation/den0144/latest

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 drivers/acpi/arm64/mpam.c      |  2 ++
 drivers/resctrl/mpam_devices.c | 46 +++++++++++++++++++++++++++++++---
 2 files changed, 45 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/arm64/mpam.c b/drivers/acpi/arm64/mpam.c
index 99c2bdbb3314..edb4d10e8dc3 100644
--- a/drivers/acpi/arm64/mpam.c
+++ b/drivers/acpi/arm64/mpam.c
@@ -341,6 +341,8 @@ static struct platform_device * __init acpi_mpam_parse_msc(struct acpi_mpam_msc_
 	} else if (iface == MPAM_IFACE_PCC) {
 		props[next_prop++] = PROPERTY_ENTRY_U32("pcc-channel",
 							tbl_msc->base_address);
+		props[next_prop++] = PROPERTY_ENTRY_U32("msc-id",
+							tbl_msc->identifier);
 	}
 
 	acpi_mpam_parse_irqs(pdev, tbl_msc, res, &next_res);
diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 62aa04cb6905..6f0d0959d3a4 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -19,6 +19,7 @@
 #include <linux/irqdesc.h>
 #include <linux/list.h>
 #include <linux/lockdep.h>
+#include <linux/mailbox_client.h>
 #include <linux/mutex.h>
 #include <linux/platform_device.h>
 #include <linux/printk.h>
@@ -27,6 +28,9 @@
 #include <linux/types.h>
 #include <linux/workqueue.h>
 
+#include <acpi/pcc.h>
+#include <acpi/acpi_io.h>
+
 #include "mpam_internal.h"
 #include "mpam_fb.h"
 
@@ -1042,7 +1046,8 @@ static u64 mpam_msc_read_mbwu_l(struct mpam_msc *msc)
 
 	mpam_mon_sel_lock_held(msc);
 
-	WARN_ON_ONCE((MSMON_MBWU_L + sizeof(u64)) > msc->mapped_hwpage_sz);
+	if (msc->iface == MPAM_IFACE_MMIO)
+		WARN_ON_ONCE((MSMON_MBWU_L + sizeof(u64)) > msc->mapped_hwpage_sz);
 	WARN_ON_ONCE(!cpumask_test_cpu(smp_processor_id(), &msc->accessibility));
 
 	mbwu_l_high2 = __mpam_read_reg(msc, MSMON_MBWU_L + 4);
@@ -2042,10 +2047,15 @@ static void mpam_msc_drv_remove(struct platform_device *pdev)
 	mpam_free_garbage();
 }
 
+static void mpam_pcc_rx_callback(struct mbox_client *cl, void *msg)
+{
+	/* TODO: wake up tasks blocked on this MSC's PCC channel */
+}
+
 static struct mpam_msc *do_mpam_msc_drv_probe(struct platform_device *pdev)
 {
 	int err;
-	u32 tmp;
+	u32 pcc_subspace_id;
 	struct mpam_msc *msc;
 	struct resource *msc_res;
 	struct device *dev = &pdev->dev;
@@ -2090,7 +2100,8 @@ static struct mpam_msc *do_mpam_msc_drv_probe(struct platform_device *pdev)
 	if (err)
 		return ERR_PTR(err);
 
-	if (device_property_read_u32(&pdev->dev, "pcc-channel", &tmp))
+	if (device_property_read_u32(&pdev->dev, "pcc-channel",
+				     &pcc_subspace_id))
 		msc->iface = MPAM_IFACE_MMIO;
 	else
 		msc->iface = MPAM_IFACE_PCC;
@@ -2106,6 +2117,35 @@ static struct mpam_msc *do_mpam_msc_drv_probe(struct platform_device *pdev)
 		}
 		msc->mapped_hwpage_sz = msc_res->end - msc_res->start;
 		msc->mapped_hwpage = io;
+	} else if (msc->iface == MPAM_IFACE_PCC) {
+		u32 msc_id;
+
+		msc->pcc_cl.dev = &pdev->dev;
+		msc->pcc_cl.rx_callback = mpam_pcc_rx_callback;
+		msc->pcc_cl.tx_block = false;
+		msc->pcc_cl.tx_tout = 1000; /* 1s */
+		msc->pcc_cl.knows_txdone = false;
+
+		if (device_property_read_u32(&pdev->dev, "msc-id", &msc_id)) {
+			pr_err("missing MPAM-Fb MSC identifier\n");
+			return ERR_PTR(-EINVAL);
+		}
+		msc->mpam_fb_msc_id = msc_id;
+
+		msc->pcc_chan = pcc_mbox_request_channel(&msc->pcc_cl,
+							 pcc_subspace_id);
+		if (IS_ERR(msc->pcc_chan)) {
+			pr_err("Failed to request MSC PCC channel\n");
+			return (void *)msc->pcc_chan;
+		}
+
+		if (msc->pcc_chan->shmem_size < MPAM_FB_MAX_MSG_SIZE) {
+			pr_err("MPAM-Fb PCC channel size too small.\n");
+			pcc_mbox_free_channel(msc->pcc_chan);
+			return ERR_PTR(-ENOMEM);
+		}
+
+		mutex_init(&msc->pcc_chan_lock);
 	} else {
 		return ERR_PTR(-EINVAL);
 	}
-- 
2.43.0



^ permalink raw reply related

* [PATCH 4/5] arm_mpam: prevent MPAM-Fb accesses inside IRQ handler
From: Andre Przywara @ 2026-04-29 14:13 UTC (permalink / raw)
  To: Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla, Catalin Marinas,
	Will Deacon, Rafael J . Wysocki, Len Brown, James Morse,
	Ben Horgan, Reinette Chatre, Fenghua Yu
  Cc: Jonathan Cameron, linux-acpi, linux-arm-kernel, linux-kernel
In-Reply-To: <20260429141339.3171205-1-andre.przywara@arm.com>

When an MPAM MSC gets into an error condition, it can trigger an error
IRQ. We cannot really do much about those errors, but we at least query
and log the error, then disable MPAM functionality.

This error report relies on reading the MSC's error status register
(ESR) in the IRQ handler, which is not possible for MPAM-Fb based
MSC accesses, since they involve mailbox routines that might sleep.

For simplicity just skip the ESR read when the MSC is not using direct
MMIO accesses. We will wrap up MPAM functionality regardless, knowing
the exact error value will not change that.

Signed-off-by: Andre Przywara <andre.przywara@arm.com>
---
 drivers/resctrl/mpam_devices.c | 30 +++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 11 deletions(-)

diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
index 90b49bfd5caa..62aa04cb6905 100644
--- a/drivers/resctrl/mpam_devices.c
+++ b/drivers/resctrl/mpam_devices.c
@@ -2472,7 +2472,7 @@ static int mpam_disable_msc_ecr(void *_msc)
 
 static irqreturn_t __mpam_irq_handler(int irq, struct mpam_msc *msc)
 {
-	u64 reg;
+	u64 reg = 0;
 	u16 partid;
 	u8 errcode, pmg, ris;
 
@@ -2481,22 +2481,30 @@ static irqreturn_t __mpam_irq_handler(int irq, struct mpam_msc *msc)
 					   &msc->accessibility)))
 		return IRQ_NONE;
 
-	reg = mpam_msc_read_esr(msc);
+	/* MPAM-Fb MSC accesses cannot be done in atomic context. */
+	if (msc->iface == MPAM_IFACE_MMIO) {
+		reg = mpam_msc_read_esr(msc);
 
-	errcode = FIELD_GET(MPAMF_ESR_ERRCODE, reg);
-	if (!errcode)
-		return IRQ_NONE;
+		errcode = FIELD_GET(MPAMF_ESR_ERRCODE, reg);
+		if (!errcode)
+			return IRQ_NONE;
+	}
 
 	/* Clear level triggered irq */
 	mpam_msc_clear_esr(msc);
 
-	partid = FIELD_GET(MPAMF_ESR_PARTID_MON, reg);
-	pmg = FIELD_GET(MPAMF_ESR_PMG, reg);
-	ris = FIELD_GET(MPAMF_ESR_RIS, reg);
+	if (reg) {
+		partid = FIELD_GET(MPAMF_ESR_PARTID_MON, reg);
+		pmg = FIELD_GET(MPAMF_ESR_PMG, reg);
+		ris = FIELD_GET(MPAMF_ESR_RIS, reg);
+
+		pr_err_ratelimited("error irq from msc:%u '%s', partid:%u, pmg: %u, ris: %u\n",
+				   msc->id, mpam_errcode_names[errcode], partid,
+				   pmg, ris);
+	} else {
+		pr_err_ratelimited("unknown error irq from msc:%u\n", msc->id);
+	}
 
-	pr_err_ratelimited("error irq from msc:%u '%s', partid:%u, pmg: %u, ris: %u\n",
-			   msc->id, mpam_errcode_names[errcode], partid, pmg,
-			   ris);
 
 	/* Disable this interrupt. */
 	mpam_disable_msc_ecr(msc);
-- 
2.43.0



^ permalink raw reply related

* Re: [PATCH v4 11/15] arm64: mm: Don't abuse memblock NOMAP to check for overlaps
From: Ard Biesheuvel @ 2026-04-29 14:23 UTC (permalink / raw)
  To: Kevin Brodsky, Ard Biesheuvel, linux-arm-kernel
  Cc: linux-kernel, Will Deacon, Catalin Marinas, Mark Rutland,
	Ryan Roberts, Anshuman Khandual, Liz Prucka, Seth Jenkins,
	Kees Cook, Mike Rapoport, David Hildenbrand, Andrew Morton,
	linux-mm, linux-hardening
In-Reply-To: <8a315ca2-3754-4a66-990e-55b85191aa6e@arm.com>



On Wed, 29 Apr 2026, at 12:54, Kevin Brodsky wrote:
> On 27/04/2026 17:34, Ard Biesheuvel wrote:
>> From: Ard Biesheuvel <ardb@kernel.org>
>>
>> Now that the DRAM mapping routines respect existing table mappings and
>> contiguous block and page mappings, it is no longer needed to fiddle
>> with the memblock tables to set and clear the NOMAP attribute in order
>> to omit text and rodata when creating the linear map.
>>
>> Instead, map the kernel text and rodata alias first with the desired
>> attributes, so that they will not be remapped later with different
>> attributes when mapping the memblocks.
>>
>> Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
>> ---
>>  arch/arm64/mm/mmu.c | 24 +++++++-------------
>>  1 file changed, 8 insertions(+), 16 deletions(-)
>>
>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>> index 5e2348b15783..1a4b4337d29a 100644
>> --- a/arch/arm64/mm/mmu.c
>> +++ b/arch/arm64/mm/mmu.c
>> @@ -1148,12 +1148,15 @@ static void __init map_mem(void)
>>  		flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
>>  
>>  	/*
>> -	 * Take care not to create a writable alias for the
>> -	 * read-only text and rodata sections of the kernel image.
>> -	 * So temporarily mark them as NOMAP to skip mappings in
>> -	 * the following for-loop
>> +	 * Map the linear alias of the [_text, __init_begin) interval
>> +	 * as non-executable now, and remove the write permission in
>> +	 * mark_linear_text_alias_ro() above (which will be called after
>> +	 * alternative patching has completed). This makes the contents
>> +	 * of the region accessible to subsystems such as hibernate,
>> +	 * but protects it from inadvertent modification or execution.
>>  	 */
>> -	memblock_mark_nomap(kernel_start, kernel_end - kernel_start);
>> +	__map_memblock(kernel_start, kernel_end, pgprot_tagged(PAGE_KERNEL),
>
> Is it now necessary for that mapping to be tagged? If so, it should
> probably be called out in the commit message.
>

As you've pointed out, the initial r/w mapping of the linear alias of rodata
will need to be mapped tagged before moving the zero page there. So this patch
will just preserve that, rather than remapping the region tagged explicitly as
it does now.


^ permalink raw reply


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