* [RFC PATCH 4/6] arm64: mm: add helper to fill execmem with trapping instructions
From: Adrian Barnaś @ 2026-06-11 13:01 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-mm, Adrian Barnaś, Catalin Marinas, Will Deacon,
Ryan Roberts, David Hildenbrand, Mike Rapoport (Microsoft),
Ard Biesheuvel, Christoph Lameter, Yang Shi, Brendan Jackman
In-Reply-To: <20260611130144.1385343-1-abarnas@google.com>
Implement the architecture-specific execmem_fill_trapping_insns() helper
to poison executable memory regions.
When CONFIG_ARCH_HAS_EXECMEM_ROX is enabled, the execmem subsystem
requires a way to fill unused or freed executable memory with
architecture-specific trapping instructions. This implementation fills
the specified region with AARCH64_BREAK_FAULT instructions and flushes
the icache to ensure the traps are immediately visible to execution.
Signed-off-by: Adrian Barnaś <abarnas@google.com>
---
arch/arm64/mm/init.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index c673a9a839dd..71aa745e0bef 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -408,6 +408,20 @@ void dump_mem_limit(void)
}
#ifdef CONFIG_EXECMEM
+
+#ifdef CONFIG_ARCH_HAS_EXECMEM_ROX
+void execmem_fill_trapping_insns(void *ptr, size_t size)
+{
+ int nr_inst = size / AARCH64_INSN_SIZE;
+ __le32 *updptr = ptr;
+
+ for (int i = 0; i < nr_inst; i++)
+ updptr[i] = cpu_to_le32(AARCH64_BREAK_FAULT);
+
+ flush_icache_range((unsigned long)ptr, (unsigned long)ptr + size);
+}
+#endif
+
static u64 module_direct_base __ro_after_init = 0;
static u64 module_plt_base __ro_after_init = 0;
--
2.54.0.1136.gdb2ca164c4-goog
^ permalink raw reply related
* [RFC PATCH 6/6] arm64: mm: support PMD page coalescing in the linear map
From: Adrian Barnaś @ 2026-06-11 13:01 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-mm, Adrian Barnaś, Catalin Marinas, Will Deacon,
Ryan Roberts, David Hildenbrand, Mike Rapoport (Microsoft),
Ard Biesheuvel, Christoph Lameter, Yang Shi, Brendan Jackman
In-Reply-To: <20260611130144.1385343-1-abarnas@google.com>
Implement PMD block coalescing to merge fragmented linear mapping regions
back into huge pages when restoring the read-only attribute.
When memory allocated with VM_ALLOW_HUGE_VMAP (such as for the execmem
ROX cache) has its permissions modified, the PMD block mapping is split
into individual PTEs. Without this change, when that memory have its RO
attribute subsequently cleared and set the mapping remains permanently
fragmented into 4K pages.
Signed-off-by: Adrian Barnaś <abarnas@google.com>
---
arch/arm64/include/asm/mmu.h | 1 +
arch/arm64/mm/mmu.c | 95 ++++++++++++++++++++++++++++++++++++
arch/arm64/mm/pageattr.c | 7 +++
3 files changed, 103 insertions(+)
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index 137a173df1ff..19158bacb2df 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -80,6 +80,7 @@ extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot);
extern void mark_linear_text_alias_ro(void);
extern int split_kernel_leaf_mapping(unsigned long start, unsigned long end);
extern void linear_map_maybe_split_to_ptes(void);
+void try_collapse_kernel_pmd(unsigned long addr);
/*
* This check is triggered during the early boot before the cpufeature
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index a6a00accf4f9..d74226fa1c9b 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -769,6 +769,101 @@ static inline bool force_pte_mapping(void)
static DEFINE_MUTEX(pgtable_split_lock);
+static inline bool __pte_can_be_collapsed(pte_t pte, unsigned long pfn, pgprot_t prot)
+{
+ if (!pte_valid(pte))
+ return false;
+ if (pte_pfn(pte) != pfn)
+ return false;
+ if ((pgprot_val(pte_pgprot(pte)) & ~PTE_CONT) != pgprot_val(prot))
+ return false;
+
+ return true;
+}
+
+static void __try_collapse_pmd(pmd_t *pmdp, pmd_t pmd, unsigned long addr)
+{
+ pte_t *ptep;
+ pte_t first_pte;
+ unsigned long pfn;
+ pgprot_t prot;
+ int i;
+
+ ptep = (pte_t *)pmd_page_vaddr(pmd);
+ first_pte = __ptep_get(ptep);
+
+ if (!pte_valid(first_pte))
+ return;
+
+ prot = pte_pgprot(first_pte);
+ prot = __pgprot(pgprot_val(prot) & ~PTE_CONT);
+ pfn = pte_pfn(first_pte);
+
+ if (!IS_ALIGNED(pfn, PMD_SIZE >> PAGE_SHIFT))
+ return;
+
+ for (i = 1; i < PTRS_PER_PTE; i++) {
+ if (!__pte_can_be_collapsed(__ptep_get(ptep + i), pfn + i, prot))
+ return;
+ }
+
+ set_pmd(pmdp, pmd_mkhuge(pfn_pmd(pfn, prot)));
+
+ __flush_tlb_kernel_pgtable(addr);
+
+ if (static_branch_unlikely(&arm64_ptdump_lock_key)) {
+ mmap_read_lock(&init_mm);
+ mmap_read_unlock(&init_mm);
+ }
+
+ pte_free_kernel(NULL, ptep);
+}
+
+void try_collapse_kernel_pmd(unsigned long addr)
+{
+ pgd_t *pgdp;
+ p4d_t *p4dp;
+ pud_t *pudp;
+ pmd_t *pmdp;
+ pmd_t pmd;
+
+ /*
+ * collapse_pmd expects exact address of block to be collapsed
+ */
+ if (WARN_ON(ALIGN_DOWN(addr, PMD_SIZE) != addr))
+ return;
+
+ mutex_lock(&pgtable_split_lock);
+
+ pgdp = pgd_offset_k(addr);
+ if (pgd_none(READ_ONCE(*pgdp)))
+ goto out;
+
+ p4dp = p4d_offset(pgdp, addr);
+ if (p4d_none(READ_ONCE(*p4dp)))
+ goto out;
+
+ pudp = pud_offset(p4dp, addr);
+ if (pud_none(READ_ONCE(*pudp)))
+ goto out;
+
+ if (pud_leaf(READ_ONCE(*pudp)))
+ goto out;
+
+ pmdp = pmd_offset(pudp, addr);
+ pmd = pmdp_get(pmdp);
+
+ if (!pmd_table(pmd))
+ goto out;
+
+ lazy_mmu_mode_enable();
+ __try_collapse_pmd(pmdp, pmd, addr);
+ lazy_mmu_mode_disable();
+
+out:
+ mutex_unlock(&pgtable_split_lock);
+}
+
int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
{
int ret;
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index eaefdf90b0d5..11e0b60264c3 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -200,6 +200,13 @@ static int change_memory_common(unsigned long addr, int numpages,
if (ret)
return ret;
}
+ /*
+ * When setting a read-only flag on the linear region, the memory
+ * may have been backed by a PMD before being split. Try to
+ * collapse it back into a PMD to restore huge page performance.
+ */
+ if (pgprot_val(set_mask) == PTE_RDONLY && area->flags & VM_ALLOW_HUGE_VMAP)
+ try_collapse_kernel_pmd((u64)page_address(area->pages[0]));
}
/*
--
2.54.0.1136.gdb2ca164c4-goog
^ permalink raw reply related
* [RFC PATCH 5/6] arm64: execmem: enable EXECMEM_ROX_CACHE on supported CPUs
From: Adrian Barnaś @ 2026-06-11 13:01 UTC (permalink / raw)
To: linux-arm-kernel
Cc: linux-mm, Adrian Barnaś, Catalin Marinas, Will Deacon,
Ryan Roberts, David Hildenbrand, Mike Rapoport (Microsoft),
Ard Biesheuvel, Christoph Lameter, Yang Shi, Brendan Jackman
In-Reply-To: <20260611130144.1385343-1-abarnas@google.com>
Enable EXECMEM_ROX_CACHE support for ARM64 systems that implement
the bbml2_no_abort CPU feature.
Using the ROX cache brings a performance boost by reducing linear region
fragmentation caused by strict memory permissions (e.g., W^X enforcement).
Grouping executable code (which is read-only in the linear region alias)
into PMD-sized block mappings reduces TLB pressure and page table size.
This is only enabled on systems with bbml2_no_abort, as splitting
these large blocks to make pages writable during module loading would
otherwise risk triggering TLB Conflict Aborts.
Signed-off-by: Adrian Barnaś <abarnas@google.com>
---
arch/arm64/Kconfig | 1 +
arch/arm64/mm/init.c | 22 +++++++++++++++++++++-
2 files changed, 22 insertions(+), 1 deletion(-)
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 38dba5f7e4d2..79c347ab841e 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -285,6 +285,7 @@ config ARM64
select USER_STACKTRACE_SUPPORT
select VDSO_GETRANDOM
select VMAP_STACK
+ select ARCH_HAS_EXECMEM_ROX
help
ARM 64-bit (AArch64) Linux support.
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 71aa745e0bef..8269d7747b84 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -420,6 +420,12 @@ void execmem_fill_trapping_insns(void *ptr, size_t size)
flush_icache_range((unsigned long)ptr, (unsigned long)ptr + size);
}
+
+#define MODULE_TEXT_FLAG EXECMEM_ROX_CACHE
+#define MODULE_TEXT_PGPROT PAGE_KERNEL_ROX
+#else
+#define MODULE_TEXT_FLAG (0)
+#define MODULE_TEXT_PGPROT PAGE_KERNEL
#endif
static u64 module_direct_base __ro_after_init = 0;
@@ -511,6 +517,8 @@ struct execmem_info __init *execmem_arch_setup(void)
{
unsigned long fallback_start = 0, fallback_end = 0;
unsigned long start = 0, end = 0;
+ enum execmem_range_flags module_text_flags = 0;
+ pgprot_t module_text_pgprot = PAGE_KERNEL;
module_init_limits();
@@ -531,12 +539,24 @@ struct execmem_info __init *execmem_arch_setup(void)
end = module_plt_base + SZ_2G;
}
+ /*
+ * The ROX Cache requires bbml2_no_abort because it uses large block
+ * mappings. On systems without this guarantee, splitting these blocks
+ * to make pages writable for module loading can trigger TLB Conflict
+ * Aborts.
+ */
+ if (system_supports_bbml2_noabort()) {
+ module_text_flags = MODULE_TEXT_FLAG;
+ module_text_pgprot = MODULE_TEXT_PGPROT;
+ }
+
execmem_info = (struct execmem_info){
.ranges = {
[EXECMEM_MODULE_TEXT] = {
.start = start,
.end = end,
- .pgprot = PAGE_KERNEL,
+ .flags = module_text_flags,
+ .pgprot = module_text_pgprot,
.alignment = 1,
.fallback_start = fallback_start,
.fallback_end = fallback_end,
--
2.54.0.1136.gdb2ca164c4-goog
^ permalink raw reply related
* [PATCH/RFC 0/9] R-Car X5H Ironhide pure SCMI proof-of-concept
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
Hi all,
As promised[1], I tried handling all issues with current R-Car X5H
Ironhide SCP FW SDK v4.28, v4.31, and v4.32 as SCMI quirks. This helped
identifying missing features in the SCMI drivers and/or protocol:
- The SCMI PM domain driver does not support always-on domains.
This limits the ability of the Linux Power Management core to
optimize its decisions by taking into account which PM domains
cannot be disabled,
- The SCMI protocol does not support clock domains.
- Power management of on-SoC modules is typically handled through two
methods: module power control and module clock gating. The former
can be exposed as an SCMI power domain, the latter as an SCMI clock.
Currently, the SCMI clock protocol does not support advertizing
whether a clock is intended for power-management of a hardware
module, so such clocks can not be managed automatically through
Runtime PM. To solve this in general, the SCMI CLOCK_ATTRIBUTES
could be extended with a new flag in the returned attributes (which
is not done by this series).
Series overvies:
- Patch 1 is a preparatory refactoring,
- Patches 2-3 add support for always-on power areas,
- Patches 4-7 add support for clock domains,
- Patch 8 adds an SCMI quirk to advertize power-management clocks on
R-Car X5H,
- Patch 9 switches the (still minimal) Ironhide DTS to SCMI (this
needs manual configuration for the actual SCP firmware version, as
the SCMI domain IDs differ).
Note that other SCMI quirks than patch 8 are not included in this
series[2], as IMHO the original issues must be fixed in the SCP firmware
instead.
While the result works, and we might get stable SCMI domain IDs
(eventually), I still prefer the approach taking by the CPG/MDLC
remapping driver series[3], as:
- It describes in DT the actual hardware (which is needed for U-Boot
IPL),
- It does not depend on SCMI domain IDs defined by firmware that is
still under active development,
- It lets us keep the DTB stable, while SCMI domain IDs may change,
depending on system partitioning (i.e. software policy),
- It allows us to support (in the Renesas LTS tree, not upstream)
firmware versions that already exist, but need quirks for proper
operation.
Thanks for your comments!
[1] "Re: [PATCH/RFC 05/14] firmware: arm_scmi: Add scmi_get_base_info()"
https://lore.kernel.org/CAMuHMdWJvMH+a1RqozbaCxxH_8M569JcruTFa8PW+87FysnjHw@mail.gmail.com
[2] List of SCMI quirks which are not included in this series, but are
needed to boot on R-Car X5H Ironhide:
firmware: arm_scmi: quirk: Handle critical clocks on R-Car X5H
firmware: arm_scmi: quirk: Handle bad power domains on R-Car X5H
firmware: arm_scmi: quirk: Handle bad clocks on R-Car X5H
firmware: arm_scmi: quirk: Handle wrong clock rates on R-Car X5H
firmware: arm_scmi: Add support for retrieving rates from another clock
firmware: arm_scmi: quirk: Handle zero clock rates on R-Car X5H
firmware: arm_scmi: quirk: Add always-on power domains on R-Car X5H
firmware: arm_scmi: quirk: Handle broken HSCIF0 reset on R-Car X5H
With diffstat:
drivers/firmware/arm_scmi/clock.c | 2555 +++++++++++++++++++++++++++-
drivers/firmware/arm_scmi/power.c | 83 +
drivers/firmware/arm_scmi/quirks.c | 12 +
drivers/firmware/arm_scmi/quirks.h | 4 +
drivers/firmware/arm_scmi/reset.c | 9 +
5 files changed, 2655 insertions(+), 8 deletions(-)
[3] "[PATCH/RFC 00/14] R-Car X5H Ironhide SCMI CPG/MDLC remapping"
https://lore.kernel.org/cover.1776793163.git.geert+renesas@glider.be
Geert Uytterhoeven (9):
firmware: arm_scmi: Replace scmi_power_proto_ops.name_get() by
.info_get()
firmware: arm_scmi: Advertize always-on power domains
pmdomain: arm: scmi: Add always-on support
firmware: arm_scmi: Add a flag for power-management clocks
clk: scmi: Add scmi_clk_is_pm_clk()
dt-bindings: firmware: arm,scmi: Document arm,clock-domain
pmdomain: arm: scmi: Add clock domain support
firmware: arm_scmi: quirk: Handle power management clocks on R-Car X5H
arm64: dts: renesas: ironhide: Switch to pure SCMI
.../bindings/firmware/arm,scmi.yaml | 7 ++
.../boot/dts/renesas/r8a78000-ironhide.dts | 44 +++++++++
drivers/clk/clk-scmi.c | 9 ++
drivers/firmware/arm_scmi/clock.c | 15 +++
drivers/firmware/arm_scmi/power.c | 21 +++--
drivers/pmdomain/arm/Kconfig | 1 +
drivers/pmdomain/arm/scmi_pm_domain.c | 93 ++++++++++++++++++-
include/linux/clk/scmi.h | 17 ++++
include/linux/scmi_protocol.h | 12 ++-
9 files changed, 204 insertions(+), 15 deletions(-)
create mode 100644 include/linux/clk/scmi.h
--
2.43.0
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/RFC 1/9] firmware: arm_scmi: Replace scmi_power_proto_ops.name_get() by .info_get()
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
The SCMI power domain protocol operations structure does not provide a
.info_get() method, unlike most other protocols. Instead, it provides
a .name_get() method.
Replace the .name_get() method by the .info_get() method, to increase
uniformity, and to prepare for returning more information.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/firmware/arm_scmi/power.c | 17 ++++++++---------
drivers/pmdomain/arm/scmi_pm_domain.c | 9 ++++++++-
include/linux/scmi_protocol.h | 10 +++++++---
3 files changed, 23 insertions(+), 13 deletions(-)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index 28ef63a4ecc2e1df..a00f7c298efb74f9 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -63,7 +63,7 @@ struct power_dom_info {
bool state_set_sync;
bool state_set_async;
bool state_set_notify;
- char name[SCMI_MAX_STR_SIZE];
+ struct scmi_power_domain_info info;
};
struct scmi_power_info {
@@ -132,7 +132,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
SUPPORTS_STATE_SET_NOTIFY(flags);
dom_info->state_set_async = SUPPORTS_STATE_SET_ASYNC(flags);
dom_info->state_set_sync = SUPPORTS_STATE_SET_SYNC(flags);
- strscpy(dom_info->name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
+ strscpy(dom_info->info.name, attr->name, SCMI_SHORT_NAME_MAX_SIZE);
}
ph->xops->xfer_put(ph, t);
@@ -143,7 +143,7 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
if (!ret && PROTOCOL_REV_MAJOR(ph->version) >= 0x3 &&
SUPPORTS_EXTENDED_NAMES(flags)) {
ph->hops->extended_name_get(ph, POWER_DOMAIN_NAME_GET,
- domain, NULL, dom_info->name,
+ domain, NULL, dom_info->info.name,
SCMI_MAX_STR_SIZE);
}
@@ -199,23 +199,22 @@ static int scmi_power_num_domains_get(const struct scmi_protocol_handle *ph)
return pi->num_domains;
}
-static const char *
-scmi_power_name_get(const struct scmi_protocol_handle *ph,
- u32 domain)
+static const struct scmi_power_domain_info *
+scmi_power_info_get(const struct scmi_protocol_handle *ph, u32 domain)
{
struct scmi_power_info *pi = ph->get_priv(ph);
struct power_dom_info *dom;
if (domain >= pi->num_domains)
- return "unknown";
+ return NULL;
dom = pi->dom_info + domain;
- return dom->name;
+ return &dom->info;
}
static const struct scmi_power_proto_ops power_proto_ops = {
.num_domains_get = scmi_power_num_domains_get,
- .name_get = scmi_power_name_get,
+ .info_get = scmi_power_info_get,
.state_set = scmi_power_state_set,
.state_get = scmi_power_state_get,
};
diff --git a/drivers/pmdomain/arm/scmi_pm_domain.c b/drivers/pmdomain/arm/scmi_pm_domain.c
index 3d73aef21d2f9942..965592e828741b11 100644
--- a/drivers/pmdomain/arm/scmi_pm_domain.c
+++ b/drivers/pmdomain/arm/scmi_pm_domain.c
@@ -76,8 +76,15 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
return -ENOMEM;
for (i = 0; i < num_domains; i++, scmi_pd++) {
+ const struct scmi_power_domain_info *info;
u32 state;
+ info = power_ops->info_get(ph, i);
+ if (!info) {
+ dev_warn(dev, "failed to get info for domain %d\n", i);
+ continue;
+ }
+
if (power_ops->state_get(ph, i, &state)) {
dev_warn(dev, "failed to get state for domain %d\n", i);
continue;
@@ -93,7 +100,7 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
scmi_pd->domain = i;
scmi_pd->ph = ph;
- scmi_pd->name = power_ops->name_get(ph, i);
+ scmi_pd->name = info->name;
scmi_pd->genpd.name = scmi_pd->name;
scmi_pd->genpd.power_off = scmi_pd_power_off;
scmi_pd->genpd.power_on = scmi_pd_power_on;
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 5ab73b1ab9aa4fa8..1c17515ba45d1fd4 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -191,19 +191,23 @@ struct scmi_perf_proto_ops {
enum scmi_power_scale (*power_scale_get)(const struct scmi_protocol_handle *ph);
};
+struct scmi_power_domain_info {
+ char name[SCMI_MAX_STR_SIZE];
+};
+
/**
* struct scmi_power_proto_ops - represents the various operations provided
* by SCMI Power Protocol
*
* @num_domains_get: get the count of power domains provided by SCMI
- * @name_get: gets the name of a power domain
+ * @info_get: gets the information of the specified power domain
* @state_set: sets the power state of a power domain
* @state_get: gets the power state of a power domain
*/
struct scmi_power_proto_ops {
int (*num_domains_get)(const struct scmi_protocol_handle *ph);
- const char *(*name_get)(const struct scmi_protocol_handle *ph,
- u32 domain);
+ const struct scmi_power_domain_info __must_check *(*info_get)
+ (const struct scmi_protocol_handle *ph, u32 domain);
#define SCMI_POWER_STATE_TYPE_SHIFT 30
#define SCMI_POWER_STATE_ID_MASK (BIT(28) - 1)
#define SCMI_POWER_STATE_PARAM(type, id) \
--
2.43.0
^ permalink raw reply related
* [PATCH/RFC 2/9] firmware: arm_scmi: Advertize always-on power domains
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
A power domains indicates in its attribute flags if it supports setting
its power state synchronously and/or asynchronously. If none of them is
supported, it must be an always-on power domain.
Make this information available to SCMI protocol drivers, so they can
make use of it.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/firmware/arm_scmi/power.c | 4 ++++
include/linux/scmi_protocol.h | 1 +
2 files changed, 5 insertions(+)
diff --git a/drivers/firmware/arm_scmi/power.c b/drivers/firmware/arm_scmi/power.c
index a00f7c298efb74f9..11ca8c9965110b5a 100644
--- a/drivers/firmware/arm_scmi/power.c
+++ b/drivers/firmware/arm_scmi/power.c
@@ -8,6 +8,7 @@
#define pr_fmt(fmt) "SCMI Notifications POWER - " fmt
#include <linux/module.h>
+#include <linux/pm_domain.h>
#include <linux/scmi_protocol.h>
#include "protocols.h"
@@ -147,6 +148,9 @@ scmi_power_domain_attributes_get(const struct scmi_protocol_handle *ph,
SCMI_MAX_STR_SIZE);
}
+ if (!ret && !dom_info->state_set_async && !dom_info->state_set_sync)
+ dom_info->info.genpd_flags |= GENPD_FLAG_ALWAYS_ON;
+
return ret;
}
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 1c17515ba45d1fd4..1d55374bc8cdcc72 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -193,6 +193,7 @@ struct scmi_perf_proto_ops {
struct scmi_power_domain_info {
char name[SCMI_MAX_STR_SIZE];
+ unsigned int genpd_flags;
};
/**
--
2.43.0
^ permalink raw reply related
* [PATCH/RFC 3/9] pmdomain: arm: scmi: Add always-on support
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
Extend the PM domain flags with the flags advertized by the SCMI core.
For now this is limited to GENPD_FLAG_ALWAYS_ON.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Questions:
- Should the power_ops->state_get() call be skipped in case of an
always-on domain, and state just be force to
SCMI_POWER_STATE_GENERIC_ON instead?
- Should the power_ops->state_set() call be skipped in case of an
always-on domain? Or might this cause issues with some firmware
implementations?
Skipping these calls may avoid adding quirk code later...
---
drivers/pmdomain/arm/scmi_pm_domain.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/pmdomain/arm/scmi_pm_domain.c b/drivers/pmdomain/arm/scmi_pm_domain.c
index 965592e828741b11..8e67f971c707e121 100644
--- a/drivers/pmdomain/arm/scmi_pm_domain.c
+++ b/drivers/pmdomain/arm/scmi_pm_domain.c
@@ -104,7 +104,8 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
scmi_pd->genpd.name = scmi_pd->name;
scmi_pd->genpd.power_off = scmi_pd_power_off;
scmi_pd->genpd.power_on = scmi_pd_power_on;
- scmi_pd->genpd.flags = GENPD_FLAG_ACTIVE_WAKEUP;
+ scmi_pd->genpd.flags = GENPD_FLAG_ACTIVE_WAKEUP |
+ info->genpd_flags;
pm_genpd_init(&scmi_pd->genpd, NULL,
state == SCMI_POWER_STATE_GENERIC_OFF);
--
2.43.0
^ permalink raw reply related
* [PATCH/RFC 4/9] firmware: arm_scmi: Add a flag for power-management clocks
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
Power management of on-SoC modules is typically handled through two
methods: module power control and module clock gating. The former is
exposed as an SCMI power domain, the latter as an SCMI clock.
Add a flag to indicate if a clock is intended for power-management of a
hardware module.
As the SCMI clock protocol does not support advertizing power-management
clocks yet, this flag can only be set by a quirk.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
include/linux/scmi_protocol.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/include/linux/scmi_protocol.h b/include/linux/scmi_protocol.h
index 1d55374bc8cdcc72..c98e0add25f0c6c6 100644
--- a/include/linux/scmi_protocol.h
+++ b/include/linux/scmi_protocol.h
@@ -55,6 +55,7 @@ struct scmi_clock_info {
bool rate_ctrl_forbidden;
bool parent_ctrl_forbidden;
bool extended_config;
+ bool pm_clk;
u64 min_rate;
u64 max_rate;
int num_parents;
--
2.43.0
^ permalink raw reply related
* [PATCH/RFC 5/9] clk: scmi: Add scmi_clk_is_pm_clk()
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
Add a helper for querying if an SCMI clock can be used for
power-management.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/clk/clk-scmi.c | 9 +++++++++
include/linux/clk/scmi.h | 17 +++++++++++++++++
2 files changed, 26 insertions(+)
create mode 100644 include/linux/clk/scmi.h
diff --git a/drivers/clk/clk-scmi.c b/drivers/clk/clk-scmi.c
index 7c562559ad8bb47f..20e6da1859290b75 100644
--- a/drivers/clk/clk-scmi.c
+++ b/drivers/clk/clk-scmi.c
@@ -7,6 +7,7 @@
#include <linux/bits.h>
#include <linux/clk-provider.h>
+#include <linux/clk/scmi.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/of.h>
@@ -364,6 +365,14 @@ scmi_clk_ops_select(struct scmi_clk *sclk, bool atomic_capable,
return ops;
}
+bool scmi_clk_is_pm_clk(struct clk *clk)
+{
+ struct clk_hw *hw = __clk_get_hw(clk);
+
+ return hw && to_scmi_clk(hw)->info->pm_clk;
+}
+EXPORT_SYMBOL_GPL(scmi_clk_is_pm_clk);
+
static int scmi_clocks_probe(struct scmi_device *sdev)
{
int idx, count, err;
diff --git a/include/linux/clk/scmi.h b/include/linux/clk/scmi.h
new file mode 100644
index 0000000000000000..12c338598d09296f
--- /dev/null
+++ b/include/linux/clk/scmi.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0+
+ */
+
+#ifndef __LINUX_CLK_SCMI_H_
+#define __LINUX_CLK_SCMI_H_
+
+#include <linux/types.h>
+
+struct clk;
+
+#if IS_ENABLED(CONFIG_COMMON_CLK_SCMI)
+bool scmi_clk_is_pm_clk(struct clk *clk);
+#else
+static inline bool scmi_clk_is_pm_clk(struct clk *clk) { return false; }
+#endif
+
+#endif /* __LINUX_CLK_SCMI_H_ */
--
2.43.0
^ permalink raw reply related
* [PATCH/RFC 6/9] dt-bindings: firmware: arm,scmi: Document arm,clock-domain
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
Power management of on-SoC modules is typically handled through two
methods: module power control and module clock gating. The former is
exposed as an SCMI power domain, the latter as an SCMI clock.
Document the new arm,clock-domain property, to link the SCMI power domain
provider to the clock domain provider that is responsible for module
clock gating.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
Documentation/devicetree/bindings/firmware/arm,scmi.yaml | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
index d06cca9273c483c0..18e4da3884c4c12e 100644
--- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
+++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
@@ -174,6 +174,13 @@ properties:
'#power-domain-cells':
const: 1
+ arm,clock-domain:
+ $ref: /schemas/types.yaml#/definitions/phandle
+ description:
+ When PM domain consumer devices are also part of a clock domain, this
+ property should be a reference to the SCMI clock protocol node for
+ the power management clocks in the clock domain.
+
required:
- '#power-domain-cells'
--
2.43.0
^ permalink raw reply related
* [PATCH/RFC 7/9] pmdomain: arm: scmi: Add clock domain support
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
PM domain consumer devices may also part of a clock domain.
Add support for managing power management clocks in a clock domain
through Runtime PM.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
drivers/pmdomain/arm/Kconfig | 1 +
drivers/pmdomain/arm/scmi_pm_domain.c | 81 ++++++++++++++++++++++++++-
2 files changed, 81 insertions(+), 1 deletion(-)
diff --git a/drivers/pmdomain/arm/Kconfig b/drivers/pmdomain/arm/Kconfig
index afed10d382ad7f66..11c4db47c1eadab0 100644
--- a/drivers/pmdomain/arm/Kconfig
+++ b/drivers/pmdomain/arm/Kconfig
@@ -14,6 +14,7 @@ config ARM_SCMI_PERF_DOMAIN
config ARM_SCMI_POWER_DOMAIN
tristate "SCMI power domain driver"
depends on ARM_SCMI_PROTOCOL || (COMPILE_TEST && OF)
+ depends on COMMON_CLK_SCMI || !COMMON_CLK_SCMI
default ARM_SCMI_PROTOCOL
select PM_GENERIC_DOMAINS if PM
help
diff --git a/drivers/pmdomain/arm/scmi_pm_domain.c b/drivers/pmdomain/arm/scmi_pm_domain.c
index 8e67f971c707e121..838917d3b236e3aa 100644
--- a/drivers/pmdomain/arm/scmi_pm_domain.c
+++ b/drivers/pmdomain/arm/scmi_pm_domain.c
@@ -5,9 +5,12 @@
* Copyright (C) 2018-2021 ARM Ltd.
*/
+#include <linux/clk.h>
+#include <linux/clk/scmi.h>
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/pm_clock.h>
#include <linux/pm_domain.h>
#include <linux/scmi_protocol.h>
@@ -16,6 +19,7 @@ static const struct scmi_power_proto_ops *power_ops;
struct scmi_pm_domain {
struct generic_pm_domain genpd;
const struct scmi_protocol_handle *ph;
+ struct device_node *clock_domain;
const char *name;
u32 domain;
};
@@ -39,6 +43,67 @@ static int scmi_pd_power_off(struct generic_pm_domain *domain)
return scmi_pd_power(domain, SCMI_POWER_STATE_GENERIC_OFF);
}
+static int scmi_pd_attach_dev(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ struct scmi_pm_domain *pd = to_scmi_pd(domain);
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args clkspec;
+ bool once = true;
+ struct clk *clk;
+ int ret;
+
+ for (int i = 0;
+ !of_parse_phandle_with_args(np, "clocks", "#clock-cells", i, &clkspec);
+ i++) {
+ if (clkspec.np != pd->clock_domain || clkspec.args_count != 1) {
+ of_node_put(clkspec.np);
+ continue;
+ }
+
+ clk = of_clk_get_from_provider(&clkspec);
+ of_node_put(clkspec.np);
+ if (!clk)
+ continue;
+
+ if (IS_ERR(clk)) {
+ ret = PTR_ERR(clk);
+ clk = NULL;
+ goto fail;
+ }
+
+ if (!scmi_clk_is_pm_clk(clk)) {
+ clk_put(clk);
+ continue;
+ }
+
+ if (once) {
+ once = false;
+ ret = pm_clk_create(dev);
+ if (ret)
+ goto fail;
+ }
+
+ ret = pm_clk_add_clk(dev, clk);
+ if (ret)
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ pm_clk_destroy(dev);
+ clk_put(clk);
+ return ret;
+}
+
+static void scmi_pd_detach_dev(struct generic_pm_domain *domain,
+ struct device *dev)
+{
+ if (!pm_clk_no_clocks(dev))
+ pm_clk_destroy(dev);
+}
+
static int scmi_pm_domain_probe(struct scmi_device *sdev)
{
int num_domains, i, ret;
@@ -48,6 +113,7 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
struct genpd_onecell_data *scmi_pd_data;
struct generic_pm_domain **domains;
const struct scmi_handle *handle = sdev->handle;
+ struct device_node *clock_domain;
struct scmi_protocol_handle *ph;
if (!handle)
@@ -75,6 +141,8 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
if (!domains)
return -ENOMEM;
+ clock_domain = of_parse_phandle(np, "arm,clock-domain", 0);
+
for (i = 0; i < num_domains; i++, scmi_pd++) {
const struct scmi_power_domain_info *info;
u32 state;
@@ -106,6 +174,12 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
scmi_pd->genpd.power_on = scmi_pd_power_on;
scmi_pd->genpd.flags = GENPD_FLAG_ACTIVE_WAKEUP |
info->genpd_flags;
+ if (clock_domain) {
+ scmi_pd->clock_domain = of_node_get(clock_domain);
+ scmi_pd->genpd.attach_dev = scmi_pd_attach_dev;
+ scmi_pd->genpd.detach_dev = scmi_pd_detach_dev;
+ scmi_pd->genpd.flags |= GENPD_FLAG_PM_CLK;
+ }
pm_genpd_init(&scmi_pd->genpd, NULL,
state == SCMI_POWER_STATE_GENERIC_OFF);
@@ -113,6 +187,8 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
domains[i] = &scmi_pd->genpd;
}
+ of_node_put(clock_domain);
+
scmi_pd_data->domains = domains;
scmi_pd_data->num_domains = num_domains;
@@ -134,8 +210,10 @@ static int scmi_pm_domain_probe(struct scmi_device *sdev)
return 0;
err_rm_genpds:
- for (i = num_domains - 1; i >= 0; i--)
+ for (i = num_domains - 1; i >= 0; i--) {
pm_genpd_remove(domains[i]);
+ of_node_put(to_scmi_pd(domains[i])->clock_domain);
+ }
return ret;
}
@@ -158,6 +236,7 @@ static void scmi_pm_domain_remove(struct scmi_device *sdev)
if (!scmi_pd_data->domains[i])
continue;
pm_genpd_remove(scmi_pd_data->domains[i]);
+ of_node_put(to_scmi_pd(scmi_pd_data->domains[i])->clock_domain);
}
}
--
2.43.0
^ permalink raw reply related
* [PATCH/RFC 8/9] firmware: arm_scmi: quirk: Handle power management clocks on R-Car X5H
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
On Renesas R-Car X5H, power management of on-SoC modules is handled
through two methods: module power control and module clock gating. The
former is exposed as an SCMI power domain, the latter as an SCMI clock.
Currently the SCMI clock protocol does not support advertizing
power-management clocks yet. Add quirks to mark all module clocks
suitable for power management, reusing the existing clock_rcar_x5h_4_28
and clock_rcar_x5h_4_31 quirk keys.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
This patch is included as a PoC.
This does not build as the quirk keys are not added in this series.
---
drivers/firmware/arm_scmi/clock.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/firmware/arm_scmi/clock.c b/drivers/firmware/arm_scmi/clock.c
index 42e666a628c732e5..c2648f9f283f2488 100644
--- a/drivers/firmware/arm_scmi/clock.c
+++ b/drivers/firmware/arm_scmi/clock.c
@@ -355,6 +355,18 @@ scmi_clock_get_permissions(const struct scmi_protocol_handle *ph, u32 clk_id,
return ret;
}
+#define QUIRK_RCAR_X5H_4_28_PM_CLK \
+ ({ \
+ if (clk_id <= 818 /* Last MDLC clock MDLC_GPIODM3 */) \
+ clk->pm_clk = true; \
+ })
+
+#define QUIRK_RCAR_X5H_4_31_PM_CLK \
+ ({ \
+ if (clk_id <= 814 /* Last MDLC clock MDLC_GPIODM3 */) \
+ clk->pm_clk = true; \
+ })
+
static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
u32 clk_id, struct clock_info *cinfo)
{
@@ -410,6 +422,9 @@ static int scmi_clock_attributes_get(const struct scmi_protocol_handle *ph,
if (SUPPORTS_EXTENDED_CONFIG(attributes))
clk->extended_config = true;
}
+
+ SCMI_QUIRK(clock_rcar_x5h_4_28, QUIRK_RCAR_X5H_4_28_PM_CLK);
+ SCMI_QUIRK(clock_rcar_x5h_4_31, QUIRK_RCAR_X5H_4_31_PM_CLK);
}
return ret;
--
2.43.0
^ permalink raw reply related
* [PATCH/RFC 9/9] arm64: dts: renesas: ironhide: Switch to pure SCMI
From: Geert Uytterhoeven @ 2026-06-11 13:02 UTC (permalink / raw)
To: Sudeep Holla, Cristian Marussi, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Michael Turquette, Stephen Boyd, Brian Masney,
Ulf Hansson
Cc: arm-scmi, linux-arm-kernel, devicetree, linux-clk, linux-pm,
linux-renesas-soc, linux-kernel, Geert Uytterhoeven
In-Reply-To: <cover.1781171705.git.geert+renesas@glider.be>
Switch from CPG/MDLC remapping to pure SCMI:
- Add SCMI IDs for selected devices, supporting SCP FW SDK v4.28,
v4.31, and v4.32,
- Enable SCMI clock domain support,
- Replace clocks, power-domains, and resets properties by pure SCMI
references.
Note that the user must uncomment the line that defines
R_CAR_X5H_SCP_FW_SDK_VERSION to the SCP FW SDK version being used.
Signed-off-by: Geert Uytterhoeven <geert+renesas@glider.be>
---
This patch is included as a PoC.
This fails to apply, as the SCMI protocol subnodes are not added in this
series.
---
.../boot/dts/renesas/r8a78000-ironhide.dts | 44 +++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts b/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
index 00b5a010b7247722..f4093c359b21379e 100644
--- a/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
+++ b/arch/arm64/boot/dts/renesas/r8a78000-ironhide.dts
@@ -9,6 +9,45 @@
#include <dt-bindings/soc/renesas,r8a78000-mfis.h>
#include "r8a78000.dtsi"
+#define V4_28 4028
+#define V4_31 4031 // Supports v4.31 and v4.32
+
+//#define R_CAR_X5H_SCP_FW_SDK_VERSION V4_28
+#define R_CAR_X5H_SCP_FW_SDK_VERSION V4_31
+
+#if R_CAR_X5H_SCP_FW_SDK_VERSION == V4_28
+
+#define CLK_SGD4_PERW_BUS 1661
+#define MDLC_HSCIF0 228
+#define MDLC_HSCIF1 229
+#define MDLC_SCIF0 209
+#define MDLC_SCIF1 210
+#define MDLC_UFS1 203
+#define RESET_HSCIF0 228
+#define RESET_HSCIF1 229
+#define RESET_SCIF0 209
+#define RESET_SCIF1 210
+#define RESET_UFS1 203
+
+#elif R_CAR_X5H_SCP_FW_SDK_VERSION == V4_31
+
+#define CLK_SGD4_PERW_BUS 1657
+#define MDLC_HSCIF0 224
+#define MDLC_HSCIF1 225
+#define MDLC_SCIF0 205
+#define MDLC_SCIF1 206
+#define MDLC_UFS1 199
+#define RESET_HSCIF0 224
+#define RESET_HSCIF1 225
+#define RESET_SCIF0 205
+#define RESET_SCIF1 206
+#define RESET_UFS1 199
+
+#endif
+
+#define PD_APL 257
+#define PD_UFS1 13
+
/ {
model = "Renesas Ironhide board based on r8a78000";
compatible = "renesas,ironhide", "renesas,r8a78000";
@@ -35,6 +74,7 @@ scmi: scmi {
scmi_devpd: protocol@11 {
reg = <0x11>;
#power-domain-cells = <1>;
+ arm,clock-domain = <&scmi_clk>;
};
scmi_sys: protocol@12 {
@@ -138,6 +178,10 @@ &extalr_clk {
};
&hscif0 {
+ clocks = <&scmi_clk MDLC_HSCIF0>, <&scmi_clk CLK_SGD4_PERW_BUS>,
+ <&scif_clk>;
+ power-domains = <&scmi_devpd PD_APL>;
+ resets = <&scmi_reset RESET_HSCIF0>;
uart-has-rtscts;
status = "okay";
};
--
2.43.0
^ permalink raw reply related
* [PATCH v7 0/6] Switch Arm SMCCC firmware services to an SMCCC bus
From: Aneesh Kumar K.V (Arm) @ 2026-06-11 13:04 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
As discussed here:
https://lore.kernel.org/all/20250728135216.48084-12-aneesh.kumar@kernel.org
The earlier CCA guest support used an arm-cca-dev platform device as a pure
software anchor for the TSM class device. That platform device did not
correspond to a DT/ACPI described device, MMIO range, interrupt, or other
platform resource; it existed only to make the CCA guest driver bind and to
place the resulting TSM device in the driver model. The same pattern also
exists for smccc_trng. Creating separate platform devices for such
SMCCC-discovered features is misleading, because those features are not
independent platform devices.
This series adds an Arm SMCCC bus for services discovered through the SMCCC
firmware interface. The bus provides SMCCC device and driver registration
helpers, name-based matching, uevent modalias generation, and a sysfs modalias
attribute. SMCCC service drivers can use MODULE_DEVICE_TABLE(arm_smccc, ...)
to emit arm_smccc:<name> aliases, allowing userspace to autoload service
drivers when the SMCCC core registers matching firmware-service devices.
The series then moves SMCCC TRNG and the Arm CCA guest RSI service off the
platform bus. When the SMCCC core discovers the corresponding firmware
service, it registers an arm-smccc device for that service. The hwrng
arm_smccc_trng driver and the Arm CCA guest TSM provider are converted to
SMCCC drivers that bind to those discovered devices.
The old arm-cca-dev platform device has also been used by userspace as a Realm
guest indicator. Removing it without a replacement would leave userspace
depending on an internal driver-binding device. This series therefore adds
/sys/firmware/cca/realm_guest as a stable, architecture-provided ABI for
detecting whether the kernel is running as an Arm CCA Realm guest, and then
removes the dummy arm-cca-dev platform-device registration.
Changes since v6:
* Move SMCCC bus-related code to bus.c.
* Remove CONFIG_ARM64 #ifdefs and switch device creation to use the generic function-ID support framework.
* Move version-specific checks and other conditionals to the device driver probe routines.
* Move RSI definitions to include/linux/arm-smccc-rsi.h.
* Split the file and variable renames into a separate patch.
Changes from v5:
https://lore.kernel.org/all/20260514094030.42495-1-aneesh.kumar@kernel.org
* Replace the arm-smccc platform-device plus auxiliary-child model with a
dedicated Arm SMCCC bus.
* Add SMCCC module alias support so SMCCC service drivers can use
MODULE_DEVICE_TABLE(arm_smccc, ...) and autoload through arm_smccc:<name>
aliases.
* Convert smccc_trng from a platform driver to an SMCCC driver.
* Convert the Arm CCA guest TSM provider from the arm-cca-dev platform device
to an SMCCC driver bound to the discovered RSI service.
* Add /sys/firmware/cca/realm_guest before removing the old arm-cca-dev dummy
platform device.
Changes from v4:
https://lore.kernel.org/all/20260427061615.905018-1-aneesh.kumar@kernel.org
* Add /sys/firmware/cca/realm_guest for detecting realm guest
* Convert smccc_trng to auxiliary device from platform device
Changes from v3:
https://lore.kernel.org/all/20260309100507.2303361-1-aneesh.kumar@kernel.org
* Rebased onto the latest kernel
* Drop pr_fmt() from drivers/firmware/smccc/rmm.c
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Greg KH <gregkh@linuxfoundation.org>
Cc: Jeremy Linton <jeremy.linton@arm.com>
Cc: Jonathan Cameron <jic23@kernel.org>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Sudeep Holla <sudeep.holla@arm.com>
Cc: Will Deacon <will@kernel.org>
Cc: Steven Price <steven.price@arm.com>
Cc: Suzuki K Poulose <Suzuki.Poulose@arm.com>
Cc: Andre Przywara <andre.przywara@arm.com>
Aneesh Kumar K.V (Arm) (6):
firmware: smccc: Add an Arm SMCCC bus
firmware: hwrng: arm_smccc_trng: Register as an SMCCC device
firmware: smccc: Move RSI definitions to include/linux
virt: coco: arm-cca-guest: Rename TSM report source file
firmware: smccc: arm-cca-guest: Bind the TSM provider to an SMCCC
device
coco: guest: arm64: Replace dummy CCA device with sysfs ABI
Documentation/ABI/testing/sysfs-firmware-cca | 10 ++
arch/arm64/include/asm/archrandom.h | 2 +-
arch/arm64/include/asm/rsi.h | 2 -
arch/arm64/include/asm/rsi_cmds.h | 74 +-------
arch/arm64/kernel/rsi.c | 39 +++--
drivers/char/hw_random/arm_smccc_trng.c | 32 ++--
drivers/firmware/smccc/Makefile | 2 +-
drivers/firmware/smccc/bus.c | 164 ++++++++++++++++++
drivers/firmware/smccc/smccc.c | 65 ++++++-
drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
drivers/virt/coco/arm-cca-guest/Makefile | 2 +
.../{arm-cca-guest.c => arm-cca.c} | 62 +++----
drivers/virt/coco/arm-cca-guest/rsi.h | 84 +++++++++
include/linux/arm-smccc-bus.h | 49 ++++++
.../linux/arm-smccc-rsi.h | 8 +-
include/linux/mod_devicetable.h | 13 ++
scripts/mod/devicetable-offsets.c | 3 +
scripts/mod/file2alias.c | 8 +
18 files changed, 480 insertions(+), 140 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-cca
create mode 100644 drivers/firmware/smccc/bus.c
rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (85%)
create mode 100644 drivers/virt/coco/arm-cca-guest/rsi.h
create mode 100644 include/linux/arm-smccc-bus.h
rename arch/arm64/include/asm/rsi_smc.h => include/linux/arm-smccc-rsi.h (97%)
base-commit: ddd664bbff63e09e7a7f9acae9c43605d4cf185f
--
2.43.0
^ permalink raw reply
* [PATCH v7 1/6] firmware: smccc: Add an Arm SMCCC bus
From: Aneesh Kumar K.V (Arm) @ 2026-06-11 13:04 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260611130429.295516-1-aneesh.kumar@kernel.org>
SMCCC-discovered firmware services are currently represented by separate
platform devices, such as smccc_trng and arm-cca-dev. Those devices do not
represent independent DT/ACPI-described platform resources; they are
features of the SMCCC firmware interface.
Add an Arm SMCCC bus for services discovered through the SMCCC firmware
interface. The bus provides SMCCC device and driver registration helpers,
name-based matching, modalias generation, and a sysfs modalias attribute so
SMCCC service drivers can bind to discovered firmware services and autoload
as modules.
Follow-up changes can then register SMCCC firmware services as arm-smccc
devices instead of creating independent per-feature platform devices.
Based on arm_ffa code
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
drivers/firmware/smccc/Makefile | 2 +-
drivers/firmware/smccc/bus.c | 164 ++++++++++++++++++++++++++++++
include/linux/arm-smccc-bus.h | 49 +++++++++
include/linux/mod_devicetable.h | 13 +++
scripts/mod/devicetable-offsets.c | 3 +
scripts/mod/file2alias.c | 8 ++
6 files changed, 238 insertions(+), 1 deletion(-)
create mode 100644 drivers/firmware/smccc/bus.c
create mode 100644 include/linux/arm-smccc-bus.h
diff --git a/drivers/firmware/smccc/Makefile b/drivers/firmware/smccc/Makefile
index 40d19144a860..68bbff1407b8 100644
--- a/drivers/firmware/smccc/Makefile
+++ b/drivers/firmware/smccc/Makefile
@@ -1,4 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
#
-obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
+obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += bus.o smccc.o kvm_guest.o
obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
diff --git a/drivers/firmware/smccc/bus.c b/drivers/firmware/smccc/bus.c
new file mode 100644
index 000000000000..fe7e893130ce
--- /dev/null
+++ b/drivers/firmware/smccc/bus.c
@@ -0,0 +1,164 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Arm Limited
+ */
+
+#include <linux/arm-smccc-bus.h>
+#include <linux/idr.h>
+#include <linux/slab.h>
+
+static DEFINE_IDA(arm_smccc_bus_id);
+
+static int arm_smccc_bus_match(struct device *dev,
+ const struct device_driver *drv)
+{
+ const struct arm_smccc_device_id *id_table;
+ struct arm_smccc_device *smccc_dev = to_arm_smccc_device(dev);
+
+ id_table = to_arm_smccc_driver(drv)->id_table;
+ if (!id_table)
+ return 0;
+
+ while (id_table->name[0]) {
+ if (!strcmp(smccc_dev->name, id_table->name))
+ return 1;
+ id_table++;
+ }
+
+ return 0;
+}
+
+static int arm_smccc_bus_probe(struct device *dev)
+{
+ struct arm_smccc_driver *smccc_drv = to_arm_smccc_driver(dev->driver);
+
+ return smccc_drv->probe(to_arm_smccc_device(dev));
+}
+
+static void arm_smccc_bus_remove(struct device *dev)
+{
+ struct arm_smccc_driver *smcc_drv = to_arm_smccc_driver(dev->driver);
+
+ if (smcc_drv->remove)
+ smcc_drv->remove(to_arm_smccc_device(dev));
+}
+
+static int arm_smccc_bus_uevent(const struct device *dev,
+ struct kobj_uevent_env *env)
+{
+ const struct arm_smccc_device *smccc_dev = to_arm_smccc_device(dev);
+
+ return add_uevent_var(env, "MODALIAS=" ARM_SMCCC_MODULE_PREFIX "%s",
+ smccc_dev->name);
+}
+
+static ssize_t modalias_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct arm_smccc_device *smccc_dev = to_arm_smccc_device(dev);
+
+ return sysfs_emit(buf, ARM_SMCCC_MODULE_PREFIX "%s\n", smccc_dev->name);
+}
+static DEVICE_ATTR_RO(modalias);
+
+static struct attribute *arm_smccc_device_attrs[] = {
+ &dev_attr_modalias.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(arm_smccc_device);
+
+const struct bus_type arm_smccc_bus_type = {
+ .name = "arm_smccc",
+ .match = arm_smccc_bus_match,
+ .probe = arm_smccc_bus_probe,
+ .remove = arm_smccc_bus_remove,
+ .uevent = arm_smccc_bus_uevent,
+ .dev_groups = arm_smccc_device_groups,
+};
+EXPORT_SYMBOL_GPL(arm_smccc_bus_type);
+
+int arm_smccc_driver_register(struct arm_smccc_driver *driver,
+ struct module *owner, const char *mod_name)
+{
+ if (!driver->probe)
+ return -EINVAL;
+
+ driver->driver.bus = &arm_smccc_bus_type;
+ driver->driver.name = driver->name;
+ driver->driver.owner = owner;
+ driver->driver.mod_name = mod_name;
+
+ return driver_register(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(arm_smccc_driver_register);
+
+void arm_smccc_driver_unregister(struct arm_smccc_driver *driver)
+{
+ driver_unregister(&driver->driver);
+}
+EXPORT_SYMBOL_GPL(arm_smccc_driver_unregister);
+
+static void arm_smccc_release_device(struct device *dev)
+{
+ struct arm_smccc_device *smccc_dev = to_arm_smccc_device(dev);
+
+ ida_free(&arm_smccc_bus_id, smccc_dev->id);
+ kfree(smccc_dev);
+}
+
+struct arm_smccc_device *arm_smccc_device_register(const char *name)
+{
+ struct arm_smccc_device *smccc_dev;
+ int id, ret;
+
+ id = ida_alloc_min(&arm_smccc_bus_id, 1, GFP_KERNEL);
+ if (id < 0)
+ return ERR_PTR(id);
+
+ smccc_dev = kzalloc_obj(*smccc_dev);
+ if (!smccc_dev) {
+ ida_free(&arm_smccc_bus_id, id);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ smccc_dev->id = id;
+ if (strscpy(smccc_dev->name, name) < 0) {
+ kfree(smccc_dev);
+ ida_free(&arm_smccc_bus_id, id);
+ return ERR_PTR(-EINVAL);
+ }
+ smccc_dev->dev.bus = &arm_smccc_bus_type;
+ smccc_dev->dev.release = arm_smccc_release_device;
+
+ ret = dev_set_name(&smccc_dev->dev, "%s-%d", smccc_dev->name, id);
+ if (ret) {
+ kfree(smccc_dev);
+ ida_free(&arm_smccc_bus_id, id);
+ return ERR_PTR(ret);
+ }
+
+ ret = device_register(&smccc_dev->dev);
+ if (ret) {
+ put_device(&smccc_dev->dev);
+ return ERR_PTR(ret);
+ }
+
+ return smccc_dev;
+}
+EXPORT_SYMBOL_GPL(arm_smccc_device_register);
+
+void arm_smccc_device_unregister(struct arm_smccc_device *smccc_dev)
+{
+ if (!smccc_dev)
+ return;
+
+ device_unregister(&smccc_dev->dev);
+}
+EXPORT_SYMBOL_GPL(arm_smccc_device_unregister);
+
+static int __init arm_smccc_bus_init(void)
+{
+ return bus_register(&arm_smccc_bus_type);
+}
+subsys_initcall(arm_smccc_bus_init);
+
diff --git a/include/linux/arm-smccc-bus.h b/include/linux/arm-smccc-bus.h
new file mode 100644
index 000000000000..188891441e57
--- /dev/null
+++ b/include/linux/arm-smccc-bus.h
@@ -0,0 +1,49 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 Arm Limited
+ */
+#ifndef __LINUX_ARM_SMCCC_BUS_H
+#define __LINUX_ARM_SMCCC_BUS_H
+
+#include <linux/device.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+
+struct arm_smccc_device {
+ int id;
+ char name[ARM_SMCCC_NAME_SIZE];
+ struct device dev;
+};
+
+#define to_arm_smccc_device(d) container_of(d, struct arm_smccc_device, dev)
+
+struct arm_smccc_driver {
+ const char *name;
+ int (*probe)(struct arm_smccc_device *sdev);
+ void (*remove)(struct arm_smccc_device *sdev);
+ const struct arm_smccc_device_id *id_table;
+
+ struct device_driver driver;
+};
+
+#define to_arm_smccc_driver(d) \
+ container_of_const(d, struct arm_smccc_driver, driver)
+
+int arm_smccc_driver_register(struct arm_smccc_driver *driver,
+ struct module *owner, const char *mod_name);
+void arm_smccc_driver_unregister(struct arm_smccc_driver *driver);
+struct arm_smccc_device *arm_smccc_device_register(const char *name);
+void arm_smccc_device_unregister(struct arm_smccc_device *smcc_dev);
+
+#define arm_smccc_register(driver) \
+ arm_smccc_driver_register(driver, THIS_MODULE, KBUILD_MODNAME)
+#define arm_smccc_unregister(driver) \
+ arm_smccc_driver_unregister(driver)
+
+#define module_arm_smccc_driver(__arm_smccc_driver) \
+ module_driver(__arm_smccc_driver, arm_smccc_register, \
+ arm_smccc_unregister)
+
+extern const struct bus_type arm_smccc_bus_type;
+
+#endif /* __LINUX_ARM_SMCCC_BUS_H */
diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
index 23ff24080dfd..c9cee8c5a0b2 100644
--- a/include/linux/mod_devicetable.h
+++ b/include/linux/mod_devicetable.h
@@ -876,6 +876,19 @@ struct auxiliary_device_id {
kernel_ulong_t driver_data;
};
+#define ARM_SMCCC_NAME_SIZE 40
+#define ARM_SMCCC_MODULE_PREFIX "arm_smccc:"
+
+/**
+ * struct arm_smccc_device_id - Arm SMCCC bus device identifier
+ * @name: SMCCC device name
+ * @driver_data: driver data
+ */
+struct arm_smccc_device_id {
+ char name[ARM_SMCCC_NAME_SIZE];
+ kernel_ulong_t driver_data;
+};
+
/* Surface System Aggregator Module */
#define SSAM_MATCH_TARGET 0x1
diff --git a/scripts/mod/devicetable-offsets.c b/scripts/mod/devicetable-offsets.c
index b4178c42d08f..a485011ff137 100644
--- a/scripts/mod/devicetable-offsets.c
+++ b/scripts/mod/devicetable-offsets.c
@@ -254,6 +254,9 @@ int main(void)
DEVID(auxiliary_device_id);
DEVID_FIELD(auxiliary_device_id, name);
+ DEVID(arm_smccc_device_id);
+ DEVID_FIELD(arm_smccc_device_id, name);
+
DEVID(ssam_device_id);
DEVID_FIELD(ssam_device_id, match_flags);
DEVID_FIELD(ssam_device_id, domain);
diff --git a/scripts/mod/file2alias.c b/scripts/mod/file2alias.c
index 2ad87a74bb03..92d3917f27cc 100644
--- a/scripts/mod/file2alias.c
+++ b/scripts/mod/file2alias.c
@@ -1323,6 +1323,13 @@ static void do_auxiliary_entry(struct module *mod, void *symval)
module_alias_printf(mod, false, AUXILIARY_MODULE_PREFIX "%s", *name);
}
+static void do_arm_smccc_entry(struct module *mod, void *symval)
+{
+ DEF_FIELD_ADDR(symval, arm_smccc_device_id, name);
+
+ module_alias_printf(mod, false, ARM_SMCCC_MODULE_PREFIX "%s", *name);
+}
+
/*
* Looks like: ssam:dNcNtNiNfN
*
@@ -1493,6 +1500,7 @@ static const struct devtable devtable[] = {
{"mhi", SIZE_mhi_device_id, do_mhi_entry},
{"mhi_ep", SIZE_mhi_device_id, do_mhi_ep_entry},
{"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry},
+ {"arm_smccc", SIZE_arm_smccc_device_id, do_arm_smccc_entry},
{"ssam", SIZE_ssam_device_id, do_ssam_entry},
{"dfl", SIZE_dfl_device_id, do_dfl_entry},
{"ishtp", SIZE_ishtp_device_id, do_ishtp_entry},
--
2.43.0
^ permalink raw reply related
* [PATCH v7 2/6] firmware: hwrng: arm_smccc_trng: Register as an SMCCC device
From: Aneesh Kumar K.V (Arm) @ 2026-06-11 13:04 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260611130429.295516-1-aneesh.kumar@kernel.org>
The SMCCC TRNG interface is a firmware-provided SMCCC service rather than a
standalone platform device. Now that the SMCCC core has an SMCCC bus,
create an arm-smccc-trng device for the discovered TRNG service and convert
the hwrng driver to an SMCCC driver.
The SMCCC id table preserves module autoloading for systems where the TRNG
driver is built as a module.
The sysfs device path changes from the old smccc_trng platform-device path
to an arm-smccc device path. No known userspace dependency on the old path
was found; a Debian Code Search lookup for the existing platform-device
name/path did not find any users.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
arch/arm64/include/asm/archrandom.h | 2 +-
drivers/char/hw_random/arm_smccc_trng.c | 32 +++++++++-----
drivers/firmware/smccc/smccc.c | 58 +++++++++++++++++++++----
3 files changed, 71 insertions(+), 21 deletions(-)
diff --git a/arch/arm64/include/asm/archrandom.h b/arch/arm64/include/asm/archrandom.h
index 8babfbe31f95..7605dd81bd1e 100644
--- a/arch/arm64/include/asm/archrandom.h
+++ b/arch/arm64/include/asm/archrandom.h
@@ -12,7 +12,7 @@
extern bool smccc_trng_available;
-static inline bool __init smccc_probe_trng(void)
+static inline bool smccc_probe_trng(void)
{
struct arm_smccc_res res;
diff --git a/drivers/char/hw_random/arm_smccc_trng.c b/drivers/char/hw_random/arm_smccc_trng.c
index dcb8e7f37f25..8f7f9d830cf2 100644
--- a/drivers/char/hw_random/arm_smccc_trng.c
+++ b/drivers/char/hw_random/arm_smccc_trng.c
@@ -16,8 +16,10 @@
#include <linux/device.h>
#include <linux/hw_random.h>
#include <linux/module.h>
-#include <linux/platform_device.h>
#include <linux/arm-smccc.h>
+#include <linux/arm-smccc-bus.h>
+
+#include <asm/archrandom.h>
#ifdef CONFIG_ARM64
#define ARM_SMCCC_TRNG_RND ARM_SMCCC_TRNG_RND64
@@ -94,29 +96,37 @@ static int smccc_trng_read(struct hwrng *rng, void *data, size_t max, bool wait)
return copied;
}
-static int smccc_trng_probe(struct platform_device *pdev)
+static int smccc_trng_probe(struct arm_smccc_device *sdev)
{
struct hwrng *trng;
- trng = devm_kzalloc(&pdev->dev, sizeof(*trng), GFP_KERNEL);
+ /* validate the minimum version requirement */
+ if (!smccc_probe_trng())
+ return -ENODEV;
+
+ trng = devm_kzalloc(&sdev->dev, sizeof(*trng), GFP_KERNEL);
if (!trng)
return -ENOMEM;
trng->name = "smccc_trng";
trng->read = smccc_trng_read;
- return devm_hwrng_register(&pdev->dev, trng);
+ return devm_hwrng_register(&sdev->dev, trng);
}
-static struct platform_driver smccc_trng_driver = {
- .driver = {
- .name = "smccc_trng",
- },
- .probe = smccc_trng_probe,
+static const struct arm_smccc_device_id smccc_trng_id_table[] = {
+ { .name = "arm-smccc-trng" },
+ {}
+};
+MODULE_DEVICE_TABLE(arm_smccc, smccc_trng_id_table);
+
+static struct arm_smccc_driver smccc_trng_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = smccc_trng_probe,
+ .id_table = smccc_trng_id_table,
};
-module_platform_driver(smccc_trng_driver);
+module_arm_smccc_driver(smccc_trng_driver);
-MODULE_ALIAS("platform:smccc_trng");
MODULE_AUTHOR("Andre Przywara");
MODULE_DESCRIPTION("Arm SMCCC TRNG firmware interface support");
MODULE_LICENSE("GPL");
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index bdee057db2fd..a47696f3a5de 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -9,7 +9,8 @@
#include <linux/init.h>
#include <linux/arm-smccc.h>
#include <linux/kernel.h>
-#include <linux/platform_device.h>
+#include <linux/arm-smccc-bus.h>
+
#include <asm/archrandom.h>
static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
@@ -81,16 +82,55 @@ bool arm_smccc_hypervisor_has_uuid(const uuid_t *hyp_uuid)
}
EXPORT_SYMBOL_GPL(arm_smccc_hypervisor_has_uuid);
+struct smccc_device_info {
+ u32 func_id;
+ bool requires_smc;
+ const char *device_name;
+};
+
+static const struct smccc_device_info smccc_devices[] __initconst = {
+ {
+ .func_id = ARM_SMCCC_TRNG_VERSION,
+ .requires_smc = false,
+ .device_name = "arm-smccc-trng",
+ },
+};
+
+static bool __init smccc_probe_smccc_device(const struct smccc_device_info *smccc_dev)
+{
+ unsigned long ret;
+ struct arm_smccc_res res;
+
+ if (smccc_conduit == SMCCC_CONDUIT_NONE)
+ return false;
+
+ if (smccc_dev->requires_smc && smccc_conduit != SMCCC_CONDUIT_SMC)
+ return false;
+
+ arm_smccc_1_1_invoke(smccc_dev->func_id, &res);
+ ret = res.a0;
+
+ if ((s32)ret == SMCCC_RET_NOT_SUPPORTED)
+ return false;
+
+ return true;
+}
+
static int __init smccc_devices_init(void)
{
- struct platform_device *pdev;
-
- if (smccc_trng_available) {
- pdev = platform_device_register_simple("smccc_trng", -1,
- NULL, 0);
- if (IS_ERR(pdev))
- pr_err("smccc_trng: could not register device: %ld\n",
- PTR_ERR(pdev));
+ struct arm_smccc_device *sdev;
+ const struct smccc_device_info *smccc_dev;
+
+ for (int i = 0; i < ARRAY_SIZE(smccc_devices); i++) {
+ smccc_dev = &smccc_devices[i];
+
+ if (!smccc_probe_smccc_device(smccc_dev))
+ continue;
+
+ sdev = arm_smccc_device_register(smccc_dev->device_name);
+ if (IS_ERR(sdev))
+ pr_err("%s: could not register device: %ld\n",
+ smccc_dev->device_name, PTR_ERR(sdev));
}
return 0;
--
2.43.0
^ permalink raw reply related
* [PATCH v7 3/6] firmware: smccc: Move RSI definitions to include/linux
From: Aneesh Kumar K.V (Arm) @ 2026-06-11 13:04 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260611130429.295516-1-aneesh.kumar@kernel.org>
The RSI SMCCC function IDs describe a firmware ABI and are not arm64
architecture specific definitions. Follow-up changes need to use them from
non-arch code, including drivers/firmware/smccc and the Arm CCA guest
driver.
Move the RSI SMCCC definitions from arch/arm64/include/asm/ to
include/linux/ so they can be shared with the driver code. This also
keeps the firmware interface outside architecture code, as requested [1].
[1] https://lore.kernel.org/all/agsNO9cc7H-b0H8L@willie-the-truck
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
arch/arm64/include/asm/rsi_cmds.h | 74 +---------------
.../virt/coco/arm-cca-guest/arm-cca-guest.c | 2 +
drivers/virt/coco/arm-cca-guest/rsi.h | 84 +++++++++++++++++++
.../linux/arm-smccc-rsi.h | 6 +-
4 files changed, 90 insertions(+), 76 deletions(-)
create mode 100644 drivers/virt/coco/arm-cca-guest/rsi.h
rename arch/arm64/include/asm/rsi_smc.h => include/linux/arm-smccc-rsi.h (98%)
diff --git a/arch/arm64/include/asm/rsi_cmds.h b/arch/arm64/include/asm/rsi_cmds.h
index 2c8763876dfb..633123a4e5d5 100644
--- a/arch/arm64/include/asm/rsi_cmds.h
+++ b/arch/arm64/include/asm/rsi_cmds.h
@@ -8,10 +8,9 @@
#include <linux/arm-smccc.h>
#include <linux/string.h>
+#include <linux/arm-smccc-rsi.h>
#include <asm/memory.h>
-#include <asm/rsi_smc.h>
-
#define RSI_GRANULE_SHIFT 12
#define RSI_GRANULE_SIZE (_AC(1, UL) << RSI_GRANULE_SHIFT)
@@ -88,75 +87,4 @@ static inline long rsi_set_addr_range_state(phys_addr_t start,
return res.a0;
}
-/**
- * rsi_attestation_token_init - Initialise the operation to retrieve an
- * attestation token.
- *
- * @challenge: The challenge data to be used in the attestation token
- * generation.
- * @size: Size of the challenge data in bytes.
- *
- * Initialises the attestation token generation and returns an upper bound
- * on the attestation token size that can be used to allocate an adequate
- * buffer. The caller is expected to subsequently call
- * rsi_attestation_token_continue() to retrieve the attestation token data on
- * the same CPU.
- *
- * Returns:
- * On success, returns the upper limit of the attestation report size.
- * Otherwise, -EINVAL
- */
-static inline long
-rsi_attestation_token_init(const u8 *challenge, unsigned long size)
-{
- struct arm_smccc_1_2_regs regs = { 0 };
-
- /* The challenge must be at least 32bytes and at most 64bytes */
- if (!challenge || size < 32 || size > 64)
- return -EINVAL;
-
- regs.a0 = SMC_RSI_ATTESTATION_TOKEN_INIT;
- memcpy(®s.a1, challenge, size);
- arm_smccc_1_2_smc(®s, ®s);
-
- if (regs.a0 == RSI_SUCCESS)
- return regs.a1;
-
- return -EINVAL;
-}
-
-/**
- * rsi_attestation_token_continue - Continue the operation to retrieve an
- * attestation token.
- *
- * @granule: {I}PA of the Granule to which the token will be written.
- * @offset: Offset within Granule to start of buffer in bytes.
- * @size: The size of the buffer.
- * @len: The number of bytes written to the buffer.
- *
- * Retrieves up to a RSI_GRANULE_SIZE worth of token data per call. The caller
- * is expected to call rsi_attestation_token_init() before calling this
- * function to retrieve the attestation token.
- *
- * Return:
- * * %RSI_SUCCESS - Attestation token retrieved successfully.
- * * %RSI_INCOMPLETE - Token generation is not complete.
- * * %RSI_ERROR_INPUT - A parameter was not valid.
- * * %RSI_ERROR_STATE - Attestation not in progress.
- */
-static inline unsigned long rsi_attestation_token_continue(phys_addr_t granule,
- unsigned long offset,
- unsigned long size,
- unsigned long *len)
-{
- struct arm_smccc_res res;
-
- arm_smccc_1_1_invoke(SMC_RSI_ATTESTATION_TOKEN_CONTINUE,
- granule, offset, size, 0, &res);
-
- if (len)
- *len = res.a1;
- return res.a0;
-}
-
#endif /* __ASM_RSI_CMDS_H */
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
index 66d00b6ceb78..8b6854e7a188 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
@@ -14,6 +14,8 @@
#include <asm/rsi.h>
+#include "rsi.h"
+
/**
* struct arm_cca_token_info - a descriptor for the token buffer.
* @challenge: Pointer to the challenge data
diff --git a/drivers/virt/coco/arm-cca-guest/rsi.h b/drivers/virt/coco/arm-cca-guest/rsi.h
new file mode 100644
index 000000000000..f7303f4bce17
--- /dev/null
+++ b/drivers/virt/coco/arm-cca-guest/rsi.h
@@ -0,0 +1,84 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 ARM Ltd.
+ */
+
+#ifndef _VIRT_COCO_RSI_H_
+#define _VIRT_COCO_RSI_H_
+
+#include <linux/arm-smccc-rsi.h>
+
+/**
+ * rsi_attestation_token_init - Initialise the operation to retrieve an
+ * attestation token.
+ *
+ * @challenge: The challenge data to be used in the attestation token
+ * generation.
+ * @size: Size of the challenge data in bytes.
+ *
+ * Initialises the attestation token generation and returns an upper bound
+ * on the attestation token size that can be used to allocate an adequate
+ * buffer. The caller is expected to subsequently call
+ * rsi_attestation_token_continue() to retrieve the attestation token data on
+ * the same CPU.
+ *
+ * Returns:
+ * On success, returns the upper limit of the attestation report size.
+ * Otherwise, -EINVAL
+ */
+static inline long
+rsi_attestation_token_init(const u8 *challenge, unsigned long size)
+{
+ struct arm_smccc_1_2_regs regs = { 0 };
+
+ /* The challenge must be at least 32bytes and at most 64bytes */
+ if (!challenge || size < 32 || size > 64)
+ return -EINVAL;
+
+ regs.a0 = SMC_RSI_ATTESTATION_TOKEN_INIT;
+ memcpy(®s.a1, challenge, size);
+ arm_smccc_1_2_smc(®s, ®s);
+
+ if (regs.a0 == RSI_SUCCESS)
+ return regs.a1;
+
+ return -EINVAL;
+}
+
+/**
+ * rsi_attestation_token_continue - Continue the operation to retrieve an
+ * attestation token.
+ *
+ * @granule: {I}PA of the Granule to which the token will be written.
+ * @offset: Offset within Granule to start of buffer in bytes.
+ * @size: The size of the buffer.
+ * @len: The number of bytes written to the buffer.
+ *
+ * Retrieves up to a RSI_GRANULE_SIZE worth of token data per call. The caller
+ * is expected to call rsi_attestation_token_init() before calling this
+ * function to retrieve the attestation token.
+ *
+ * Return:
+ * * %RSI_SUCCESS - Attestation token retrieved successfully.
+ * * %RSI_INCOMPLETE - Token generation is not complete.
+ * * %RSI_ERROR_INPUT - A parameter was not valid.
+ * * %RSI_ERROR_STATE - Attestation not in progress.
+ */
+static inline unsigned long rsi_attestation_token_continue(phys_addr_t granule,
+ unsigned long offset,
+ unsigned long size,
+ unsigned long *len)
+{
+ struct arm_smccc_res res;
+
+ arm_smccc_1_1_invoke(SMC_RSI_ATTESTATION_TOKEN_CONTINUE,
+ granule, offset, size, 0, &res);
+
+ if (len)
+ *len = res.a1;
+ return res.a0;
+}
+
+
+
+#endif
diff --git a/arch/arm64/include/asm/rsi_smc.h b/include/linux/arm-smccc-rsi.h
similarity index 98%
rename from arch/arm64/include/asm/rsi_smc.h
rename to include/linux/arm-smccc-rsi.h
index e19253f96c94..fddb77986f70 100644
--- a/arch/arm64/include/asm/rsi_smc.h
+++ b/include/linux/arm-smccc-rsi.h
@@ -3,8 +3,8 @@
* Copyright (C) 2023 ARM Ltd.
*/
-#ifndef __ASM_RSI_SMC_H_
-#define __ASM_RSI_SMC_H_
+#ifndef __LINUX_ARM_SMCCC_RSI_H_
+#define __LINUX_ARM_SMCCC_RSI_H_
#include <linux/arm-smccc.h>
@@ -190,4 +190,4 @@ struct realm_config {
*/
#define SMC_RSI_HOST_CALL SMC_RSI_FID(0x199)
-#endif /* __ASM_RSI_SMC_H_ */
+#endif /* __LINUX_ARM_SMCCC_RSI_H_ */
--
2.43.0
^ permalink raw reply related
* [PATCH v7 4/6] virt: coco: arm-cca-guest: Rename TSM report source file
From: Aneesh Kumar K.V (Arm) @ 2026-06-11 13:04 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260611130429.295516-1-aneesh.kumar@kernel.org>
The Arm CCA guest driver currently only implements TSM report support, but
follow-up changes will add more TSM-related functionality to the same
module.
Rename arm-cca-guest.c to arm-cca.c and build it as an object of the
arm-cca-guest module. This leaves room for the module to grow additional
source files.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
drivers/virt/coco/arm-cca-guest/Makefile | 2 ++
.../virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} | 6 +++---
2 files changed, 5 insertions(+), 3 deletions(-)
rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (97%)
diff --git a/drivers/virt/coco/arm-cca-guest/Makefile b/drivers/virt/coco/arm-cca-guest/Makefile
index 69eeba08e98a..778146148515 100644
--- a/drivers/virt/coco/arm-cca-guest/Makefile
+++ b/drivers/virt/coco/arm-cca-guest/Makefile
@@ -1,2 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_ARM_CCA_GUEST) += arm-cca-guest.o
+
+arm-cca-guest-y += arm-cca.o
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c b/drivers/virt/coco/arm-cca-guest/arm-cca.c
similarity index 97%
rename from drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
rename to drivers/virt/coco/arm-cca-guest/arm-cca.c
index 8b6854e7a188..0bbd1fa53ee4 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca.c
@@ -184,7 +184,7 @@ static int arm_cca_report_new(struct tsm_report *report, void *data)
return ret;
}
-static const struct tsm_report_ops arm_cca_tsm_ops = {
+static const struct tsm_report_ops arm_cca_tsm_report_ops = {
.name = KBUILD_MODNAME,
.report_new = arm_cca_report_new,
};
@@ -205,7 +205,7 @@ static int __init arm_cca_guest_init(void)
if (!is_realm_world())
return -ENODEV;
- ret = tsm_report_register(&arm_cca_tsm_ops, NULL);
+ ret = tsm_report_register(&arm_cca_tsm_report_ops, NULL);
if (ret < 0)
pr_err("Error %d registering with TSM\n", ret);
@@ -219,7 +219,7 @@ module_init(arm_cca_guest_init);
*/
static void __exit arm_cca_guest_exit(void)
{
- tsm_report_unregister(&arm_cca_tsm_ops);
+ tsm_report_unregister(&arm_cca_tsm_report_ops);
}
module_exit(arm_cca_guest_exit);
--
2.43.0
^ permalink raw reply related
* [PATCH v7 5/6] firmware: smccc: arm-cca-guest: Bind the TSM provider to an SMCCC device
From: Aneesh Kumar K.V (Arm) @ 2026-06-11 13:04 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260611130429.295516-1-aneesh.kumar@kernel.org>
The Arm CCA guest TSM provider currently binds through the arm-cca-dev
platform device. Like arm-smccc-trng, this device is not an independent
platform resource; it is a software representation of the RSI firmware
service discovered through SMCCC.
Move RSI discovery into the SMCCC firmware driver. When the SMCCC conduit
is SMC and if RSI ABI version call is supported, create an arm-rsi-dev
SMCCC device. Convert the Arm CCA guest TSM provider to an SMCCC driver so
it binds to that discovered RSI service and keeps module autoloading
through the SMCCC device id table.
Keep the old arm-cca-dev platform-device registration for now. Userspace
has used that device as a Realm-guest indicator, so removing it is left to
a follow-up patch that adds a replacement sysfs ABI.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
arch/arm64/include/asm/rsi.h | 2 -
arch/arm64/kernel/rsi.c | 2 +-
drivers/firmware/smccc/smccc.c | 7 +++
drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
drivers/virt/coco/arm-cca-guest/arm-cca.c | 56 +++++++++++------------
include/linux/arm-smccc-rsi.h | 2 +
6 files changed, 39 insertions(+), 31 deletions(-)
diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
index 88b50d660e85..5f9c8623183d 100644
--- a/arch/arm64/include/asm/rsi.h
+++ b/arch/arm64/include/asm/rsi.h
@@ -10,8 +10,6 @@
#include <linux/jump_label.h>
#include <asm/rsi_cmds.h>
-#define RSI_PDEV_NAME "arm-cca-dev"
-
DECLARE_STATIC_KEY_FALSE(rsi_present);
void __init arm64_rsi_init(void);
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 92160f2e57ff..da440f71bb64 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -161,7 +161,7 @@ void __init arm64_rsi_init(void)
}
static struct platform_device rsi_dev = {
- .name = RSI_PDEV_NAME,
+ .name = "arm-cca-dev",
.id = PLATFORM_DEVID_NONE
};
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index a47696f3a5de..7127af3dbe5c 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -10,6 +10,7 @@
#include <linux/arm-smccc.h>
#include <linux/kernel.h>
#include <linux/arm-smccc-bus.h>
+#include <linux/arm-smccc-rsi.h>
#include <asm/archrandom.h>
@@ -94,6 +95,12 @@ static const struct smccc_device_info smccc_devices[] __initconst = {
.requires_smc = false,
.device_name = "arm-smccc-trng",
},
+
+ {
+ .func_id = SMC_RSI_ABI_VERSION,
+ .requires_smc = true,
+ .device_name = RSI_DEV_NAME,
+ },
};
static bool __init smccc_probe_smccc_device(const struct smccc_device_info *smccc_dev)
diff --git a/drivers/virt/coco/arm-cca-guest/Kconfig b/drivers/virt/coco/arm-cca-guest/Kconfig
index 3f0f013f03f1..ad7538750c5a 100644
--- a/drivers/virt/coco/arm-cca-guest/Kconfig
+++ b/drivers/virt/coco/arm-cca-guest/Kconfig
@@ -1,6 +1,7 @@
config ARM_CCA_GUEST
tristate "Arm CCA Guest driver"
depends on ARM64
+ depends on HAVE_ARM_SMCCC_DISCOVERY
select TSM_REPORTS
help
The driver provides userspace interface to request and
diff --git a/drivers/virt/coco/arm-cca-guest/arm-cca.c b/drivers/virt/coco/arm-cca-guest/arm-cca.c
index 0bbd1fa53ee4..4f9289ccf498 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca.c
@@ -4,6 +4,7 @@
*/
#include <linux/arm-smccc.h>
+#include <linux/arm-smccc-bus.h>
#include <linux/cc_platform.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
@@ -189,16 +190,12 @@ static const struct tsm_report_ops arm_cca_tsm_report_ops = {
.report_new = arm_cca_report_new,
};
-/**
- * arm_cca_guest_init - Register with the Trusted Security Module (TSM)
- * interface.
- *
- * Return:
- * * %0 - Registered successfully with the TSM interface.
- * * %-ENODEV - The execution context is not an Arm Realm.
- * * %-EBUSY - Already registered.
- */
-static int __init arm_cca_guest_init(void)
+static void unregister_cca_tsm_report(void *data)
+{
+ tsm_report_unregister(&arm_cca_tsm_report_ops);
+}
+
+static int cca_tsm_probe(struct arm_smccc_device *sdev)
{
int ret;
@@ -206,30 +203,33 @@ static int __init arm_cca_guest_init(void)
return -ENODEV;
ret = tsm_report_register(&arm_cca_tsm_report_ops, NULL);
- if (ret < 0)
- pr_err("Error %d registering with TSM\n", ret);
+ if (ret < 0) {
+ dev_err_probe(&sdev->dev, ret, "Error registering with TSM\n");
+ return ret;
+ }
- return ret;
-}
-module_init(arm_cca_guest_init);
+ ret = devm_add_action_or_reset(&sdev->dev, unregister_cca_tsm_report,
+ NULL);
+ if (ret < 0) {
+ dev_err_probe(&sdev->dev, ret, "Error registering devm action\n");
+ return ret;
+ }
-/**
- * arm_cca_guest_exit - unregister with the Trusted Security Module (TSM)
- * interface.
- */
-static void __exit arm_cca_guest_exit(void)
-{
- tsm_report_unregister(&arm_cca_tsm_report_ops);
+ return 0;
}
-module_exit(arm_cca_guest_exit);
-/* modalias, so userspace can autoload this module when RSI is available */
-static const struct platform_device_id arm_cca_match[] __maybe_unused = {
- { RSI_PDEV_NAME, 0},
- { }
+static const struct arm_smccc_device_id cca_tsm_id_table[] = {
+ { .name = RSI_DEV_NAME },
+ {}
};
+MODULE_DEVICE_TABLE(arm_smccc, cca_tsm_id_table);
-MODULE_DEVICE_TABLE(platform, arm_cca_match);
+static struct arm_smccc_driver cca_tsm_driver = {
+ .name = KBUILD_MODNAME,
+ .probe = cca_tsm_probe,
+ .id_table = cca_tsm_id_table,
+};
+module_arm_smccc_driver(cca_tsm_driver);
MODULE_AUTHOR("Sami Mujawar <sami.mujawar@arm.com>");
MODULE_DESCRIPTION("Arm CCA Guest TSM Driver");
MODULE_LICENSE("GPL");
diff --git a/include/linux/arm-smccc-rsi.h b/include/linux/arm-smccc-rsi.h
index fddb77986f70..ae663aa8fd7f 100644
--- a/include/linux/arm-smccc-rsi.h
+++ b/include/linux/arm-smccc-rsi.h
@@ -8,6 +8,8 @@
#include <linux/arm-smccc.h>
+#define RSI_DEV_NAME "arm-rsi-dev"
+
/*
* This file describes the Realm Services Interface (RSI) Application Binary
* Interface (ABI) for SMC calls made from within the Realm to the RMM and
--
2.43.0
^ permalink raw reply related
* [PATCH v7 6/6] coco: guest: arm64: Replace dummy CCA device with sysfs ABI
From: Aneesh Kumar K.V (Arm) @ 2026-06-11 13:04 UTC (permalink / raw)
To: linux-coco, linux-arm-kernel, linux-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Steven Price, Suzuki K Poulose, Andre Przywara
In-Reply-To: <20260611130429.295516-1-aneesh.kumar@kernel.org>
The SMCCC firmware driver now creates the arm-smccc platform device and
instantiates the CCA RSI auxiliary devices once the RSI ABI is discovered.
The arm64-specific arm-cca-dev platform device stub is therefore no longer
needed.
However, userspace has used the arm-cca-dev platform device to detect Arm
CCA Realm guests [1]. Removing it without a replacement would break that
detection and would also leave userspace depending on kernel device-model
details.
Add /sys/firmware/cca/realm_guest as a stable, architecture-provided ABI
for detecting whether the kernel is running as an Arm CCA Realm guest. The
file returns 1 in Realm world and 0 otherwise, similar to the existing s390
/sys/firmware/uv/prot_virt_guest interface for protected virtualization
guests.
Remove the dummy arm-cca-dev registration now that userspace has a
dedicated CCA Realm guest indicator, and document the new ABI in
Documentation/ABI/testing/sysfs-firmware-cca.
[1] https://lore.kernel.org/all/4a7d84b2-2ec4-4773-a2d5-7b63d5c683cf@arm.com
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
Documentation/ABI/testing/sysfs-firmware-cca | 10 +++++
arch/arm64/kernel/rsi.c | 39 +++++++++++++++-----
2 files changed, 39 insertions(+), 10 deletions(-)
create mode 100644 Documentation/ABI/testing/sysfs-firmware-cca
diff --git a/Documentation/ABI/testing/sysfs-firmware-cca b/Documentation/ABI/testing/sysfs-firmware-cca
new file mode 100644
index 000000000000..bf177d636b92
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-firmware-cca
@@ -0,0 +1,10 @@
+What: /sys/firmware/cca/realm_guest
+Date: May 2026
+Contact: Linux ARM Kernel Mailing list <linux-arm-kernel@lists.infradead.org>
+Description: Read-only. Indicates whether the kernel is running as an
+ Arm Confidential Compute Architecture (CCA) Realm guest.
+
+ The value is one of:
+
+ 0: the kernel is not running as a Realm guest
+ 1: the kernel is running as a Realm guest
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index da440f71bb64..a333029ddf08 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -9,6 +9,8 @@
#include <linux/swiotlb.h>
#include <linux/cc_platform.h>
#include <linux/platform_device.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
#include <asm/io.h>
#include <asm/mem_encrypt.h>
@@ -16,6 +18,7 @@
#include <asm/rsi.h>
static struct realm_config config;
+static struct kobject *cca_kobj;
unsigned long prot_ns_shared;
EXPORT_SYMBOL(prot_ns_shared);
@@ -160,17 +163,33 @@ void __init arm64_rsi_init(void)
static_branch_enable(&rsi_present);
}
-static struct platform_device rsi_dev = {
- .name = "arm-cca-dev",
- .id = PLATFORM_DEVID_NONE
+static ssize_t cca_is_realm_guest(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ return sysfs_emit(buf, "%d\n", is_realm_world());
+}
+
+static struct kobj_attribute cca_realm_guest =
+ __ATTR(realm_guest, 0444, cca_is_realm_guest, NULL);
+
+static const struct attribute *cca_realm_attrs[] = {
+ &cca_realm_guest.attr,
+ NULL,
};
-static int __init arm64_create_dummy_rsi_dev(void)
+static int __init realm_sysfs_init(void)
{
- if (is_realm_world() &&
- platform_device_register(&rsi_dev))
- pr_err("failed to register rsi platform device\n");
- return 0;
-}
+ int ret;
+
+ cca_kobj = kobject_create_and_add("cca", firmware_kobj);
+ if (!cca_kobj)
+ return -ENOMEM;
-arch_initcall(arm64_create_dummy_rsi_dev)
+ ret = sysfs_create_files(cca_kobj, cca_realm_attrs);
+ if (!ret)
+ return 0;
+
+ kobject_put(cca_kobj);
+ return ret;
+}
+device_initcall(realm_sysfs_init);
--
2.43.0
^ permalink raw reply related
* [PATCH] usb: dwc3: meson-g12a: fix refcount leak in dwc3_meson_g12a_resume()
From: WenTao Liang @ 2026-06-11 13:11 UTC (permalink / raw)
To: Thinh.Nguyen, gregkh, neil.armstrong, khilman
Cc: jbrunet, martin.blumenstingl, linux-usb, linux-arm-kernel,
linux-amlogic, linux-kernel, WenTao Liang, stable
If dwc3_meson_g12a_resume() succeeds in calling
reset_control_reset(), an internal triggered_count reference is
acquired. If any later step fails (usb_init, phy_init,
phy_power_on, regulator_enable, or usb_post_init), the function
returns the error without rearming the reset control. This leaks
the reference and leaves the reset control in a triggered state,
causing future reset_control_reset() calls to incorrectly return
early as if already reset.
Add an error path that calls reset_control_rearm() to balance
the reference before returning the error.
Cc: stable@vger.kernel.org
Fixes: 5b0ba0caaf3a ("usb: dwc3: meson-g12a: refactor usb init")
Signed-off-by: WenTao Liang <vulab@iscas.ac.cn>
---
drivers/usb/dwc3/dwc3-meson-g12a.c | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/drivers/usb/dwc3/dwc3-meson-g12a.c b/drivers/usb/dwc3/dwc3-meson-g12a.c
index 55e144ba8cfc..4d611c08e8a4 100644
--- a/drivers/usb/dwc3/dwc3-meson-g12a.c
+++ b/drivers/usb/dwc3/dwc3-meson-g12a.c
@@ -907,35 +907,39 @@ static int __maybe_unused dwc3_meson_g12a_resume(struct device *dev)
ret = priv->drvdata->usb_init(priv);
if (ret)
- return ret;
+ goto err_rearm;
/* Init PHYs */
for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = phy_init(priv->phys[i]);
if (ret)
- return ret;
+ goto err_rearm;
}
/* Set PHY Power */
for (i = 0 ; i < PHY_COUNT ; ++i) {
ret = phy_power_on(priv->phys[i]);
if (ret)
- return ret;
+ goto err_rearm;
}
if (priv->vbus && priv->otg_phy_mode == PHY_MODE_USB_HOST) {
ret = regulator_enable(priv->vbus);
if (ret)
- return ret;
+ goto err_rearm;
}
if (priv->drvdata->usb_post_init) {
ret = priv->drvdata->usb_post_init(priv);
if (ret)
- return ret;
+ goto err_rearm;
}
return 0;
+
+err_rearm:
+ reset_control_rearm(priv->reset);
+ return ret;
}
static const struct dev_pm_ops dwc3_meson_g12a_dev_pm_ops = {
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* [PATCH] arm64: static_call: include asm/insns.h
From: Arnd Bergmann @ 2026-06-11 13:21 UTC (permalink / raw)
To: Peter Zijlstra, Josh Poimboeuf, Jason Baron, Alice Ryhl,
Catalin Marinas, Will Deacon, Ard Biesheuvel
Cc: Arnd Bergmann, Steven Rostedt, linux-arm-kernel, linux-kernel
From: Arnd Bergmann <arnd@arndb.de>
I came a cross a missing declaration in a randconfig build:
arch/arm64/kernel/static_call.c:16:5: error: call to undeclared function 'aarch64_insn_adrp_get_offset'; ISO C99 and later do not support implicit function declarations [-Wimplicit-function-declaration]
16 | aarch64_insn_adrp_get_offset(le32_to_cpup(tramp + 4)) +
| ^
Include the header that contains this definition explicitly,
rather than relying on it to come indirectly through another
header.
Fixes: 54ac9ff8f119 ("arm64: Use static call trampolines when kCFI is enabled")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
arch/arm64/kernel/static_call.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/kernel/static_call.c b/arch/arm64/kernel/static_call.c
index 8b3a19e10871..c126edced022 100644
--- a/arch/arm64/kernel/static_call.c
+++ b/arch/arm64/kernel/static_call.c
@@ -2,6 +2,7 @@
#include <linux/static_call.h>
#include <linux/memory.h>
#include <asm/text-patching.h>
+#include <asm/insn.h>
void arch_static_call_transform(void *site, void *tramp, void *func, bool tail)
{
--
2.39.5
^ permalink raw reply related
* [PATCH] media: cec: stm32: prevent out-of-bounds write on RX overflow
From: Weigang He @ 2026-06-11 13:22 UTC (permalink / raw)
To: Hans Verkuil, Mauro Carvalho Chehab, Maxime Coquelin,
Alexandre Torgue
Cc: linux-media, linux-stm32, linux-arm-kernel, linux-kernel, stable,
Weigang He
stm32_rx_done() appends each received CEC byte to rx_msg.msg[] using
rx_msg.len as the write index, incrementing it on every RXBR
(receive-byte-ready) interrupt without checking it against the buffer
size:
cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
rx_msg.msg[] is a fixed CEC_MAX_MSG_SIZE (16) byte array in struct
cec_msg, and rx_msg.len is only reset on RXACKE/RXOVR or after a
completed message (RXEND). The number of bytes received before RXEND is
decided by the remote CEC device (it sets EOM), not by the driver. A
peer that keeps sending bytes without ending the message drives RXBR
repeatedly, pushing rx_msg.len past 16 and writing peer-controlled bytes
out of bounds into the surrounding memory. This is reachable in normal
operation once the driver has probed and receiving is enabled, from the
IRQ thread, without any local privilege.
The length check in the CEC core runs on the consumer side, after the
byte has been stored, so it does not prevent the overflow. Bound the
index in the driver before the store, as the other platform CEC drivers
already do (e.g. tegra_cec), dropping the excess bytes of an overlong
frame.
Found by static analysis tool CodeQL.
Fixes: d69ae57453c8 ("[media] cec: add STM32 cec driver")
Cc: stable@vger.kernel.org
Signed-off-by: Weigang He <geoffreyhe2@gmail.com>
---
drivers/media/cec/platform/stm32/stm32-cec.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c
index 1ec0cece0a5b7..8c2fc232202de 100644
--- a/drivers/media/cec/platform/stm32/stm32-cec.c
+++ b/drivers/media/cec/platform/stm32/stm32-cec.c
@@ -132,7 +132,8 @@ static void stm32_rx_done(struct stm32_cec *cec, u32 status)
u32 val;
regmap_read(cec->regmap, CEC_RXDR, &val);
- cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
+ if (cec->rx_msg.len < CEC_MAX_MSG_SIZE)
+ cec->rx_msg.msg[cec->rx_msg.len++] = val & 0xFF;
}
if (cec->irq_status & RXEND) {
base-commit: 9716c086c8e8b141d35aa61f2e96a2e83de212a7
--
2.43.0
^ permalink raw reply related
* Re: [GIT PULL] ARM: mvebu: dt64 for v7.2 (#1)
From: Arnd Bergmann @ 2026-06-11 13:30 UTC (permalink / raw)
To: Aleksander Jan Bajkowski, Gregory Clement, arm, soc
Cc: Andrew Lunn, Sebastian Hesselbarth, linux-arm-kernel
In-Reply-To: <956403e3-d47f-498c-9f62-79d39c1cf5db@app.fastmail.com>
On Tue, Jun 9, 2026, at 21:29, Arnd Bergmann wrote:
> On Tue, Jun 9, 2026, at 19:35, Aleksander Jan Bajkowski wrote:
>> On 09/06/2026 18:11, Arnd Bergmann wrote:
>>> I'm a bit surprised by this oneline change. Since you successfully tested
>>> this, I assume the change is correct, but I have two questions that
>>> I would like to have an answer for before I pull it.
>> By the way, the upstream safexcel driver works correctly only on
>> coherent
>> platforms. On non-coherent platforms (MediaTek), the SHA-384 and SHA-512
>> selftests fail. Since the selftests pass on Armada's SoC, I assume I'm
>> right.
>
> It's not necessarily proof that this is correct, but it is quite likely.
>
> After checking the datasheet some more and finding that this should
> indeed be coherent everywhere, I remembered that even the old
> 32-bit Armada 370 had a coherency manager. At the time, we used a hack
> in arch/arm/mach-mvebu/coherency.c to mark all device nodes as coherent,
> since the original DTB did not contain the correct annotations.
>
> I suspect that the Armada 37xx started out with a copy of the
> old DT files and also never had the annotation, but then never
> had the same hack because arch/arm64 does not have platform
> specific code.
After investigating a little more, I think the correct fix here
will be to mark all DMA masters in this SoC as dma-coherent.
I thought there was a way to do this for an entire system,
but I could not find that, so this likely has to be done
for each DMA master separately.
Not sure who still has the hardware and has time to
test this properly. Given that the incorrect DT has
existed for over 10 years now, I assume this is not
urgent and I will skip the pull request for 7.2.
Arnd
^ permalink raw reply
* Re: [PATCH v3] arm64: errata: Workaround NVIDIA Olympus device store/load ordering erratum
From: Will Deacon @ 2026-06-11 13:34 UTC (permalink / raw)
To: Shanker Donthineni
Cc: Catalin Marinas, Vladimir Murzin, Jason Gunthorpe,
linux-arm-kernel, Mark Rutland, linux-kernel, linux-doc,
Vikram Sethi, Jason Sequeira
In-Reply-To: <20260610164822.4157248-1-sdonthineni@nvidia.com>
On Wed, Jun 10, 2026 at 11:48:22AM -0500, Shanker Donthineni wrote:
> On systems with NVIDIA Olympus cores, a Device-nGnR* load can be
> observed by a peripheral before an older, non-overlapping Device-nGnR*
> store to the same peripheral. This breaks the program-order guarantee
> that software expects for Device-nGnR* accesses and can leave a
> peripheral in an incorrect state, as a load is observed before an
> earlier store takes effect.
>
> The erratum can occur only when all of the following apply:
>
> - A PE executes a Device-nGnR* store followed by a younger
> Device-nGnR* load.
> - The store is not a store-release.
> - The accesses target the same peripheral and do not overlap in bytes.
> - There is at most one intervening Device-nGnR* store in program
> order, and there are no intervening Device-nGnR* loads.
> - There is no DSB, and no DMB that orders loads, between the store and
> the load.
> - Specific micro-architectural and timing conditions occur.
>
> Promote the raw MMIO store helpers (__raw_writeb/w/l/q) from plain str*
> to stlr* (Store-Release), which removes the "store is not a
> store-release" condition for every device write the kernel issues.
> Because writel() and writel_relaxed() are both built on __raw_writel()
> in asm-generic/io.h, patching the raw variants covers both the
> non-relaxed and relaxed APIs without touching the higher layers. Note
> that writel()'s own barrier sits before the store, so it does not order
> the store against a subsequent readl(); the store-release promotion is
> what provides that ordering.
>
> Like ARM64_ERRATUM_832075 on the load side, the change is gated on a new
> ARM64_WORKAROUND_DEVICE_STORE_RELEASE capability and only activated on
> parts that match MIDR_NVIDIA_OLYMPUS, so unaffected CPUs continue to use
> the plain str* sequence.
>
> Note: stlr* only supports base-register addressing, so affected CPUs use
> a base-register stlr* path. Unaffected CPUs keep the original
> offset-addressed str* sequence introduced by commit d044d6ba6f02
> ("arm64: io: permit offset addressing").
>
> The __const_memcpy_toio_aligned32() and __const_memcpy_toio_aligned64()
> helpers are left unchanged. These helpers are intended for
> write-combining mappings, which are Normal-NC on arm64. Replacing their
> contiguous str* groups would defeat the write-combining behavior used to
> improve store performance.
>
> Co-developed-by: Vikram Sethi <vsethi@nvidia.com>
> Signed-off-by: Vikram Sethi <vsethi@nvidia.com>
> Signed-off-by: Shanker Donthineni <sdonthineni@nvidia.com>
> Reviewed-by: Catalin Marinas <catalin.marinas@arm.com>
> ---
> Changes since v2:
> - Reworked the raw MMIO write helpers so unaffected CPUs keep the
> existing offset-addressed STR sequence, while affected CPUs use the
> base-register STLR path.
> - Updated the commit message to match the code changes.
> - Rebased on top of the arm64 for-next/errata branch:
> https://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux.git/log/?h=for-next/errata
>
> Changes since v1:
> - Updated the commit message based on feedback from Vladimir Murzin.
>
> Documentation/arch/arm64/silicon-errata.rst | 2 ++
> arch/arm64/Kconfig | 23 ++++++++++++++++
> arch/arm64/include/asm/io.h | 30 +++++++++++++++++++++
> arch/arm64/kernel/cpu_errata.c | 8 ++++++
> arch/arm64/tools/cpucaps | 1 +
> 5 files changed, 64 insertions(+)
>
> diff --git a/Documentation/arch/arm64/silicon-errata.rst b/Documentation/arch/arm64/silicon-errata.rst
> index ad09bbb10da80..fc45125dc2f80 100644
> --- a/Documentation/arch/arm64/silicon-errata.rst
> +++ b/Documentation/arch/arm64/silicon-errata.rst
> @@ -298,6 +298,8 @@ stable kernels.
> +----------------+-----------------+-----------------+-----------------------------+
> | NVIDIA | Carmel Core | N/A | NVIDIA_CARMEL_CNP_ERRATUM |
> +----------------+-----------------+-----------------+-----------------------------+
> +| NVIDIA | Olympus core | T410-OLY-1027 | NVIDIA_OLYMPUS_1027_ERRATUM |
> ++----------------+-----------------+-----------------+-----------------------------+
> | NVIDIA | Olympus core | T410-OLY-1029 | ARM64_ERRATUM_4118414 |
> +----------------+-----------------+-----------------+-----------------------------+
> | NVIDIA | T241 GICv3/4.x | T241-FABRIC-4 | N/A |
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index c65cef81be86a..d633eb70de1ac 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -564,6 +564,29 @@ config ARM64_ERRATUM_832075
>
> If unsure, say Y.
>
> +config NVIDIA_OLYMPUS_1027_ERRATUM
> + bool "NVIDIA Olympus: device store/load ordering erratum"
> + default y
> + help
> + This option adds an alternative code sequence to work around an
> + NVIDIA Olympus core erratum where a Device-nGnR* store can be
> + observed by a peripheral after a younger Device-nGnR* load to the
> + same peripheral. This breaks the program order that drivers rely
> + on for MMIO and can leave a device in an incorrect state.
> +
> + The workaround promotes the raw MMIO store helpers
> + (__raw_writeb/w/l/q) to Store-Release (STLR), which restores the
> + required ordering. Because writel() and writel_relaxed() are built
> + on __raw_writel(), both are covered without changes to the higher
> + layers.
> +
> + The fix is applied through the alternatives framework, so enabling
> + this option does not by itself activate the workaround: it is
> + patched in only when an affected CPU is detected, and is a no-op on
> + unaffected CPUs.
> +
> + If unsure, say Y.
> +
> config ARM64_ERRATUM_834220
> bool "Cortex-A57: 834220: Stage 2 translation fault might be incorrectly reported in presence of a Stage 1 fault (rare)"
> depends on KVM
> diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
> index 8cbd1e96fd50b..801223e754c90 100644
> --- a/arch/arm64/include/asm/io.h
> +++ b/arch/arm64/include/asm/io.h
> @@ -22,10 +22,22 @@
> /*
> * Generic IO read/write. These perform native-endian accesses.
> */
> +static __always_inline bool arm64_needs_device_store_release(void)
> +{
> + return alternative_has_cap_unlikely(
> + ARM64_WORKAROUND_DEVICE_STORE_RELEASE);
> +}
> +
> #define __raw_writeb __raw_writeb
> static __always_inline void __raw_writeb(u8 val, volatile void __iomem *addr)
> {
> volatile u8 __iomem *ptr = addr;
> +
> + if (arm64_needs_device_store_release()) {
> + asm volatile("stlrb %w0, [%1]" : : "rZ" (val), "r" (addr));
> + return;
> + }
> +
> asm volatile("strb %w0, %1" : : "rZ" (val), "Qo" (*ptr));
> }
Use an 'else' clause instead of the early return? (similarly for the other
changes).
I still reckon you should do something with the memcpy-to-io routines.
A simple option could be to make dgh() a dmb on parts with the erratum?
That at least moves the barrier out of the loop.
Will
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox