* RE: [PATCH v2 07/15] arm64: hyperv: Add support for mshv_vtl_return_call
From: Michael Kelley @ 2026-04-27 5:38 UTC (permalink / raw)
To: Naman Jain, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Catalin Marinas, Will Deacon,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, H . Peter Anvin, Arnd Bergmann, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Michael Kelley
Cc: Marc Zyngier, Timothy Hayes, Lorenzo Pieralisi, Sascha Bischoff,
mrigendrachaubey, linux-hyperv@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-riscv@lists.infradead.org, vdso@mailbox.org,
ssengar@linux.microsoft.com
In-Reply-To: <20260423124206.2410879-8-namjain@linux.microsoft.com>
From: Naman Jain <namjain@linux.microsoft.com> Sent: Thursday, April 23, 2026 5:42 AM
>
> Add the arm64 variant of mshv_vtl_return_call() to support the MSHV_VTL
> driver on arm64. This function enables the transition between Virtual
> Trust Levels (VTLs) in MSHV_VTL when the kernel acts as a paravisor.
>
> Signed-off-by: Roman Kisel <romank@linux.microsoft.com>
> Reviewed-by: Roman Kisel <vdso@mailbox.org>
> Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
> ---
> arch/arm64/hyperv/Makefile | 1 +
> arch/arm64/hyperv/hv_vtl.c | 158 ++++++++++++++++++++++++++++++
> arch/arm64/include/asm/mshyperv.h | 13 +++
> arch/x86/include/asm/mshyperv.h | 2 -
> drivers/hv/mshv_vtl.h | 3 +
> include/asm-generic/mshyperv.h | 2 +
> 6 files changed, 177 insertions(+), 2 deletions(-)
> create mode 100644 arch/arm64/hyperv/hv_vtl.c
>
[snip]
> diff --git a/arch/arm64/include/asm/mshyperv.h b/arch/arm64/include/asm/mshyperv.h
> index 585b23a26f1b..9eb0e5999f29 100644
> --- a/arch/arm64/include/asm/mshyperv.h
> +++ b/arch/arm64/include/asm/mshyperv.h
> @@ -60,6 +60,18 @@ static inline u64 hv_get_non_nested_msr(unsigned int reg)
> ARM_SMCCC_SMC_64, \
> ARM_SMCCC_OWNER_VENDOR_HYP, \
> HV_SMCCC_FUNC_NUMBER)
> +
> +struct mshv_vtl_cpu_context {
> +/*
> + * x18 is managed by the hypervisor. It won't be reloaded from this array.
> + * It is included here for convenience in array indexing.
> + * 'rsvd' field serves as alignment padding so q[] starts at offset 32*8=256.
> + */
> + __u64 x[31];
> + __u64 rsvd;
> + __uint128_t q[32];
> +};
> +
> #ifdef CONFIG_HYPERV_VTL_MODE
> /*
> * Get/Set the register. If the function returns `1`, that must be done via
> @@ -69,6 +81,7 @@ static inline int hv_vtl_get_set_reg(struct hv_register_assoc *regs,
> bool set, b
> {
> return 1;
> }
> +
This appears to be a spurious blank line being added since there
are no other changes in the vicinity.
> #endif
>
> #include <asm-generic/mshyperv.h>
> diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
> index 08278547b84c..b4d80c9a673a 100644
> --- a/arch/x86/include/asm/mshyperv.h
> +++ b/arch/x86/include/asm/mshyperv.h
> @@ -286,7 +286,6 @@ struct mshv_vtl_cpu_context {
> #ifdef CONFIG_HYPERV_VTL_MODE
> void __init hv_vtl_init_platform(void);
> int __init hv_vtl_early_init(void);
> -void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
> void mshv_vtl_return_call_init(u64 vtl_return_offset);
> void mshv_vtl_return_hypercall(void);
> void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
> @@ -294,7 +293,6 @@ int hv_vtl_get_set_reg(struct hv_register_assoc *regs, bool set,
> bool shared);
> #else
> static inline void __init hv_vtl_init_platform(void) {}
> static inline int __init hv_vtl_early_init(void) { return 0; }
> -static inline void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
> static inline void mshv_vtl_return_call_init(u64 vtl_return_offset) {}
> static inline void mshv_vtl_return_hypercall(void) {}
> static inline void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
> diff --git a/drivers/hv/mshv_vtl.h b/drivers/hv/mshv_vtl.h
> index a6eea52f7aa2..103f07371f3f 100644
> --- a/drivers/hv/mshv_vtl.h
> +++ b/drivers/hv/mshv_vtl.h
> @@ -22,4 +22,7 @@ struct mshv_vtl_run {
> char vtl_ret_actions[MSHV_MAX_RUN_MSG_SIZE];
> };
>
> +static_assert(sizeof(struct mshv_vtl_cpu_context) <= 1024,
> + "struct mshv_vtl_cpu_context exceeds reserved space in struct
> mshv_vtl_run");
> +
> #endif /* _MSHV_VTL_H */
> diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
> index db183c8cfb95..8cdf2a9fbdfb 100644
> --- a/include/asm-generic/mshyperv.h
> +++ b/include/asm-generic/mshyperv.h
> @@ -396,8 +396,10 @@ static inline int hv_deposit_memory(u64 partition_id, u64 status)
>
> #if IS_ENABLED(CONFIG_HYPERV_VTL_MODE)
> u8 __init get_vtl(void);
> +void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
> #else
> static inline u8 get_vtl(void) { return 0; }
> +static inline void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
Is this stub needed? Maybe I missed something, but it looks to me like none
of the code that calls this gets built unless CONFIG_HYPERV_VTL_MODE is set.
See further comments about stubs in Patch 8 of this series.
> #endif
>
> #endif
> --
> 2.43.0
>
^ permalink raw reply
* RE: [PATCH v2 08/15] Drivers: hv: Move hv_call_(get|set)_vp_registers() declarations
From: Michael Kelley @ 2026-04-27 5:39 UTC (permalink / raw)
To: Naman Jain, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Catalin Marinas, Will Deacon,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, H . Peter Anvin, Arnd Bergmann, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Michael Kelley
Cc: Marc Zyngier, Timothy Hayes, Lorenzo Pieralisi, Sascha Bischoff,
mrigendrachaubey, linux-hyperv@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-riscv@lists.infradead.org, vdso@mailbox.org,
ssengar@linux.microsoft.com
In-Reply-To: <20260423124206.2410879-9-namjain@linux.microsoft.com>
From: Naman Jain <namjain@linux.microsoft.com> Sent: Thursday, April 23, 2026 5:42 AM
>
> Move hv_call_get_vp_registers() and hv_call_set_vp_registers()
> declarations from drivers/hv/mshv.h to include/asm-generic/mshyperv.h.
>
> These functions are defined in mshv_common.c and are going to be called
> from both drivers/hv/ and arch/x86/hyperv/hv_vtl.c. The latter never
> included mshv.h, relying on implicit declaration visibility. Moving the
> declarations to the arch-generic Hyper-V header makes them properly
> visible to all architecture-specific callers.
>
> Provide static inline stubs returning -EOPNOTSUPP when neither
> CONFIG_MSHV_ROOT nor CONFIG_MSHV_VTL is enabled.
Looking at the drivers/hv/Kconfig, it's possible to build with
CONFIG_HYPERV_VTL_MODE=y, but not CONFIG_MSHV_VTL. In such a
case, mshv_common.o doesn't get built, which is why the stubs are
needed. Is such a configuration desirable for some scenarios?
I wonder if having CONFIG_HYPERV_VTL_MODE force the building of
mshv_common.o would be a better approach. Then the stubs wouldn't
be needed. The "ifneq" statement in drivers/hv/Makefile could use
CONFIG_HYPERV_VTL_MODE instead of CONFIG_MSHV_VTL, and
everything would be good since CONFIG_MSHV_VTL depends on
CONFIG_HYPERV_VTL_MODE.
>
> Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
> ---
> drivers/hv/mshv.h | 8 --------
> include/asm-generic/mshyperv.h | 26 ++++++++++++++++++++++++++
> 2 files changed, 26 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/hv/mshv.h b/drivers/hv/mshv.h
> index d4813df92b9c..0fcb7f9ba6a9 100644
> --- a/drivers/hv/mshv.h
> +++ b/drivers/hv/mshv.h
> @@ -14,14 +14,6 @@
> memchr_inv(&((STRUCT).MEMBER), \
> 0, sizeof_field(typeof(STRUCT), MEMBER))
>
> -int hv_call_get_vp_registers(u32 vp_index, u64 partition_id, u16 count,
> - union hv_input_vtl input_vtl,
> - struct hv_register_assoc *registers);
> -
> -int hv_call_set_vp_registers(u32 vp_index, u64 partition_id, u16 count,
> - union hv_input_vtl input_vtl,
> - struct hv_register_assoc *registers);
> -
> int hv_call_get_partition_property(u64 partition_id, u64 property_code,
> u64 *property_value);
>
> diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
> index 8cdf2a9fbdfb..ef0b9466808c 100644
> --- a/include/asm-generic/mshyperv.h
> +++ b/include/asm-generic/mshyperv.h
> @@ -394,6 +394,32 @@ static inline int hv_deposit_memory(u64 partition_id, u64
> status)
> return hv_deposit_memory_node(NUMA_NO_NODE, partition_id, status);
> }
>
> +#if IS_ENABLED(CONFIG_MSHV_ROOT) || IS_ENABLED(CONFIG_MSHV_VTL)
> +int hv_call_get_vp_registers(u32 vp_index, u64 partition_id, u16 count,
> + union hv_input_vtl input_vtl,
> + struct hv_register_assoc *registers);
> +
> +int hv_call_set_vp_registers(u32 vp_index, u64 partition_id, u16 count,
> + union hv_input_vtl input_vtl,
> + struct hv_register_assoc *registers);
> +#else
> +static inline int hv_call_get_vp_registers(u32 vp_index, u64 partition_id,
> + u16 count,
> + union hv_input_vtl input_vtl,
> + struct hv_register_assoc *registers)
> +{
> + return -EOPNOTSUPP;
> +}
> +
> +static inline int hv_call_set_vp_registers(u32 vp_index, u64 partition_id,
> + u16 count,
> + union hv_input_vtl input_vtl,
> + struct hv_register_assoc *registers)
> +{
> + return -EOPNOTSUPP;
> +}
> +#endif /* CONFIG_MSHV_ROOT || CONFIG_MSHV_VTL */
> +
> #if IS_ENABLED(CONFIG_HYPERV_VTL_MODE)
> u8 __init get_vtl(void);
> void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
> --
> 2.43.0
>
^ permalink raw reply
* RE: [PATCH v2 09/15] Drivers: hv: mshv_vtl: Move hv_vtl_configure_reg_page() to x86
From: Michael Kelley @ 2026-04-27 5:40 UTC (permalink / raw)
To: Naman Jain, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Catalin Marinas, Will Deacon,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, H . Peter Anvin, Arnd Bergmann, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Michael Kelley
Cc: Marc Zyngier, Timothy Hayes, Lorenzo Pieralisi, Sascha Bischoff,
mrigendrachaubey, linux-hyperv@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-riscv@lists.infradead.org, vdso@mailbox.org,
ssengar@linux.microsoft.com
In-Reply-To: <20260423124206.2410879-10-namjain@linux.microsoft.com>
From: Naman Jain <namjain@linux.microsoft.com> Sent: Thursday, April 23, 2026 5:42 AM
>
> Move hv_vtl_configure_reg_page() from drivers/hv/mshv_vtl_main.c to
> arch/x86/hyperv/hv_vtl.c. The register page overlay is an x86-specific
> feature that uses HV_X64_REGISTER_REG_PAGE, so its configuration belongs
> in architecture-specific code.
>
> Move struct mshv_vtl_per_cpu and union hv_synic_overlay_page_msr to
> include/asm-generic/mshyperv.h so they are visible to both arch and
> driver code.
>
> Change the return type from void to bool so the caller can determine
> whether the register page was successfully configured and set
> mshv_has_reg_page accordingly.
>
> Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
> ---
> arch/x86/hyperv/hv_vtl.c | 32 ++++++++++++++++++++++
> drivers/hv/mshv_vtl_main.c | 49 +++-------------------------------
> include/asm-generic/mshyperv.h | 17 ++++++++++++
> 3 files changed, 53 insertions(+), 45 deletions(-)
>
> diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c
> index 09d81f9b853c..f3ffb6a7cb2d 100644
> --- a/arch/x86/hyperv/hv_vtl.c
> +++ b/arch/x86/hyperv/hv_vtl.c
> @@ -20,6 +20,7 @@
> #include <uapi/asm/mtrr.h>
> #include <asm/debugreg.h>
> #include <linux/export.h>
> +#include <linux/hyperv.h>
> #include <../kernel/smpboot.h>
> #include "../../kernel/fpu/legacy.h"
>
> @@ -259,6 +260,37 @@ int __init hv_vtl_early_init(void)
> return 0;
> }
>
> +static const union hv_input_vtl input_vtl_zero;
> +
> +bool hv_vtl_configure_reg_page(struct mshv_vtl_per_cpu *per_cpu)
> +{
> + struct hv_register_assoc reg_assoc = {};
> + union hv_synic_overlay_page_msr overlay = {};
> + struct page *reg_page;
> +
> + reg_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_RETRY_MAYFAIL);
> + if (!reg_page) {
> + WARN(1, "failed to allocate register page\n");
> + return false;
> + }
> +
> + overlay.enabled = 1;
> + overlay.pfn = page_to_hvpfn(reg_page);
> + reg_assoc.name = HV_X64_REGISTER_REG_PAGE;
> + reg_assoc.value.reg64 = overlay.as_uint64;
> +
> + if (hv_call_set_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
> + 1, input_vtl_zero, ®_assoc)) {
> + WARN(1, "failed to setup register page\n");
> + __free_page(reg_page);
> + return false;
> + }
> +
> + per_cpu->reg_page = reg_page;
> + return true;
> +}
> +EXPORT_SYMBOL_GPL(hv_vtl_configure_reg_page);
> +
> DEFINE_STATIC_CALL_NULL(__mshv_vtl_return_hypercall, void (*)(void));
>
> void mshv_vtl_return_call_init(u64 vtl_return_offset)
> diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c
> index 91517b45d526..c79d24317b8e 100644
> --- a/drivers/hv/mshv_vtl_main.c
> +++ b/drivers/hv/mshv_vtl_main.c
> @@ -78,21 +78,6 @@ struct mshv_vtl {
> u64 id;
> };
>
> -struct mshv_vtl_per_cpu {
> - struct mshv_vtl_run *run;
> - struct page *reg_page;
> -};
> -
> -/* SYNIC_OVERLAY_PAGE_MSR - internal, identical to hv_synic_simp */
> -union hv_synic_overlay_page_msr {
> - u64 as_uint64;
> - struct {
> - u64 enabled: 1;
> - u64 reserved: 11;
> - u64 pfn: 52;
> - } __packed;
> -};
> -
> static struct mutex mshv_vtl_poll_file_lock;
> static union hv_register_vsm_page_offsets mshv_vsm_page_offsets;
> static union hv_register_vsm_capabilities mshv_vsm_capabilities;
> @@ -201,34 +186,6 @@ static struct page *mshv_vtl_cpu_reg_page(int cpu)
> return *per_cpu_ptr(&mshv_vtl_per_cpu.reg_page, cpu);
> }
>
> -static void mshv_vtl_configure_reg_page(struct mshv_vtl_per_cpu *per_cpu)
> -{
> - struct hv_register_assoc reg_assoc = {};
> - union hv_synic_overlay_page_msr overlay = {};
> - struct page *reg_page;
> -
> - reg_page = alloc_page(GFP_KERNEL | __GFP_ZERO | __GFP_RETRY_MAYFAIL);
> - if (!reg_page) {
> - WARN(1, "failed to allocate register page\n");
> - return;
> - }
> -
> - overlay.enabled = 1;
> - overlay.pfn = page_to_hvpfn(reg_page);
> - reg_assoc.name = HV_X64_REGISTER_REG_PAGE;
> - reg_assoc.value.reg64 = overlay.as_uint64;
> -
> - if (hv_call_set_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
> - 1, input_vtl_zero, ®_assoc)) {
> - WARN(1, "failed to setup register page\n");
> - __free_page(reg_page);
> - return;
> - }
> -
> - per_cpu->reg_page = reg_page;
> - mshv_has_reg_page = true;
> -}
> -
> static void mshv_vtl_synic_enable_regs(unsigned int cpu)
> {
> union hv_synic_sint sint;
> @@ -329,8 +286,10 @@ static int mshv_vtl_alloc_context(unsigned int cpu)
> if (!per_cpu->run)
> return -ENOMEM;
>
> - if (mshv_vsm_capabilities.intercept_page_available)
> - mshv_vtl_configure_reg_page(per_cpu);
> + if (mshv_vsm_capabilities.intercept_page_available) {
> + if (hv_vtl_configure_reg_page(per_cpu))
> + mshv_has_reg_page = true;
> + }
>
> mshv_vtl_synic_enable_regs(cpu);
>
> diff --git a/include/asm-generic/mshyperv.h b/include/asm-generic/mshyperv.h
> index ef0b9466808c..9e86178c182e 100644
> --- a/include/asm-generic/mshyperv.h
> +++ b/include/asm-generic/mshyperv.h
> @@ -420,12 +420,29 @@ static inline int hv_call_set_vp_registers(u32 vp_index, u64
> partition_id,
> }
> #endif /* CONFIG_MSHV_ROOT || CONFIG_MSHV_VTL */
>
> +struct mshv_vtl_per_cpu {
> + struct mshv_vtl_run *run;
> + struct page *reg_page;
> +};
> +
> #if IS_ENABLED(CONFIG_HYPERV_VTL_MODE)
> +/* SYNIC_OVERLAY_PAGE_MSR - internal, identical to hv_synic_simp */
This comment pre-dates your patch, but I don't understand the point
it is trying to make. The comment is factually true, but I don't know
why calling that out is relevant. The REG_PAGE MSR seems to be
conceptually separate and distinct from the SIMP MSR, so the fact
that the layouts are the same is just a coincidence. Or is there some
relationship between the two MSRs that I'm not aware of, and the
comment is trying (and failing?) to point out?
> +union hv_synic_overlay_page_msr {
> + u64 as_uint64;
> + struct {
> + u64 enabled: 1;
> + u64 reserved: 11;
> + u64 pfn: 52;
> + } __packed;
> +};
> +
> u8 __init get_vtl(void);
> void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
> +bool hv_vtl_configure_reg_page(struct mshv_vtl_per_cpu *per_cpu);
> #else
> static inline u8 get_vtl(void) { return 0; }
> static inline void mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
> +static inline bool hv_vtl_configure_reg_page(struct mshv_vtl_per_cpu *per_cpu) { return false; }
As with Patch 8, if CONFIG_HYPERV_VTL_MODE caused mshv_common.o
to be built, this stub wouldn't be needed.
> #endif
>
> #endif
> --
> 2.43.0
>
^ permalink raw reply
* RE: [PATCH v2 12/15] mshv_vtl: Move VSM code page offset logic to x86 files
From: Michael Kelley @ 2026-04-27 5:40 UTC (permalink / raw)
To: Naman Jain, K . Y . Srinivasan, Haiyang Zhang, Wei Liu,
Dexuan Cui, Long Li, Catalin Marinas, Will Deacon,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen,
x86@kernel.org, H . Peter Anvin, Arnd Bergmann, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Michael Kelley
Cc: Marc Zyngier, Timothy Hayes, Lorenzo Pieralisi, Sascha Bischoff,
mrigendrachaubey, linux-hyperv@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, linux-arch@vger.kernel.org,
linux-riscv@lists.infradead.org, vdso@mailbox.org,
ssengar@linux.microsoft.com
In-Reply-To: <20260423124206.2410879-13-namjain@linux.microsoft.com>
From: Naman Jain <namjain@linux.microsoft.com> Sent: Thursday, April 23, 2026 5:42 AM
>
> The VSM code page offset register (HV_REGISTER_VSM_CODE_PAGE_OFFSETS)
> is x86 specific, its value configures the static call used to return
> to VTL0 via the hypercall page. Move the register read from the common
> mshv_vtl_get_vsm_regs() into the x86 mshv_vtl_return_call_init(),
> which is the sole consumer of the offset.
>
> Change mshv_vtl_return_call_init() from taking a u64 parameter
> to taking no arguments, and rename mshv_vtl_get_vsm_regs() to
> mshv_vtl_get_vsm_cap_reg() since it now only fetches
> HV_REGISTER_VSM_CAPABILITIES.
>
> No functional change on x86. This prepares the common driver code for
> ARM64 where VSM code page offsets do not apply.
>
> Signed-off-by: Naman Jain <namjain@linux.microsoft.com>
> ---
> arch/x86/hyperv/hv_vtl.c | 19 +++++++++++++++++--
> arch/x86/include/asm/mshyperv.h | 4 ++--
> drivers/hv/mshv_vtl_main.c | 24 +++++++++++++-----------
> 3 files changed, 32 insertions(+), 15 deletions(-)
>
> diff --git a/arch/x86/hyperv/hv_vtl.c b/arch/x86/hyperv/hv_vtl.c
> index f3ffb6a7cb2d..7c10b34cf8a4 100644
> --- a/arch/x86/hyperv/hv_vtl.c
> +++ b/arch/x86/hyperv/hv_vtl.c
> @@ -293,10 +293,25 @@ EXPORT_SYMBOL_GPL(hv_vtl_configure_reg_page);
>
> DEFINE_STATIC_CALL_NULL(__mshv_vtl_return_hypercall, void (*)(void));
>
> -void mshv_vtl_return_call_init(u64 vtl_return_offset)
> +int mshv_vtl_return_call_init(void)
> {
> + struct hv_register_assoc vsm_pg_offset_reg;
> + union hv_register_vsm_page_offsets offsets;
> + int ret;
> +
> + vsm_pg_offset_reg.name = HV_REGISTER_VSM_CODE_PAGE_OFFSETS;
> +
> + ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
> + 1, input_vtl_zero, &vsm_pg_offset_reg);
> + if (ret)
> + return ret;
> +
> + offsets.as_uint64 = vsm_pg_offset_reg.value.reg64;
> +
> static_call_update(__mshv_vtl_return_hypercall,
> - (void *)((u8 *)hv_hypercall_pg + vtl_return_offset));
> + (void *)((u8 *)hv_hypercall_pg + offsets.vtl_return_offset));
> +
> + return 0;
> }
> EXPORT_SYMBOL(mshv_vtl_return_call_init);
>
> diff --git a/arch/x86/include/asm/mshyperv.h b/arch/x86/include/asm/mshyperv.h
> index b4d80c9a673a..b48f115c1292 100644
> --- a/arch/x86/include/asm/mshyperv.h
> +++ b/arch/x86/include/asm/mshyperv.h
> @@ -286,14 +286,14 @@ struct mshv_vtl_cpu_context {
> #ifdef CONFIG_HYPERV_VTL_MODE
> void __init hv_vtl_init_platform(void);
> int __init hv_vtl_early_init(void);
> -void mshv_vtl_return_call_init(u64 vtl_return_offset);
> +int mshv_vtl_return_call_init(void);
> void mshv_vtl_return_hypercall(void);
> void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0);
> int hv_vtl_get_set_reg(struct hv_register_assoc *regs, bool set, bool shared);
> #else
> static inline void __init hv_vtl_init_platform(void) {}
> static inline int __init hv_vtl_early_init(void) { return 0; }
> -static inline void mshv_vtl_return_call_init(u64 vtl_return_offset) {}
> +static inline int mshv_vtl_return_call_init(void) { return 0; }
> static inline void mshv_vtl_return_hypercall(void) {}
> static inline void __mshv_vtl_return_call(struct mshv_vtl_cpu_context *vtl0) {}
> #endif
> diff --git a/drivers/hv/mshv_vtl_main.c b/drivers/hv/mshv_vtl_main.c
> index 4c9ae65ad3e8..be498c9234fd 100644
> --- a/drivers/hv/mshv_vtl_main.c
> +++ b/drivers/hv/mshv_vtl_main.c
> @@ -79,7 +79,6 @@ struct mshv_vtl {
> };
>
> static struct mutex mshv_vtl_poll_file_lock;
> -static union hv_register_vsm_page_offsets mshv_vsm_page_offsets;
> static union hv_register_vsm_capabilities mshv_vsm_capabilities;
>
> static DEFINE_PER_CPU(struct mshv_vtl_poll_file, mshv_vtl_poll_file);
> @@ -203,21 +202,19 @@ static void mshv_vtl_synic_enable_regs(unsigned int cpu)
> /* VTL2 Host VSP SINT is (un)masked when the user mode requests that */
> }
>
> -static int mshv_vtl_get_vsm_regs(void)
> +static int mshv_vtl_get_vsm_cap_reg(void)
> {
> - struct hv_register_assoc registers[2];
> - int ret, count = 2;
> + struct hv_register_assoc vsm_capability_reg;
> + int ret;
>
> - registers[0].name = HV_REGISTER_VSM_CODE_PAGE_OFFSETS;
> - registers[1].name = HV_REGISTER_VSM_CAPABILITIES;
> + vsm_capability_reg.name = HV_REGISTER_VSM_CAPABILITIES;
>
> ret = hv_call_get_vp_registers(HV_VP_INDEX_SELF, HV_PARTITION_ID_SELF,
> - count, input_vtl_zero, registers);
> + 1, input_vtl_zero, &vsm_capability_reg);
> if (ret)
> return ret;
>
> - mshv_vsm_page_offsets.as_uint64 = registers[0].value.reg64;
> - mshv_vsm_capabilities.as_uint64 = registers[1].value.reg64;
> + mshv_vsm_capabilities.as_uint64 = vsm_capability_reg.value.reg64;
>
> return ret;
Nit: This could be just "return 0".
> }
> @@ -1139,13 +1136,18 @@ static int __init mshv_vtl_init(void)
> tasklet_init(&msg_dpc, mshv_vtl_sint_on_msg_dpc, 0);
> init_waitqueue_head(&fd_wait_queue);
>
> - if (mshv_vtl_get_vsm_regs()) {
> + if (mshv_vtl_get_vsm_cap_reg()) {
> dev_emerg(dev, "Unable to get VSM capabilities !!\n");
Why is this failure an emergency message, while the other failures
here in mshv_vtl_init() are just error messages? When there's lack
of consistency, I always wonder if there is a reason ..... :-)
> ret = -ENODEV;
> goto free_dev;
> }
>
> - mshv_vtl_return_call_init(mshv_vsm_page_offsets.vtl_return_offset);
> + ret = mshv_vtl_return_call_init();
> + if (ret) {
> + dev_err(dev, "mshv_vtl_return_call_init failed: %d\n", ret);
> + goto free_dev;
> + }
> +
> ret = hv_vtl_setup_synic();
> if (ret)
> goto free_dev;
> --
> 2.43.0
>
^ permalink raw reply
* [PATCH v4 0/3] Allow ATS to be always on for certain ATS-capable devices
From: Nicolin Chen @ 2026-04-27 5:53 UTC (permalink / raw)
To: jgg, will, robin.murphy, bhelgaas
Cc: joro, praan, baolu.lu, kevin.tian, miko.lenczewski,
linux-arm-kernel, iommu, linux-kernel, linux-pci, dan.j.williams,
jonathan.cameron, vsethi, linux-cxl, nirmoyd
PCI ATS function is controlled by the IOMMU driver calling pci_enable_ats()
and pci_disable_ats() helpers. In general, IOMMU driver only enables ATS
when a translation channel is enabled on a PASID, typically for an SVA use
case. When a device's RID is IOMMU bypassed and its PASIDs are not running
SVA use case, ATS is always disabled.
However, certain PCIe devices require non-PASID ATS on the RID, even if the
RID is IOMMU bypassed. E.g. CXL.cache capability requires ATS to access the
physical memory; some pre-CXL NVIDIA GPUs also require the ATS to be always
on even when their RIDs are IOMMU bypassed.
Provide a helper function to detect CXL.cache capability and scan through a
pre-CXL device ID list.
As the initial use case, call the helper in ARM SMMUv3 driver and adapt the
driver accordingly with a per-device ats_always_on flag.
This is on Github:
https://github.com/nicolinc/iommufd/commits/pci_ats_always_on-v4/
Changelog
v4
* Rebase on v7.1-rc1
* Added Reviewed/Tested/Acked-by lines
* Update commit messages and inline comments
* [pci-quirks] Add range-based scan for NVIDIA GPUs
* [smmu] Add missing arm_smmu_remove_master() in error path
* [pci-ats] Don't init "cap=0"; check pci_read_config_word error
v3
https://lore.kernel.org/all/cover.1772833963.git.nicolinc@nvidia.com/
* Add Reviewed-by from Jonathan
* Update function kdocs of PCI APIs
* Simplify boolean return/variable computations
v2
https://lore.kernel.org/all/cover.1771886695.git.nicolinc@nvidia.com/
* s/non-CXL/pre-CXL
* Rebase on v7.0-rc1
* Update inline comments and commit message
* Add WARN_ON back at !ptr in arm_smmu_clear_cd()
* Add NVIDIA CX10 Family NVlink-C2C to the pre-CXL list
* Do not add boolean parameter to arm_smmu_attach_dev_ste()
v1
https://lore.kernel.org/all/cover.1768624180.git.nicolinc@nvidia.com/
Nicolin Chen (3):
PCI: Allow ATS to be always on for CXL.cache capable devices
PCI: Allow ATS to be always on for pre-CXL devices
iommu/arm-smmu-v3: Allow ATS to be always on
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 +
drivers/pci/pci.h | 9 +++
include/linux/pci-ats.h | 3 +
include/uapi/linux/pci_regs.h | 1 +
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 75 ++++++++++++++++++---
drivers/pci/ats.c | 44 ++++++++++++
drivers/pci/quirks.c | 38 +++++++++++
7 files changed, 163 insertions(+), 8 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH v4 1/3] PCI: Allow ATS to be always on for CXL.cache capable devices
From: Nicolin Chen @ 2026-04-27 5:54 UTC (permalink / raw)
To: jgg, will, robin.murphy, bhelgaas
Cc: joro, praan, baolu.lu, kevin.tian, miko.lenczewski,
linux-arm-kernel, iommu, linux-kernel, linux-pci, dan.j.williams,
jonathan.cameron, vsethi, linux-cxl, nirmoyd
In-Reply-To: <cover.1777269009.git.nicolinc@nvidia.com>
Controlled by the IOMMU driver, ATS is usually enabled "on demand" when a
given PASID on a device is attached to an I/O page table. This is working
even when a device has no translation on its RID (i.e., the RID is IOMMU
bypassed).
However, certain PCIe devices require non-PASID ATS on their RID even when
the RID is IOMMU bypassed. Call this "always on".
For example, CXL spec r4.0 notes in sec 3.2.5.13 Memory Type on CXL.cache:
"To source requests on CXL.cache, devices need to get the Host Physical
Address (HPA) from the Host by means of an ATS request on CXL.io."
In other words, the CXL.cache capability requires ATS; otherwise, it can't
access host physical memory.
Introduce a new pci_ats_always_on() helper for the IOMMU driver to scan a
PCI device and shift ATS policies between "on demand" and "always on".
Add the support for CXL.cache devices first. Pre-CXL devices will be added
in quirks.c file.
Note that pci_ats_always_on() validates against pci_ats_supported(), so we
ensure that untrusted devices (e.g. external ports) will not be always on.
This maintains the existing ATS security policy regarding potential side-
channel attacks via ATS.
Cc: linux-cxl@vger.kernel.org
Suggested-by: Vikram Sethi <vsethi@nvidia.com>
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Tested-by: Nirmoy Das <nirmoyd@nvidia.com>
Acked-by: Nirmoy Das <nirmoyd@nvidia.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
include/linux/pci-ats.h | 3 +++
include/uapi/linux/pci_regs.h | 1 +
drivers/pci/ats.c | 43 +++++++++++++++++++++++++++++++++++
3 files changed, 47 insertions(+)
diff --git a/include/linux/pci-ats.h b/include/linux/pci-ats.h
index 75c6c86cf09dc..d14ba727d38b3 100644
--- a/include/linux/pci-ats.h
+++ b/include/linux/pci-ats.h
@@ -12,6 +12,7 @@ int pci_prepare_ats(struct pci_dev *dev, int ps);
void pci_disable_ats(struct pci_dev *dev);
int pci_ats_queue_depth(struct pci_dev *dev);
int pci_ats_page_aligned(struct pci_dev *dev);
+bool pci_ats_always_on(struct pci_dev *dev);
#else /* CONFIG_PCI_ATS */
static inline bool pci_ats_supported(struct pci_dev *d)
{ return false; }
@@ -24,6 +25,8 @@ static inline int pci_ats_queue_depth(struct pci_dev *d)
{ return -ENODEV; }
static inline int pci_ats_page_aligned(struct pci_dev *dev)
{ return 0; }
+static inline bool pci_ats_always_on(struct pci_dev *dev)
+{ return false; }
#endif /* CONFIG_PCI_ATS */
#ifdef CONFIG_PCI_PRI
diff --git a/include/uapi/linux/pci_regs.h b/include/uapi/linux/pci_regs.h
index 14f634ab9350d..6ac45be1008b8 100644
--- a/include/uapi/linux/pci_regs.h
+++ b/include/uapi/linux/pci_regs.h
@@ -1349,6 +1349,7 @@
/* CXL r4.0, 8.1.3: PCIe DVSEC for CXL Device */
#define PCI_DVSEC_CXL_DEVICE 0
#define PCI_DVSEC_CXL_CAP 0xA
+#define PCI_DVSEC_CXL_CACHE_CAPABLE _BITUL(0)
#define PCI_DVSEC_CXL_MEM_CAPABLE _BITUL(2)
#define PCI_DVSEC_CXL_HDM_COUNT __GENMASK(5, 4)
#define PCI_DVSEC_CXL_CTRL 0xC
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index ec6c8dbdc5e9c..fc871858b65bc 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -205,6 +205,49 @@ int pci_ats_page_aligned(struct pci_dev *pdev)
return 0;
}
+/*
+ * CXL r4.0, sec 3.2.5.13 Memory Type on CXL.cache notes: to source requests on
+ * CXL.cache, devices need to get the Host Physical Address (HPA) from the Host
+ * by means of an ATS request on CXL.io.
+ *
+ * In other words, CXL.cache devices cannot access host physical memory without
+ * ATS.
+ */
+static bool pci_cxl_ats_always_on(struct pci_dev *pdev)
+{
+ int offset;
+ u16 cap;
+
+ offset = pci_find_dvsec_capability(pdev, PCI_VENDOR_ID_CXL,
+ PCI_DVSEC_CXL_DEVICE);
+ if (!offset)
+ return false;
+
+ if (pci_read_config_word(pdev, offset + PCI_DVSEC_CXL_CAP, &cap))
+ return false;
+
+ return cap & PCI_DVSEC_CXL_CACHE_CAPABLE;
+}
+
+/**
+ * pci_ats_always_on - Whether the PCI device requires ATS to be always enabled
+ * @pdev: the PCI device
+ *
+ * Returns true, if the PCI device requires ATS for basic functional operation.
+ */
+bool pci_ats_always_on(struct pci_dev *pdev)
+{
+ if (pci_ats_disabled() || !pci_ats_supported(pdev))
+ return false;
+
+ /* A VF inherits its PF's requirement for ATS function */
+ if (pdev->is_virtfn)
+ pdev = pci_physfn(pdev);
+
+ return pci_cxl_ats_always_on(pdev);
+}
+EXPORT_SYMBOL_GPL(pci_ats_always_on);
+
#ifdef CONFIG_PCI_PRI
void pci_pri_init(struct pci_dev *pdev)
{
--
2.43.0
^ permalink raw reply related
* [PATCH v4 2/3] PCI: Allow ATS to be always on for pre-CXL devices
From: Nicolin Chen @ 2026-04-27 5:54 UTC (permalink / raw)
To: jgg, will, robin.murphy, bhelgaas
Cc: joro, praan, baolu.lu, kevin.tian, miko.lenczewski,
linux-arm-kernel, iommu, linux-kernel, linux-pci, dan.j.williams,
jonathan.cameron, vsethi, linux-cxl, nirmoyd
In-Reply-To: <cover.1777269009.git.nicolinc@nvidia.com>
Some NVIDIA GPU/NIC devices, though they don't implement CXL config space,
have many CXL-like properties. Call this kind "pre-CXL".
Similar to CXL.cache capability, these pre-CXL devices also require the ATS
function even when their RIDs are IOMMU bypassed, i.e. keep ATS "always on"
v.s. "on demand" when a non-zero PASID line gets enabled in SVA use cases.
Introduce pci_dev_specific_ats_always_on() quirk function to scan a list of
IDs for these devices. Then, include it in pci_ats_always_on().
Suggested-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Nirmoy Das <nirmoyd@nvidia.com>
Tested-by: Nirmoy Das <nirmoyd@nvidia.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/pci/pci.h | 9 +++++++++
drivers/pci/ats.c | 3 ++-
drivers/pci/quirks.c | 38 ++++++++++++++++++++++++++++++++++++++
3 files changed, 49 insertions(+), 1 deletion(-)
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4a14f88e543a2..4e0077478cd7a 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -1155,6 +1155,15 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, bool probe)
}
#endif
+#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_PCI_ATS)
+bool pci_dev_specific_ats_always_on(struct pci_dev *dev);
+#else
+static inline bool pci_dev_specific_ats_always_on(struct pci_dev *dev)
+{
+ return false;
+}
+#endif
+
#if defined(CONFIG_PCI_QUIRKS) && defined(CONFIG_ARM64)
int acpi_get_rc_resources(struct device *dev, const char *hid, u16 segment,
struct resource *res);
diff --git a/drivers/pci/ats.c b/drivers/pci/ats.c
index fc871858b65bc..3846447ea322f 100644
--- a/drivers/pci/ats.c
+++ b/drivers/pci/ats.c
@@ -244,7 +244,8 @@ bool pci_ats_always_on(struct pci_dev *pdev)
if (pdev->is_virtfn)
pdev = pci_physfn(pdev);
- return pci_cxl_ats_always_on(pdev);
+ return pci_cxl_ats_always_on(pdev) ||
+ pci_dev_specific_ats_always_on(pdev);
}
EXPORT_SYMBOL_GPL(pci_ats_always_on);
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index caaed1a01dc02..887babba97cc7 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -5715,6 +5715,44 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1457, quirk_intel_e2000_no_ats);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x1459, quirk_intel_e2000_no_ats);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145a, quirk_intel_e2000_no_ats);
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x145c, quirk_intel_e2000_no_ats);
+
+static bool quirk_nvidia_gpu_ats_always_on(struct pci_dev *pdev)
+{
+ switch (pdev->device) {
+ case 0x2e00 ... 0x2e3f: /* GB20B */
+ return true;
+ }
+ return false;
+}
+
+static const struct pci_dev_ats_always_on {
+ u16 vendor;
+ u16 device;
+ bool (*ats_always_on)(struct pci_dev *dev);
+} pci_dev_ats_always_on[] = {
+ /* NVIDIA GPUs */
+ { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, quirk_nvidia_gpu_ats_always_on },
+ /* NVIDIA CX10 Family NVlink-C2C */
+ { PCI_VENDOR_ID_MELLANOX, 0x2101, NULL },
+ { 0 }
+};
+
+/* Some pre-CXL devices require ATS when it is IOMMU-bypassed */
+bool pci_dev_specific_ats_always_on(struct pci_dev *pdev)
+{
+ const struct pci_dev_ats_always_on *i;
+
+ for (i = pci_dev_ats_always_on; i->vendor; i++) {
+ if (i->vendor != pdev->vendor)
+ continue;
+ if (i->ats_always_on && i->ats_always_on(pdev))
+ return true;
+ if (!i->ats_always_on && i->device == pdev->device)
+ return true;
+ }
+
+ return false;
+}
#endif /* CONFIG_PCI_ATS */
/* Freescale PCIe doesn't support MSI in RC mode */
--
2.43.0
^ permalink raw reply related
* [PATCH v4 3/3] iommu/arm-smmu-v3: Allow ATS to be always on
From: Nicolin Chen @ 2026-04-27 5:54 UTC (permalink / raw)
To: jgg, will, robin.murphy, bhelgaas
Cc: joro, praan, baolu.lu, kevin.tian, miko.lenczewski,
linux-arm-kernel, iommu, linux-kernel, linux-pci, dan.j.williams,
jonathan.cameron, vsethi, linux-cxl, nirmoyd
In-Reply-To: <cover.1777269009.git.nicolinc@nvidia.com>
When a device's default substream attaches to an identity domain, the SMMU
driver currently sets the device's STE between two modes:
Mode 1: Cfg=Translate, S1DSS=Bypass, EATS=1
Mode 2: Cfg=bypass (EATS is ignored by HW)
When there is an active PASID (non-default substream), mode 1 is used. And
when there is no PASID support or no active PASID, mode 2 is used.
The driver will also downgrade an STE from mode 1 to mode 2, when the last
active substream becomes inactive.
However, there are PCIe devices that demand ATS to be always on. For these
devices, their STEs have to use the mode 1 as HW ignores EATS with mode 2.
Change the driver accordingly:
- always use the mode 1
- never downgrade to mode 2
- allocate and retain a CD table (see note below)
Note that these devices might not support PASID, i.e. doing non-PASID ATS.
In such a case, the ssid_bits is set to 0. However, s1cdmax must be set to
a !0 value in order to keep the S1DSS field effective. Thus, when a master
requires ats_always_on, set its s1cdmax to at least 1, meaning that the CD
table will have a dummy entry (SSID=1) that will never be used.
Now for these devices, arm_smmu_cdtab_allocated() will always return true,
v.s. false prior to this change. When its default substream is attached to
an IDENTITY domain, its first CD is NULL in the table, which is a totally
valid case. Thus, add "!master->ats_always_on" to the condition.
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Tested-by: Nirmoy Das <nirmoyd@nvidia.com>
Acked-by: Nirmoy Das <nirmoyd@nvidia.com>
Reviewed-by: Jason Gunthorpe <jgg@nvidia.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Nicolin Chen <nicolinc@nvidia.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 1 +
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 75 ++++++++++++++++++---
2 files changed, 68 insertions(+), 8 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index ef42df4753ec4..8c3600f4364c5 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -943,6 +943,7 @@ struct arm_smmu_master {
bool ats_enabled : 1;
bool ste_ats_enabled : 1;
bool stall_enabled;
+ bool ats_always_on;
unsigned int ssid_bits;
unsigned int iopf_refcount;
};
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index e8d7dbe495f03..d478f148cd34b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1742,8 +1742,11 @@ void arm_smmu_clear_cd(struct arm_smmu_master *master, ioasid_t ssid)
if (!arm_smmu_cdtab_allocated(&master->cd_table))
return;
cdptr = arm_smmu_get_cd_ptr(master, ssid);
- if (WARN_ON(!cdptr))
+ if (!cdptr) {
+ /* Only ats_always_on allows a NULL CD on default substream */
+ WARN_ON(!master->ats_always_on || ssid);
return;
+ }
arm_smmu_write_cd_entry(master, ssid, cdptr, &target);
}
@@ -1756,6 +1759,22 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master)
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
cd_table->s1cdmax = master->ssid_bits;
+
+ /*
+ * When a device doesn't support PASID (non default SSID), ssid_bits is
+ * set to 0. This also sets S1CDMAX to 0, which disables the substreams
+ * and ignores the S1DSS field.
+ *
+ * On the other hand, if a device demands ATS to be always on even when
+ * its default substream is IOMMU bypassed, it has to use EATS that is
+ * only effective with an STE (CFG=S1translate, S1DSS=Bypass). For such
+ * use cases, S1CDMAX has to be !0, in order to make use of S1DSS/EATS.
+ *
+ * Set S1CDMAX no lower than 1. This would add a dummy substream in the
+ * CD table but it should never be used by an actual CD.
+ */
+ if (master->ats_always_on)
+ cd_table->s1cdmax = max_t(u8, cd_table->s1cdmax, 1);
max_contexts = 1 << cd_table->s1cdmax;
if (!(smmu->features & ARM_SMMU_FEAT_2_LVL_CDTAB) ||
@@ -3851,7 +3870,8 @@ static int arm_smmu_blocking_set_dev_pasid(struct iommu_domain *new_domain,
* When the last user of the CD table goes away downgrade the STE back
* to a non-cd_table one, by re-attaching its sid_domain.
*/
- if (!arm_smmu_ssids_in_use(&master->cd_table)) {
+ if (!master->ats_always_on &&
+ !arm_smmu_ssids_in_use(&master->cd_table)) {
struct iommu_domain *sid_domain =
iommu_driver_get_domain_for_dev(master->dev);
@@ -3875,6 +3895,8 @@ static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,
.old_domain = old_domain,
.ssid = IOMMU_NO_PASID,
};
+ bool ats_always_on = master->ats_always_on &&
+ s1dss != STRTAB_STE_1_S1DSS_TERMINATE;
/*
* Do not allow any ASID to be changed while are working on the STE,
@@ -3886,7 +3908,7 @@ static void arm_smmu_attach_dev_ste(struct iommu_domain *domain,
* If the CD table is not in use we can use the provided STE, otherwise
* we use a cdtable STE with the provided S1DSS.
*/
- if (arm_smmu_ssids_in_use(&master->cd_table)) {
+ if (ats_always_on || arm_smmu_ssids_in_use(&master->cd_table)) {
/*
* If a CD table has to be present then we need to run with ATS
* on because we have to assume a PASID is using ATS. For
@@ -4215,6 +4237,42 @@ static void arm_smmu_remove_master(struct arm_smmu_master *master)
kfree(master->build_invs);
}
+static int arm_smmu_master_prepare_ats(struct arm_smmu_master *master)
+{
+ bool s1p = master->smmu->features & ARM_SMMU_FEAT_TRANS_S1;
+ unsigned int stu = __ffs(master->smmu->pgsize_bitmap);
+ struct pci_dev *pdev;
+ int ret;
+
+ if (!arm_smmu_ats_supported(master))
+ return 0;
+
+ pdev = to_pci_dev(master->dev);
+
+ if (!pci_ats_always_on(pdev))
+ goto out_prepare;
+
+ /*
+ * S1DSS is required for ATS to be always on for identity domain cases.
+ * However, the S1DSS field is ignored if !IDR0_S1P or !IDR1_SSIDSIZE.
+ */
+ if (!s1p || !master->smmu->ssid_bits) {
+ dev_info_once(master->dev,
+ "SMMU doesn't support ATS to be always on\n");
+ goto out_prepare;
+ }
+
+ master->ats_always_on = true;
+
+ ret = arm_smmu_alloc_cd_tables(master);
+ if (ret)
+ return ret;
+
+out_prepare:
+ pci_prepare_ats(pdev, stu);
+ return 0;
+}
+
static struct iommu_device *arm_smmu_probe_device(struct device *dev)
{
int ret;
@@ -4263,14 +4321,15 @@ static struct iommu_device *arm_smmu_probe_device(struct device *dev)
smmu->features & ARM_SMMU_FEAT_STALL_FORCE)
master->stall_enabled = true;
- if (dev_is_pci(dev)) {
- unsigned int stu = __ffs(smmu->pgsize_bitmap);
-
- pci_prepare_ats(to_pci_dev(dev), stu);
- }
+ ret = arm_smmu_master_prepare_ats(master);
+ if (ret)
+ goto err_disable_pasid;
return &smmu->iommu;
+err_disable_pasid:
+ arm_smmu_disable_pasid(master);
+ arm_smmu_remove_master(master);
err_free_master:
kfree(master);
return ERR_PTR(ret);
--
2.43.0
^ permalink raw reply related
* [PATCH v8 0/2] arm64: dts/defconfig: enable BST C1200 eMMC
From: Albert Yang @ 2026-04-27 5:55 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
This series adds DTS and defconfig support for the eMMC controller on
Black Sesame Technologies C1200 SoC, split from the v5 MMC series [1].
The MMC driver patches (dt-bindings, sdhci bounce buffer, BST SDHCI
driver, and MAINTAINERS update) were merged via mmc-next during the
v7.1 merge window and are now in mainline as of Linux 7.1-rc1 [2].
These remaining DTS and defconfig patches are submitted to the mailing
lists for review (per Krzysztof's feedback on v6 [3])
Both patches now carry Acked-by: Gordon Ge <gordon.ge@bst.ai> (BST
maintainer), collected from the v7 thread [4][5].
Changes since v7 [6]:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai> on patch 1/2 [4]
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai> on patch 2/2 [5]
- Rebased onto v7.1-rc1
- No code changes
Changes since v6:
- Resend with corrected recipients: send to mailing lists for review
first, not directly to soc@ (BST has a platform maintainer in
MAINTAINERS), per Krzysztof's feedback [3].
Changes since v5:
- Patch 2 (defconfig): fix CONFIG_MMC_SDHCI_BST ordering to match
Kconfig position (between CONFIG_MMC_SDHCI_TEGRA and
CONFIG_MMC_SDHCI_F_SDH30), as pointed out by Krzysztof Kozlowski.
Confirmed via savedefconfig.
Build/check on v7.1-rc1:
- arch/arm64 defconfig: clean (savedefconfig keeps CONFIG_MMC_SDHCI_BST
at its Kconfig-ordered position; no diff in the MMC_SDHCI section)
- arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dtb: builds clean
with W=1 and CHECK_DTBS=y (no new warnings)
- checkpatch.pl --strict: 0 errors, 0 warnings, 0 checks on both patches
[1] https://lore.kernel.org/lkml/20260123095342.272505-1-yangzh0906@thundersoft.com/
[2] https://lore.kernel.org/lkml/CAPDyKFrcXFAiYouOpjDx3NN-xWACU9jAzEfTU2m_-yvQ9SpC_A@mail.gmail.com/
[3] https://lore.kernel.org/lkml/12058c14-67c7-4b43-bbbc-ef0ccb813e61@kernel.org/
[4] https://lore.kernel.org/lkml/20260417.164709-gordon.ge@bst.ai/
[5] https://lore.kernel.org/lkml/20260417.163754-gordon.ge@bst.ai/
[6] https://lore.kernel.org/lkml/20260310091211.4171307-1-yangzh0906@thundersoft.com/
Albert Yang (2):
arm64: dts: bst: enable eMMC controller in C1200 CDCU1.0 board
arm64: defconfig: enable BST SDHCI controller
.../dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts | 19 +++++++++++++++++++
arch/arm64/boot/dts/bst/bstc1200.dtsi | 18 ++++++++++++++++++
arch/arm64/configs/defconfig | 1 +
3 files changed, 38 insertions(+)
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
--
2.43.0
^ permalink raw reply
* [PATCH v8 1/2] arm64: dts: bst: enable eMMC controller in C1200 CDCU1.0 board
From: Albert Yang @ 2026-04-27 5:55 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260427055555.3693459-1-yangzh0906@thundersoft.com>
Add eMMC controller support to the BST C1200 device tree:
- bstc1200.dtsi: Add mmc0 node for the DWCMSHC SDHCI controller
with basic configuration (disabled by default)
- bstc1200.dtsi: Add fixed clock definition for MMC controller
- bstc1200-cdcu1.0-adas_4c2g.dts: Enable mmc0 with board-specific
configuration including 8-bit bus width and reserved SRAM buffer
The bounce buffer in reserved SRAM addresses hardware constraints
where the eMMC controller cannot access main system memory through
SMMU due to a hardware bug, and all DRAM is located outside the
4GB boundary.
Signed-off-by: Albert Yang <yangzh0906@thundersoft.com>
Acked-by: Gordon Ge <gordon.ge@bst.ai>
---
Changes for v8:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai>
- Rebased onto v7.1-rc1
- No code changes
Changes for v7:
- No code changes; resend with corrected recipients
Changes for v5:
- Split from platform series per Arnd's feedback
Changes for v4:
- Change compatible to bst,c1200-sdhci
- Move bus-width and non-removable to board dts
Changes for v3:
- Split defconfig into dedicated patch
Changes for v2:
- Reorganize memory map, standardize interrupt definitions
---
.../dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts | 19 +++++++++++++++++++
arch/arm64/boot/dts/bst/bstc1200.dtsi | 18 ++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts b/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
index 5eb9ef369d8c..178ad4bf4f0a 100644
--- a/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
+++ b/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
@@ -17,6 +17,25 @@ memory@810000000 {
<0x8 0xc0000000 0x1 0x0>,
<0xc 0x00000000 0x0 0x40000000>;
};
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ mmc0_reserved: mmc0-reserved@5160000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0x5160000 0x0 0x10000>;
+ no-map;
+ };
+ };
+};
+
+&mmc0 {
+ bus-width = <8>;
+ memory-region = <&mmc0_reserved>;
+ non-removable;
+ status = "okay";
};
&uart0 {
diff --git a/arch/arm64/boot/dts/bst/bstc1200.dtsi b/arch/arm64/boot/dts/bst/bstc1200.dtsi
index dd13c6bfc3c8..9660d8396e27 100644
--- a/arch/arm64/boot/dts/bst/bstc1200.dtsi
+++ b/arch/arm64/boot/dts/bst/bstc1200.dtsi
@@ -7,6 +7,12 @@ / {
#address-cells = <2>;
#size-cells = <2>;
+ clk_mmc: clock-4000000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <4000000>;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -72,6 +78,18 @@ uart0: serial@20008000 {
status = "disabled";
};
+ mmc0: mmc@22200000 {
+ compatible = "bst,c1200-sdhci";
+ reg = <0x0 0x22200000 0x0 0x1000>,
+ <0x0 0x23006000 0x0 0x1000>;
+ clocks = <&clk_mmc>;
+ clock-names = "core";
+ dma-coherent;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ max-frequency = <200000000>;
+ status = "disabled";
+ };
+
gic: interrupt-controller@32800000 {
compatible = "arm,gic-v3";
reg = <0x0 0x32800000 0x0 0x10000>,
--
2.43.0
^ permalink raw reply related
* [PATCH v8 2/2] arm64: defconfig: enable BST SDHCI controller
From: Albert Yang @ 2026-04-27 5:55 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260427055555.3693459-1-yangzh0906@thundersoft.com>
Enable CONFIG_MMC_SDHCI_BST to support eMMC on Black Sesame
Technologies C1200 boards.
Signed-off-by: Albert Yang <yangzh0906@thundersoft.com>
Acked-by: Gordon Ge <gordon.ge@bst.ai>
---
Changes for v8:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai>
- Rebased onto v7.1-rc1
- No code changes
Changes for v7:
- No code changes; resend with corrected recipients
Changes for v6:
- Fix CONFIG_MMC_SDHCI_BST ordering to match Kconfig position
(between CONFIG_MMC_SDHCI_TEGRA and CONFIG_MMC_SDHCI_F_SDH30)
as pointed out by Krzysztof Kozlowski. Confirmed via savedefconfig.
Changes for v5:
- Split from platform series per Arnd's feedback
Changes for v4:
- Move CONFIG_MMC_SDHCI_BST before CONFIG_MMC_SDHCI_F_SDH30
Changes for v3:
- Split from arm64: dts patch
Changes for v2:
- Initial defconfig change included in DTS patch
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index d905a0777f93..304e12c80af9 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1292,6 +1292,7 @@ CONFIG_MMC_SDHCI_OF_SPARX5=y
CONFIG_MMC_SDHCI_CADENCE=y
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_MMC_SDHCI_BST=y
CONFIG_MMC_SDHCI_F_SDH30=y
CONFIG_MMC_MESON_GX=y
CONFIG_MMC_SDHCI_MSM=y
--
2.43.0
^ permalink raw reply related
* Re: [PATCH 1/1] scsi: ufs: remove ucd_rsp_dma_addr and ucd_prdt_dma_addr from ufshcd_lrb
From: Peter Wang (王信友) @ 2026-04-27 6:11 UTC (permalink / raw)
To: avri.altman@wdc.com, AngeloGioacchino Del Regno,
Ed Tsai (蔡宗軒), bvanassche@acm.org,
alim.akhtar@samsung.com, matthias.bgg@gmail.com,
James.Bottomley@HansenPartnership.com, martin.petersen@oracle.com
Cc: Alice Chao (趙珮均), linux-scsi@vger.kernel.org,
wsd_upstream, linux-kernel@vger.kernel.org,
Chun-Hung Wu (巫駿宏),
linux-arm-kernel@lists.infradead.org,
Naomi Chu (朱詠田),
linux-mediatek@lists.infradead.org, stable@vger.kernel.org
In-Reply-To: <20260427035856.1610363-1-ed.tsai@mediatek.com>
On Mon, 2026-04-27 at 11:58 +0800, ed.tsai@mediatek.com wrote:
> The offsets stored in utp_transfer_req_desc are in double words on
> hosts without UFSHCD_QUIRK_PRDT_BYTE_GRAN, using them directly to
> compute ucd_rsp_dma_addr and ucd_prdt_dma_addr results in incorrect
> DMA addresses.
>
> Since these fields are only used for error logging, remove them from
> struct ufshcd_lrb and compute directly in ufshcd_print_tr() using
> offsetof(struct utp_transfer_cmd_desc, ...) instead.
>
> Fixes: d5130c5a0932 ("scsi: ufs: Use pre-calculated offsets in
> ufshcd_init_lrb()")
> Cc: stable@vger.kernel.org
> Link:
> https://lore.kernel.org/all/20260424063603.382328-2-ed.tsai@mediatek.com/
> Signed-off-by: Ed Tsai <ed.tsai@mediatek.com>
> ---
Reviewed-by: Peter Wang <peter.wang@mediatek.com>
^ permalink raw reply
* Re: [PATCH v7 01/59] perf inject: Fix itrace branch stack synthesis
From: Namhyung Kim @ 2026-04-27 6:13 UTC (permalink / raw)
To: Ian Rogers
Cc: acme, adrian.hunter, james.clark, leo.yan, tmricht,
alice.mei.rogers, dapeng1.mi, linux-arm-kernel, linux-kernel,
linux-perf-users, mingo, peterz
In-Reply-To: <20260425224951.174663-2-irogers@google.com>
Hi Ian,
On Sat, Apr 25, 2026 at 03:48:53PM -0700, Ian Rogers wrote:
> When using "perf inject --itrace=L" to synthesize branch stacks from
> AUX data, several issues caused failures:
>
> 1. The synthesized samples were delivered without the
> PERF_SAMPLE_BRANCH_STACK flag if it was not in the original event's
> sample_type. Fixed by using sample_type | evsel->synth_sample_type
> in intel_pt_deliver_synth_event.
>
> 2. The record layout was misaligned because of inconsistent handling
> of PERF_SAMPLE_BRANCH_HW_INDEX. Fixed by explicitly writing nr and
> hw_idx in perf_event__synthesize_sample.
>
> 3. Modifying evsel->core.attr.sample_type early in __cmd_inject caused
> parse failures for subsequent records in the input file. Fixed by
> moving this modification to just before writing the header.
>
> 4. perf_event__repipe_sample was narrowed to only synthesize samples
> when branch stack injection was requested, and restored the use of
> perf_inject__cut_auxtrace_sample as a fallback to preserve
> functionality.
Looks like it does a lot of things in a patch. I think these are
independent fixes from this series. How about moving this out to a
separate series?
Thanks,
Namhyung
>
> Assisted-by: Gemini:gemini-3.1-pro-preview
> Signed-off-by: Ian Rogers <irogers@google.com>
> ---
> Issues fixed in v2:
>
> 1. Potential Heap Overflow in perf_event__repipe_sample : Addressed by
> adding a check that prints an error and returns -EFAULT if the
> calculated event size exceeds PERF_SAMPLE_MAX_SIZE , as you
> requested.
>
> 2. Header vs Payload Mismatch in __cmd_inject : Addressed by narrowing
> the condition so that HEADER_BRANCH_STACK is only set in the file
> header if add_last_branch was true.
>
> 3. NULL Pointer Dereference in intel-pt.c : Addressed by updating the
> condition in intel_pt_do_synth_pebs_sample to fill sample.
> branch_stack if it was synthesized, even if not in the original
> sample_type .
>
> 4. Unsafe Reads for events lacking HW_INDEX in synthetic-events.c :
> Addressed by using the perf_sample__branch_entries() macro and
> checking sample->no_hw_idx .
>
> 5. Size mismatch in perf_event__sample_event_size : Addressed by
> passing branch_sample_type to it and conditioning the hw_idx size on
> PERF_SAMPLE_BRANCH_HW_INDEX .
> ---
> tools/perf/bench/inject-buildid.c | 9 ++--
> tools/perf/builtin-inject.c | 77 ++++++++++++++++++++++++++++--
> tools/perf/tests/dlfilter-test.c | 8 +++-
> tools/perf/tests/sample-parsing.c | 5 +-
> tools/perf/util/arm-spe.c | 7 ++-
> tools/perf/util/cs-etm.c | 6 ++-
> tools/perf/util/intel-bts.c | 3 +-
> tools/perf/util/intel-pt.c | 13 +++--
> tools/perf/util/synthetic-events.c | 25 +++++++---
> tools/perf/util/synthetic-events.h | 6 ++-
> 10 files changed, 129 insertions(+), 30 deletions(-)
>
> diff --git a/tools/perf/bench/inject-buildid.c b/tools/perf/bench/inject-buildid.c
> index aad572a78d7f..bfd2c5ec9488 100644
> --- a/tools/perf/bench/inject-buildid.c
> +++ b/tools/perf/bench/inject-buildid.c
> @@ -228,9 +228,12 @@ static ssize_t synthesize_sample(struct bench_data *data, struct bench_dso *dso,
>
> event.header.type = PERF_RECORD_SAMPLE;
> event.header.misc = PERF_RECORD_MISC_USER;
> - event.header.size = perf_event__sample_event_size(&sample, bench_sample_type, 0);
> -
> - perf_event__synthesize_sample(&event, bench_sample_type, 0, &sample);
> + event.header.size = perf_event__sample_event_size(&sample, bench_sample_type,
> + /*read_format=*/0,
> + /*branch_sample_type=*/0);
> + perf_event__synthesize_sample(&event, bench_sample_type,
> + /*read_format=*/0,
> + /*branch_sample_type=*/0, &sample);
>
> return writen(data->input_pipe[1], &event, event.header.size);
> }
> diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
> index f174bc69cec4..88c0ef4f5ff1 100644
> --- a/tools/perf/builtin-inject.c
> +++ b/tools/perf/builtin-inject.c
> @@ -375,7 +375,59 @@ static int perf_event__repipe_sample(const struct perf_tool *tool,
>
> build_id__mark_dso_hit(tool, event, sample, evsel, machine);
>
> - if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
> + if (inject->itrace_synth_opts.set &&
> + (inject->itrace_synth_opts.last_branch ||
> + inject->itrace_synth_opts.add_last_branch)) {
> + union perf_event *event_copy = (void *)inject->event_copy;
> + struct branch_stack dummy_bs = { .nr = 0 };
> + int err;
> + size_t sz;
> + u64 orig_type = evsel->core.attr.sample_type;
> + u64 orig_branch_type = evsel->core.attr.branch_sample_type;
> +
> + if (event_copy == NULL) {
> + inject->event_copy = malloc(PERF_SAMPLE_MAX_SIZE);
> + if (!inject->event_copy)
> + return -ENOMEM;
> +
> + event_copy = (void *)inject->event_copy;
> + }
> +
> + if (!sample->branch_stack)
> + sample->branch_stack = &dummy_bs;
> +
> + if (inject->itrace_synth_opts.add_last_branch) {
> + /* Temporarily add in type bits for synthesis. */
> + evsel->core.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
> + evsel->core.attr.branch_sample_type |= PERF_SAMPLE_BRANCH_HW_INDEX;
> + evsel->core.attr.sample_type &= ~PERF_SAMPLE_AUX;
> + }
> +
> + sz = perf_event__sample_event_size(sample, evsel->core.attr.sample_type,
> + evsel->core.attr.read_format,
> + evsel->core.attr.branch_sample_type);
> +
> + if (sz > PERF_SAMPLE_MAX_SIZE) {
> + pr_err("Sample size %zu exceeds max size %d\n", sz, PERF_SAMPLE_MAX_SIZE);
> + return -EFAULT;
> + }
> +
> + event_copy->header.type = PERF_RECORD_SAMPLE;
> + event_copy->header.size = sz;
> +
> + err = perf_event__synthesize_sample(event_copy, evsel->core.attr.sample_type,
> + evsel->core.attr.read_format,
> + evsel->core.attr.branch_sample_type, sample);
> +
> + evsel->core.attr.sample_type = orig_type;
> + evsel->core.attr.branch_sample_type = orig_branch_type;
> +
> + if (err) {
> + pr_err("Failed to synthesize sample\n");
> + return err;
> + }
> + event = event_copy;
> + } else if (inject->itrace_synth_opts.set && sample->aux_sample.size) {
> event = perf_inject__cut_auxtrace_sample(inject, event, sample);
> if (IS_ERR(event))
> return PTR_ERR(event);
> @@ -464,7 +516,8 @@ static int perf_event__convert_sample_callchain(const struct perf_tool *tool,
> sample_type &= ~(PERF_SAMPLE_STACK_USER | PERF_SAMPLE_REGS_USER);
>
> perf_event__synthesize_sample(event_copy, sample_type,
> - evsel->core.attr.read_format, sample);
> + evsel->core.attr.read_format,
> + evsel->core.attr.branch_sample_type, sample);
> return perf_event__repipe_synth(tool, event_copy);
> }
>
> @@ -1100,7 +1153,8 @@ static int perf_inject__sched_stat(const struct perf_tool *tool,
> sample_sw.period = sample->period;
> sample_sw.time = sample->time;
> perf_event__synthesize_sample(event_sw, evsel->core.attr.sample_type,
> - evsel->core.attr.read_format, &sample_sw);
> + evsel->core.attr.read_format,
> + evsel->core.attr.branch_sample_type, &sample_sw);
> build_id__mark_dso_hit(tool, event_sw, &sample_sw, evsel, machine);
> ret = perf_event__repipe(tool, event_sw, &sample_sw, machine);
> perf_sample__exit(&sample_sw);
> @@ -2434,12 +2488,25 @@ static int __cmd_inject(struct perf_inject *inject)
> * synthesized hardware events, so clear the feature flag.
> */
> if (inject->itrace_synth_opts.set) {
> + struct evsel *evsel;
> +
> perf_header__clear_feat(&session->header,
> HEADER_AUXTRACE);
> - if (inject->itrace_synth_opts.last_branch ||
> - inject->itrace_synth_opts.add_last_branch)
> +
> + evlist__for_each_entry(session->evlist, evsel) {
> + evsel->core.attr.sample_type &= ~PERF_SAMPLE_AUX;
> + }
> +
> + if (inject->itrace_synth_opts.add_last_branch) {
> perf_header__set_feat(&session->header,
> HEADER_BRANCH_STACK);
> +
> + evlist__for_each_entry(session->evlist, evsel) {
> + evsel->core.attr.sample_type |= PERF_SAMPLE_BRANCH_STACK;
> + evsel->core.attr.branch_sample_type |=
> + PERF_SAMPLE_BRANCH_HW_INDEX;
> + }
> + }
> }
>
> /*
> diff --git a/tools/perf/tests/dlfilter-test.c b/tools/perf/tests/dlfilter-test.c
> index e63790c61d53..204663571943 100644
> --- a/tools/perf/tests/dlfilter-test.c
> +++ b/tools/perf/tests/dlfilter-test.c
> @@ -188,8 +188,12 @@ static int write_sample(struct test_data *td, u64 sample_type, u64 id, pid_t pid
>
> event->header.type = PERF_RECORD_SAMPLE;
> event->header.misc = PERF_RECORD_MISC_USER;
> - event->header.size = perf_event__sample_event_size(&sample, sample_type, 0);
> - err = perf_event__synthesize_sample(event, sample_type, 0, &sample);
> + event->header.size = perf_event__sample_event_size(&sample, sample_type,
> + /*read_format=*/0,
> + /*branch_sample_type=*/0);
> + err = perf_event__synthesize_sample(event, sample_type,
> + /*read_format=*/0,
> + /*branch_sample_type=*/0, &sample);
> if (err)
> return test_result("perf_event__synthesize_sample() failed", TEST_FAIL);
>
> diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
> index a7327c942ca2..55f0b73ca20e 100644
> --- a/tools/perf/tests/sample-parsing.c
> +++ b/tools/perf/tests/sample-parsing.c
> @@ -310,7 +310,8 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
> sample.read.one.lost = 1;
> }
>
> - sz = perf_event__sample_event_size(&sample, sample_type, read_format);
> + sz = perf_event__sample_event_size(&sample, sample_type, read_format,
> + evsel.core.attr.branch_sample_type);
> bufsz = sz + 4096; /* Add a bit for overrun checking */
> event = malloc(bufsz);
> if (!event) {
> @@ -324,7 +325,7 @@ static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
> event->header.size = sz;
>
> err = perf_event__synthesize_sample(event, sample_type, read_format,
> - &sample);
> + evsel.core.attr.branch_sample_type, &sample);
> if (err) {
> pr_debug("%s failed for sample_type %#"PRIx64", error %d\n",
> "perf_event__synthesize_sample", sample_type, err);
> diff --git a/tools/perf/util/arm-spe.c b/tools/perf/util/arm-spe.c
> index e5835042acdf..c4ed9f10e731 100644
> --- a/tools/perf/util/arm-spe.c
> +++ b/tools/perf/util/arm-spe.c
> @@ -484,8 +484,11 @@ static void arm_spe__prep_branch_stack(struct arm_spe_queue *speq)
>
> static int arm_spe__inject_event(union perf_event *event, struct perf_sample *sample, u64 type)
> {
> - event->header.size = perf_event__sample_event_size(sample, type, 0);
> - return perf_event__synthesize_sample(event, type, 0, sample);
> + event->header.type = PERF_RECORD_SAMPLE;
> + event->header.size = perf_event__sample_event_size(sample, type, /*read_format=*/0,
> + /*branch_sample_type=*/0);
> + return perf_event__synthesize_sample(event, type, /*read_format=*/0,
> + /*branch_sample_type=*/0, sample);
> }
>
> static inline int
> diff --git a/tools/perf/util/cs-etm.c b/tools/perf/util/cs-etm.c
> index 8a639d2e51a4..1ebc1a6a5e75 100644
> --- a/tools/perf/util/cs-etm.c
> +++ b/tools/perf/util/cs-etm.c
> @@ -1425,8 +1425,10 @@ static void cs_etm__update_last_branch_rb(struct cs_etm_queue *etmq,
> static int cs_etm__inject_event(union perf_event *event,
> struct perf_sample *sample, u64 type)
> {
> - event->header.size = perf_event__sample_event_size(sample, type, 0);
> - return perf_event__synthesize_sample(event, type, 0, sample);
> + event->header.size = perf_event__sample_event_size(sample, type, /*read_format=*/0,
> + /*branch_sample_type=*/0);
> + return perf_event__synthesize_sample(event, type, /*read_format=*/0,
> + /*branch_sample_type=*/0, sample);
> }
>
>
> diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c
> index 382255393fb3..0b18ebd13f7c 100644
> --- a/tools/perf/util/intel-bts.c
> +++ b/tools/perf/util/intel-bts.c
> @@ -303,7 +303,8 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq,
> event.sample.header.size = bts->branches_event_size;
> ret = perf_event__synthesize_sample(&event,
> bts->branches_sample_type,
> - 0, &sample);
> + /*read_format=*/0, /*branch_sample_type=*/0,
> + &sample);
> if (ret)
> return ret;
> }
> diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c
> index fc9eec8b54b8..2dce6106c038 100644
> --- a/tools/perf/util/intel-pt.c
> +++ b/tools/perf/util/intel-pt.c
> @@ -1731,8 +1731,12 @@ static void intel_pt_prep_b_sample(struct intel_pt *pt,
> static int intel_pt_inject_event(union perf_event *event,
> struct perf_sample *sample, u64 type)
> {
> - event->header.size = perf_event__sample_event_size(sample, type, 0);
> - return perf_event__synthesize_sample(event, type, 0, sample);
> + event->header.type = PERF_RECORD_SAMPLE;
> + event->header.size = perf_event__sample_event_size(sample, type, /*read_format=*/0,
> + /*branch_sample_type=*/0);
> +
> + return perf_event__synthesize_sample(event, type, /*read_format=*/0,
> + /*branch_sample_type=*/0, sample);
> }
>
> static inline int intel_pt_opt_inject(struct intel_pt *pt,
> @@ -2486,7 +2490,7 @@ static int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evse
> intel_pt_add_xmm(intr_regs, pos, items, regs_mask);
> }
>
> - if (sample_type & PERF_SAMPLE_BRANCH_STACK) {
> + if ((sample_type | evsel->synth_sample_type) & PERF_SAMPLE_BRANCH_STACK) {
> if (items->mask[INTEL_PT_LBR_0_POS] ||
> items->mask[INTEL_PT_LBR_1_POS] ||
> items->mask[INTEL_PT_LBR_2_POS]) {
> @@ -2557,7 +2561,8 @@ static int intel_pt_do_synth_pebs_sample(struct intel_pt_queue *ptq, struct evse
> sample.transaction = txn;
> }
>
> - ret = intel_pt_deliver_synth_event(pt, event, &sample, sample_type);
> + ret = intel_pt_deliver_synth_event(pt, event, &sample,
> + sample_type | evsel->synth_sample_type);
> perf_sample__exit(&sample);
> return ret;
> }
> diff --git a/tools/perf/util/synthetic-events.c b/tools/perf/util/synthetic-events.c
> index 85bee747f4cd..2461f25a4d7d 100644
> --- a/tools/perf/util/synthetic-events.c
> +++ b/tools/perf/util/synthetic-events.c
> @@ -1455,7 +1455,8 @@ int perf_event__synthesize_stat_round(const struct perf_tool *tool,
> return process(tool, (union perf_event *) &event, NULL, machine);
> }
>
> -size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format)
> +size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format,
> + u64 branch_sample_type)
> {
> size_t sz, result = sizeof(struct perf_record_sample);
>
> @@ -1515,8 +1516,10 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
>
> if (type & PERF_SAMPLE_BRANCH_STACK) {
> sz = sample->branch_stack->nr * sizeof(struct branch_entry);
> - /* nr, hw_idx */
> - sz += 2 * sizeof(u64);
> + /* nr */
> + sz += sizeof(u64);
> + if (branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX)
> + sz += sizeof(u64);
> result += sz;
> }
>
> @@ -1605,7 +1608,7 @@ static __u64 *copy_read_group_values(__u64 *array, __u64 read_format,
> }
>
> int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
> - const struct perf_sample *sample)
> + u64 branch_sample_type, const struct perf_sample *sample)
> {
> __u64 *array;
> size_t sz;
> @@ -1719,9 +1722,17 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_fo
>
> if (type & PERF_SAMPLE_BRANCH_STACK) {
> sz = sample->branch_stack->nr * sizeof(struct branch_entry);
> - /* nr, hw_idx */
> - sz += 2 * sizeof(u64);
> - memcpy(array, sample->branch_stack, sz);
> +
> + *array++ = sample->branch_stack->nr;
> +
> + if (branch_sample_type & PERF_SAMPLE_BRANCH_HW_INDEX) {
> + if (sample->no_hw_idx)
> + *array++ = 0;
> + else
> + *array++ = sample->branch_stack->hw_idx;
> + }
> +
> + memcpy(array, perf_sample__branch_entries((struct perf_sample *)sample), sz);
> array = (void *)array + sz;
> }
>
> diff --git a/tools/perf/util/synthetic-events.h b/tools/perf/util/synthetic-events.h
> index b0edad0c3100..8c7f49f9ccf5 100644
> --- a/tools/perf/util/synthetic-events.h
> +++ b/tools/perf/util/synthetic-events.h
> @@ -81,7 +81,8 @@ int perf_event__synthesize_mmap_events(const struct perf_tool *tool, union perf_
> int perf_event__synthesize_modules(const struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
> int perf_event__synthesize_namespaces(const struct perf_tool *tool, union perf_event *event, pid_t pid, pid_t tgid, perf_event__handler_t process, struct machine *machine);
> int perf_event__synthesize_cgroups(const struct perf_tool *tool, perf_event__handler_t process, struct machine *machine);
> -int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format, const struct perf_sample *sample);
> +int perf_event__synthesize_sample(union perf_event *event, u64 type, u64 read_format,
> + u64 branch_sample_type, const struct perf_sample *sample);
> int perf_event__synthesize_stat_config(const struct perf_tool *tool, struct perf_stat_config *config, perf_event__handler_t process, struct machine *machine);
> int perf_event__synthesize_stat_events(struct perf_stat_config *config, const struct perf_tool *tool, struct evlist *evlist, perf_event__handler_t process, bool attrs);
> int perf_event__synthesize_stat_round(const struct perf_tool *tool, u64 time, u64 type, perf_event__handler_t process, struct machine *machine);
> @@ -97,7 +98,8 @@ void perf_event__synthesize_final_bpf_metadata(struct perf_session *session,
>
> int perf_tool__process_synth_event(const struct perf_tool *tool, union perf_event *event, struct machine *machine, perf_event__handler_t process);
>
> -size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type, u64 read_format);
> +size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
> + u64 read_format, u64 branch_sample_type);
>
> int __machine__synthesize_threads(struct machine *machine, const struct perf_tool *tool,
> struct target *target, struct perf_thread_map *threads,
> --
> 2.54.0.545.g6539524ca2-goog
>
^ permalink raw reply
* [PATCH v4 0/2] Switch Arm CCA to use an auxiliary device instead of a platform device
From: Aneesh Kumar K.V (Arm) @ 2026-04-27 6:16 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon
As discussed here:
https://lore.kernel.org/all/20250728135216.48084-12-aneesh.kumar@kernel.org
The general feedback was that a platform device should not be used when
there is no underlying platform resource to represent. The existing CCA
support uses a platform device solely to anchor the TSM interface in the
device hierarchy, which is not an appropriate use of a platform device.
Use an auxiliary device instead to track CCA support.
The TSM framework uses the device abstraction to provide cross-architecture
TSM and TEE I/O functionality, including enumerating available platform TEE
I/O capabilities and provisioning connections between the platform TSM and
device DSMs.
For the CCA platform, the resulting device hierarchy appears as follows.
Note that the auxiliary device is still parented by the arm-smccc platform
device, so the sysfs path remains under /devices/platform/arm-smccc/:
$ cd /sys/class/tsm/
$ ls -al
total 0
drwxr-xr-x 2 root root 0 Jan 1 00:02 .
drwxr-xr-x 23 root root 0 Jan 1 00:00 ..
lrwxrwxrwx 1 root root 0 Jan 1 00:03 tsm0 -> ../../devices/platform/arm-smccc/arm_cca_guest.arm-rsi-dev.0/tsm/tsm0
$
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>
Aneesh Kumar K.V (Arm) (2):
firmware: smccc: coco: Manage arm-smccc platform device and CCA
auxiliary drivers
coco: guest: arm64: Drop dummy RSI platform device stub
arch/arm64/include/asm/rsi.h | 2 +-
arch/arm64/kernel/rsi.c | 15 -----
drivers/firmware/smccc/Kconfig | 1 +
drivers/firmware/smccc/Makefile | 1 +
drivers/firmware/smccc/rmm.c | 23 ++++++++
drivers/firmware/smccc/rmm.h | 17 ++++++
drivers/firmware/smccc/smccc.c | 14 +++++
drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
drivers/virt/coco/arm-cca-guest/Makefile | 2 +
.../{arm-cca-guest.c => arm-cca.c} | 59 +++++++++----------
10 files changed, 89 insertions(+), 46 deletions(-)
create mode 100644 drivers/firmware/smccc/rmm.c
create mode 100644 drivers/firmware/smccc/rmm.h
rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (84%)
--
2.43.0
^ permalink raw reply
* [PATCH v4 1/2] firmware: smccc: coco: Manage arm-smccc platform device and CCA auxiliary drivers
From: Aneesh Kumar K.V (Arm) @ 2026-04-27 6:16 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon
In-Reply-To: <20260427061615.905018-1-aneesh.kumar@kernel.org>
Make the SMCCC driver responsible for registering the arm-smccc platform
device and after confirming the relevant SMCCC function IDs, create
the arm_cca_guest auxiliary device.
Also update the arm-cca-guest driver to use the auxiliary device
interface instead of the platform device (arm-cca-dev). The removal of
the platform device registration will follow in a subsequent patch,
allowing this change to be applied without immediately breaking existing
userspace dependencies [1].
[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>
---
arch/arm64/include/asm/rsi.h | 2 +-
arch/arm64/kernel/rsi.c | 2 +-
drivers/firmware/smccc/Kconfig | 1 +
drivers/firmware/smccc/Makefile | 1 +
drivers/firmware/smccc/rmm.c | 23 ++++++++
drivers/firmware/smccc/rmm.h | 17 ++++++
drivers/firmware/smccc/smccc.c | 14 +++++
drivers/virt/coco/arm-cca-guest/Kconfig | 1 +
drivers/virt/coco/arm-cca-guest/Makefile | 2 +
.../{arm-cca-guest.c => arm-cca.c} | 59 +++++++++----------
10 files changed, 90 insertions(+), 32 deletions(-)
create mode 100644 drivers/firmware/smccc/rmm.c
create mode 100644 drivers/firmware/smccc/rmm.h
rename drivers/virt/coco/arm-cca-guest/{arm-cca-guest.c => arm-cca.c} (84%)
diff --git a/arch/arm64/include/asm/rsi.h b/arch/arm64/include/asm/rsi.h
index 88b50d660e85..2d2d363aaaee 100644
--- a/arch/arm64/include/asm/rsi.h
+++ b/arch/arm64/include/asm/rsi.h
@@ -10,7 +10,7 @@
#include <linux/jump_label.h>
#include <asm/rsi_cmds.h>
-#define RSI_PDEV_NAME "arm-cca-dev"
+#define RSI_DEV_NAME "arm-rsi-dev"
DECLARE_STATIC_KEY_FALSE(rsi_present);
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 9e846ce4ef9c..8380e5ba88d2 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/Kconfig b/drivers/firmware/smccc/Kconfig
index 15e7466179a6..2b6984757241 100644
--- a/drivers/firmware/smccc/Kconfig
+++ b/drivers/firmware/smccc/Kconfig
@@ -8,6 +8,7 @@ config HAVE_ARM_SMCCC
config HAVE_ARM_SMCCC_DISCOVERY
bool
depends on ARM_PSCI_FW
+ select AUXILIARY_BUS
default y
help
SMCCC v1.0 lacked discoverability and hence PSCI v1.0 was updated
diff --git a/drivers/firmware/smccc/Makefile b/drivers/firmware/smccc/Makefile
index 40d19144a860..146dc3c03c20 100644
--- a/drivers/firmware/smccc/Makefile
+++ b/drivers/firmware/smccc/Makefile
@@ -2,3 +2,4 @@
#
obj-$(CONFIG_HAVE_ARM_SMCCC_DISCOVERY) += smccc.o kvm_guest.o
obj-$(CONFIG_ARM_SMCCC_SOC_ID) += soc_id.o
+obj-$(CONFIG_ARM64) += rmm.o
diff --git a/drivers/firmware/smccc/rmm.c b/drivers/firmware/smccc/rmm.c
new file mode 100644
index 000000000000..2a6187df3285
--- /dev/null
+++ b/drivers/firmware/smccc/rmm.c
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 Arm Limited
+ */
+
+#include <linux/auxiliary_bus.h>
+#include "rmm.h"
+
+void __init register_rsi_device(struct platform_device *pdev)
+{
+ unsigned long ret;
+ unsigned long ver_lower, ver_higher;
+
+ if (arm_smccc_1_1_get_conduit() != SMCCC_CONDUIT_SMC)
+ return;
+
+ ret = rsi_request_version(RSI_ABI_VERSION, &ver_lower, &ver_higher);
+ if (ret != RSI_SUCCESS)
+ return;
+
+ __devm_auxiliary_device_create(&pdev->dev,
+ "arm_cca_guest", RSI_DEV_NAME, NULL, 0);
+}
diff --git a/drivers/firmware/smccc/rmm.h b/drivers/firmware/smccc/rmm.h
new file mode 100644
index 000000000000..a47a650d4f51
--- /dev/null
+++ b/drivers/firmware/smccc/rmm.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _SMCCC_RMM_H
+#define _SMCCC_RMM_H
+
+#include <linux/platform_device.h>
+
+#ifdef CONFIG_ARM64
+#include <asm/rsi_cmds.h>
+void __init register_rsi_device(struct platform_device *pdev);
+#else
+
+static void __init register_rsi_device(struct platform_device *pdev)
+{
+
+}
+#endif
+#endif
diff --git a/drivers/firmware/smccc/smccc.c b/drivers/firmware/smccc/smccc.c
index bdee057db2fd..fc9b44b7c687 100644
--- a/drivers/firmware/smccc/smccc.c
+++ b/drivers/firmware/smccc/smccc.c
@@ -12,6 +12,8 @@
#include <linux/platform_device.h>
#include <asm/archrandom.h>
+#include "rmm.h"
+
static u32 smccc_version = ARM_SMCCC_VERSION_1_0;
static enum arm_smccc_conduit smccc_conduit = SMCCC_CONDUIT_NONE;
@@ -85,6 +87,18 @@ static int __init smccc_devices_init(void)
{
struct platform_device *pdev;
+ pdev = platform_device_register_simple("arm-smccc",
+ PLATFORM_DEVID_NONE, NULL, 0);
+ if (IS_ERR(pdev)) {
+ pr_err("arm-smccc: could not register device: %ld\n", PTR_ERR(pdev));
+ } else {
+ /*
+ * Register the RMI and RSI devices only when firmware exposes
+ * the required SMCCC function IDs at a supported revision.
+ */
+ register_rsi_device(pdev);
+ }
+
if (smccc_trng_available) {
pdev = platform_device_register_simple("smccc_trng", -1,
NULL, 0);
diff --git a/drivers/virt/coco/arm-cca-guest/Kconfig b/drivers/virt/coco/arm-cca-guest/Kconfig
index 3f0f013f03f1..a42359a90558 100644
--- a/drivers/virt/coco/arm-cca-guest/Kconfig
+++ b/drivers/virt/coco/arm-cca-guest/Kconfig
@@ -2,6 +2,7 @@ config ARM_CCA_GUEST
tristate "Arm CCA Guest driver"
depends on ARM64
select TSM_REPORTS
+ select AUXILIARY_BUS
help
The driver provides userspace interface to request and
attestation report from the Realm Management Monitor(RMM).
diff --git a/drivers/virt/coco/arm-cca-guest/Makefile b/drivers/virt/coco/arm-cca-guest/Makefile
index 69eeba08e98a..75a120e24fda 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 84%
rename from drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
rename to drivers/virt/coco/arm-cca-guest/arm-cca.c
index 0c9ea24a200c..7daada072cc0 100644
--- a/drivers/virt/coco/arm-cca-guest/arm-cca-guest.c
+++ b/drivers/virt/coco/arm-cca-guest/arm-cca.c
@@ -3,6 +3,7 @@
* Copyright (C) 2023 ARM Ltd.
*/
+#include <linux/auxiliary_bus.h>
#include <linux/arm-smccc.h>
#include <linux/cc_platform.h>
#include <linux/kernel.h>
@@ -181,52 +182,50 @@ 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,
};
-/**
- * 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_devsec_tsm_probe(struct auxiliary_device *adev,
+ const struct auxiliary_device_id *id)
{
int ret;
if (!is_realm_world())
return -ENODEV;
- ret = tsm_report_register(&arm_cca_tsm_ops, NULL);
- if (ret < 0)
- pr_err("Error %d registering with TSM\n", ret);
+ ret = tsm_report_register(&arm_cca_tsm_report_ops, NULL);
+ if (ret < 0) {
+ dev_err_probe(&adev->dev, ret, "Error registering with TSM\n");
+ return ret;
+ }
- return ret;
-}
-module_init(arm_cca_guest_init);
+ ret = devm_add_action_or_reset(&adev->dev, unregister_cca_tsm_report, NULL);
+ if (ret < 0) {
+ dev_err_probe(&adev->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_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 auxiliary_device_id cca_devsec_tsm_id_table[] = {
+ { .name = KBUILD_MODNAME "." RSI_DEV_NAME },
+ {}
};
+MODULE_DEVICE_TABLE(auxiliary, cca_devsec_tsm_id_table);
-MODULE_DEVICE_TABLE(platform, arm_cca_match);
+static struct auxiliary_driver cca_devsec_tsm_driver = {
+ .probe = cca_devsec_tsm_probe,
+ .id_table = cca_devsec_tsm_id_table,
+};
+module_auxiliary_driver(cca_devsec_tsm_driver);
MODULE_AUTHOR("Sami Mujawar <sami.mujawar@arm.com>");
MODULE_DESCRIPTION("Arm CCA Guest TSM Driver");
MODULE_LICENSE("GPL");
--
2.43.0
^ permalink raw reply related
* [PATCH v4 2/2] coco: guest: arm64: Drop dummy RSI platform device stub
From: Aneesh Kumar K.V (Arm) @ 2026-04-27 6:16 UTC (permalink / raw)
To: linux-kernel, linux-arm-kernel
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Greg KH, Jeremy Linton,
Jonathan Cameron, Lorenzo Pieralisi, Mark Rutland, Sudeep Holla,
Will Deacon, Jonathan Cameron
In-Reply-To: <20260427061615.905018-1-aneesh.kumar@kernel.org>
The SMCCC firmware driver now creates the `arm-smccc` platform device
and also creates the CCA auxiliary devices once the RSI ABI is
discovered. This makes the arch-specific arm64_create_dummy_rsi_dev()
helper redundant. Remove the arm-cca-dev platform device registration
and let the SMCCC probe manage the RSI device.
systemd match on platform:arm-cca-dev for confidential vm detection [1].
Losing the platform device registration can break that. Keeping this
removal in its own change makes it easy to revert if that regression
blocks the rollout.
[1] https://lore.kernel.org/all/4a7d84b2-2ec4-4773-a2d5-7b63d5c683cf@arm.com
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
arch/arm64/kernel/rsi.c | 15 ---------------
1 file changed, 15 deletions(-)
diff --git a/arch/arm64/kernel/rsi.c b/arch/arm64/kernel/rsi.c
index 8380e5ba88d2..9ba29e832685 100644
--- a/arch/arm64/kernel/rsi.c
+++ b/arch/arm64/kernel/rsi.c
@@ -159,18 +159,3 @@ 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 int __init arm64_create_dummy_rsi_dev(void)
-{
- if (is_realm_world() &&
- platform_device_register(&rsi_dev))
- pr_err("failed to register rsi platform device\n");
- return 0;
-}
-
-arch_initcall(arm64_create_dummy_rsi_dev)
--
2.43.0
^ permalink raw reply related
* [PATCH] pinctrl: mediatek: common-v1: Directly modify registers to set GPIO direction
From: Chen-Yu Tsai @ 2026-04-27 6:17 UTC (permalink / raw)
To: Sean Wang, Matthias Brugger, AngeloGioacchino Del Regno,
Linus Walleij
Cc: Chen-Yu Tsai, linux-mediatek, linux-gpio, linux-arm-kernel,
linux-kernel
pinctrl_gpio_direction_input() / pinctrl_gpio_direction_output() take
the pinctrl mutex. This causes a gpiochip operations to need to sleep.
Worse yet, the .can_sleep field in the gpiochip is not set. This causes
the shared GPIO proxy to trip over, as it uses gpiod_cansleep() to check
whether it can use a spinlock or needs a mutex. In this case, it ends
up taking a spinlock, then calls pinctrl_gpio_direction_output(), which
takes a mutex. This causes a huge warning.
Since the Mediatek hardware has separate clear/set registers, there is
no risk of clobbering other bits like with a read-modify-write pattern.
Switch to directly setting the GPIO direction register bits to avoid
the mutex.
Signed-off-by: Chen-Yu Tsai <wenst@chromium.org>
---
Only compile tested. Accidentally fixed the wrong file when my target
actually used pinctrl-paris.c
---
drivers/pinctrl/mediatek/pinctrl-mtk-common.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
index 3f518dce6d23..9c258e205e39 100644
--- a/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
+++ b/drivers/pinctrl/mediatek/pinctrl-mtk-common.c
@@ -806,16 +806,24 @@ static const struct pinmux_ops mtk_pmx_ops = {
.gpio_request_enable = mtk_pmx_gpio_request_enable,
};
+static int mtk_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
+
+ return mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, offset, true);
+}
+
static int mtk_gpio_direction_output(struct gpio_chip *chip,
unsigned offset, int value)
{
+ struct mtk_pinctrl *pctl = gpiochip_get_data(chip);
int ret;
ret = mtk_gpio_set(chip, offset, value);
if (ret)
return ret;
- return pinctrl_gpio_direction_output(chip, offset);
+ return mtk_pmx_gpio_set_direction(pctl->pctl_dev, NULL, offset, true);
}
static int mtk_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
@@ -895,7 +903,7 @@ static const struct gpio_chip mtk_gpio_chip = {
.request = gpiochip_generic_request,
.free = gpiochip_generic_free,
.get_direction = mtk_gpio_get_direction,
- .direction_input = pinctrl_gpio_direction_input,
+ .direction_input = mtk_gpio_direction_input,
.direction_output = mtk_gpio_direction_output,
.get = mtk_gpio_get,
.set = mtk_gpio_set,
--
2.54.0.rc2.544.gc7ae2d5bb8-goog
^ permalink raw reply related
* [PATCH v8 0/2] arm64: dts/defconfig: enable BST C1200 eMMC
From: Albert Yang @ 2026-04-27 6:23 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
This series adds DTS and defconfig support for the eMMC controller on
Black Sesame Technologies C1200 SoC, split from the v5 MMC series [1].
The MMC driver patches (dt-bindings, sdhci bounce buffer, BST SDHCI
driver, and MAINTAINERS update) were merged via mmc-next during the
v7.1 merge window and are now in mainline as of Linux 7.1-rc1 [2].
These remaining DTS and defconfig patches are submitted to the mailing
lists for review (per Krzysztof's feedback on v6 [3])
Both patches now carry Acked-by: Gordon Ge <gordon.ge@bst.ai> (BST
maintainer), collected from the v7 thread [4][5].
Changes since v7 [6]:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai> on patch 1/2 [4]
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai> on patch 2/2 [5]
- Rebased onto v7.1-rc1
- No code changes
Changes since v6:
- Resend with corrected recipients: send to mailing lists for review
first, not directly to soc@ (BST has a platform maintainer in
MAINTAINERS), per Krzysztof's feedback [3].
Changes since v5:
- Patch 2 (defconfig): fix CONFIG_MMC_SDHCI_BST ordering to match
Kconfig position (between CONFIG_MMC_SDHCI_TEGRA and
CONFIG_MMC_SDHCI_F_SDH30), as pointed out by Krzysztof Kozlowski.
Confirmed via savedefconfig.
Build/check on v7.1-rc1:
- arch/arm64 defconfig: clean (savedefconfig keeps CONFIG_MMC_SDHCI_BST
at its Kconfig-ordered position; no diff in the MMC_SDHCI section)
- arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dtb: builds clean
with W=1 and CHECK_DTBS=y (no new warnings)
- checkpatch.pl --strict: 0 errors, 0 warnings, 0 checks on both patches
[1] https://lore.kernel.org/lkml/20260123095342.272505-1-yangzh0906@thundersoft.com/
[2] https://lore.kernel.org/lkml/CAPDyKFrcXFAiYouOpjDx3NN-xWACU9jAzEfTU2m_-yvQ9SpC_A@mail.gmail.com/
[3] https://lore.kernel.org/lkml/12058c14-67c7-4b43-bbbc-ef0ccb813e61@kernel.org/
[4] https://lore.kernel.org/lkml/20260417.164709-gordon.ge@bst.ai/
[5] https://lore.kernel.org/lkml/20260417.163754-gordon.ge@bst.ai/
[6] https://lore.kernel.org/lkml/20260310091211.4171307-1-yangzh0906@thundersoft.com/
Albert Yang (2):
arm64: dts: bst: enable eMMC controller in C1200 CDCU1.0 board
arm64: defconfig: enable BST SDHCI controller
.../dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts | 19 +++++++++++++++++++
arch/arm64/boot/dts/bst/bstc1200.dtsi | 18 ++++++++++++++++++
arch/arm64/configs/defconfig | 1 +
3 files changed, 38 insertions(+)
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
--
2.43.0
^ permalink raw reply
* [PATCH v8 1/2] arm64: dts: bst: enable eMMC controller in C1200 CDCU1.0 board
From: Albert Yang @ 2026-04-27 6:23 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260427062326.3715732-1-yangzh0906@thundersoft.com>
Add eMMC controller support to the BST C1200 device tree:
- bstc1200.dtsi: Add mmc0 node for the DWCMSHC SDHCI controller
with basic configuration (disabled by default)
- bstc1200.dtsi: Add fixed clock definition for MMC controller
- bstc1200-cdcu1.0-adas_4c2g.dts: Enable mmc0 with board-specific
configuration including 8-bit bus width and reserved SRAM buffer
The bounce buffer in reserved SRAM addresses hardware constraints
where the eMMC controller cannot access main system memory through
SMMU due to a hardware bug, and all DRAM is located outside the
4GB boundary.
Signed-off-by: Albert Yang <yangzh0906@thundersoft.com>
Acked-by: Gordon Ge <gordon.ge@bst.ai>
---
Changes for v8:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai>
- Rebased onto v7.1-rc1
- No code changes
Changes for v7:
- No code changes; resend with corrected recipients
Changes for v5:
- Split from platform series per Arnd's feedback
Changes for v4:
- Change compatible to bst,c1200-sdhci
- Move bus-width and non-removable to board dts
Changes for v3:
- Split defconfig into dedicated patch
Changes for v2:
- Reorganize memory map, standardize interrupt definitions
---
.../dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts | 19 +++++++++++++++++++
arch/arm64/boot/dts/bst/bstc1200.dtsi | 18 ++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts b/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
index 5eb9ef369d8c..178ad4bf4f0a 100644
--- a/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
+++ b/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
@@ -17,6 +17,25 @@ memory@810000000 {
<0x8 0xc0000000 0x1 0x0>,
<0xc 0x00000000 0x0 0x40000000>;
};
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ mmc0_reserved: mmc0-reserved@5160000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0x5160000 0x0 0x10000>;
+ no-map;
+ };
+ };
+};
+
+&mmc0 {
+ bus-width = <8>;
+ memory-region = <&mmc0_reserved>;
+ non-removable;
+ status = "okay";
};
&uart0 {
diff --git a/arch/arm64/boot/dts/bst/bstc1200.dtsi b/arch/arm64/boot/dts/bst/bstc1200.dtsi
index dd13c6bfc3c8..9660d8396e27 100644
--- a/arch/arm64/boot/dts/bst/bstc1200.dtsi
+++ b/arch/arm64/boot/dts/bst/bstc1200.dtsi
@@ -7,6 +7,12 @@ / {
#address-cells = <2>;
#size-cells = <2>;
+ clk_mmc: clock-4000000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <4000000>;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -72,6 +78,18 @@ uart0: serial@20008000 {
status = "disabled";
};
+ mmc0: mmc@22200000 {
+ compatible = "bst,c1200-sdhci";
+ reg = <0x0 0x22200000 0x0 0x1000>,
+ <0x0 0x23006000 0x0 0x1000>;
+ clocks = <&clk_mmc>;
+ clock-names = "core";
+ dma-coherent;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ max-frequency = <200000000>;
+ status = "disabled";
+ };
+
gic: interrupt-controller@32800000 {
compatible = "arm,gic-v3";
reg = <0x0 0x32800000 0x0 0x10000>,
--
2.43.0
^ permalink raw reply related
* [PATCH v8 2/2] arm64: defconfig: enable BST SDHCI controller
From: Albert Yang @ 2026-04-27 6:23 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260427062326.3715732-1-yangzh0906@thundersoft.com>
Enable CONFIG_MMC_SDHCI_BST to support eMMC on Black Sesame
Technologies C1200 boards.
Signed-off-by: Albert Yang <yangzh0906@thundersoft.com>
Acked-by: Gordon Ge <gordon.ge@bst.ai>
---
Changes for v8:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai>
- Rebased onto v7.1-rc1
- No code changes
Changes for v7:
- No code changes; resend with corrected recipients
Changes for v6:
- Fix CONFIG_MMC_SDHCI_BST ordering to match Kconfig position
(between CONFIG_MMC_SDHCI_TEGRA and CONFIG_MMC_SDHCI_F_SDH30)
as pointed out by Krzysztof Kozlowski. Confirmed via savedefconfig.
Changes for v5:
- Split from platform series per Arnd's feedback
Changes for v4:
- Move CONFIG_MMC_SDHCI_BST before CONFIG_MMC_SDHCI_F_SDH30
Changes for v3:
- Split from arm64: dts patch
Changes for v2:
- Initial defconfig change included in DTS patch
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index d905a0777f93..304e12c80af9 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1292,6 +1292,7 @@ CONFIG_MMC_SDHCI_OF_SPARX5=y
CONFIG_MMC_SDHCI_CADENCE=y
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_MMC_SDHCI_BST=y
CONFIG_MMC_SDHCI_F_SDH30=y
CONFIG_MMC_MESON_GX=y
CONFIG_MMC_SDHCI_MSM=y
--
2.43.0
^ permalink raw reply related
* [PATCH v8 2/2] arm64: defconfig: enable BST SDHCI controller
From: Albert Yang @ 2026-04-27 6:23 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260427062329.3715925-1-yangzh0906@thundersoft.com>
Enable CONFIG_MMC_SDHCI_BST to support eMMC on Black Sesame
Technologies C1200 boards.
Signed-off-by: Albert Yang <yangzh0906@thundersoft.com>
Acked-by: Gordon Ge <gordon.ge@bst.ai>
---
Changes for v8:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai>
- Rebased onto v7.1-rc1
- No code changes
Changes for v7:
- No code changes; resend with corrected recipients
Changes for v6:
- Fix CONFIG_MMC_SDHCI_BST ordering to match Kconfig position
(between CONFIG_MMC_SDHCI_TEGRA and CONFIG_MMC_SDHCI_F_SDH30)
as pointed out by Krzysztof Kozlowski. Confirmed via savedefconfig.
Changes for v5:
- Split from platform series per Arnd's feedback
Changes for v4:
- Move CONFIG_MMC_SDHCI_BST before CONFIG_MMC_SDHCI_F_SDH30
Changes for v3:
- Split from arm64: dts patch
Changes for v2:
- Initial defconfig change included in DTS patch
---
arch/arm64/configs/defconfig | 1 +
1 file changed, 1 insertion(+)
diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index d905a0777f93..304e12c80af9 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -1292,6 +1292,7 @@ CONFIG_MMC_SDHCI_OF_SPARX5=y
CONFIG_MMC_SDHCI_CADENCE=y
CONFIG_MMC_SDHCI_ESDHC_IMX=y
CONFIG_MMC_SDHCI_TEGRA=y
+CONFIG_MMC_SDHCI_BST=y
CONFIG_MMC_SDHCI_F_SDH30=y
CONFIG_MMC_MESON_GX=y
CONFIG_MMC_SDHCI_MSM=y
--
2.43.0
^ permalink raw reply related
* [PATCH v8 1/2] arm64: dts: bst: enable eMMC controller in C1200 CDCU1.0 board
From: Albert Yang @ 2026-04-27 6:23 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
In-Reply-To: <20260427062329.3715925-1-yangzh0906@thundersoft.com>
Add eMMC controller support to the BST C1200 device tree:
- bstc1200.dtsi: Add mmc0 node for the DWCMSHC SDHCI controller
with basic configuration (disabled by default)
- bstc1200.dtsi: Add fixed clock definition for MMC controller
- bstc1200-cdcu1.0-adas_4c2g.dts: Enable mmc0 with board-specific
configuration including 8-bit bus width and reserved SRAM buffer
The bounce buffer in reserved SRAM addresses hardware constraints
where the eMMC controller cannot access main system memory through
SMMU due to a hardware bug, and all DRAM is located outside the
4GB boundary.
Signed-off-by: Albert Yang <yangzh0906@thundersoft.com>
Acked-by: Gordon Ge <gordon.ge@bst.ai>
---
Changes for v8:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai>
- Rebased onto v7.1-rc1
- No code changes
Changes for v7:
- No code changes; resend with corrected recipients
Changes for v5:
- Split from platform series per Arnd's feedback
Changes for v4:
- Change compatible to bst,c1200-sdhci
- Move bus-width and non-removable to board dts
Changes for v3:
- Split defconfig into dedicated patch
Changes for v2:
- Reorganize memory map, standardize interrupt definitions
---
.../dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts | 19 +++++++++++++++++++
arch/arm64/boot/dts/bst/bstc1200.dtsi | 18 ++++++++++++++++++
2 files changed, 37 insertions(+)
diff --git a/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts b/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
index 5eb9ef369d8c..178ad4bf4f0a 100644
--- a/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
+++ b/arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts
@@ -17,6 +17,25 @@ memory@810000000 {
<0x8 0xc0000000 0x1 0x0>,
<0xc 0x00000000 0x0 0x40000000>;
};
+
+ reserved-memory {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ mmc0_reserved: mmc0-reserved@5160000 {
+ compatible = "shared-dma-pool";
+ reg = <0x0 0x5160000 0x0 0x10000>;
+ no-map;
+ };
+ };
+};
+
+&mmc0 {
+ bus-width = <8>;
+ memory-region = <&mmc0_reserved>;
+ non-removable;
+ status = "okay";
};
&uart0 {
diff --git a/arch/arm64/boot/dts/bst/bstc1200.dtsi b/arch/arm64/boot/dts/bst/bstc1200.dtsi
index dd13c6bfc3c8..9660d8396e27 100644
--- a/arch/arm64/boot/dts/bst/bstc1200.dtsi
+++ b/arch/arm64/boot/dts/bst/bstc1200.dtsi
@@ -7,6 +7,12 @@ / {
#address-cells = <2>;
#size-cells = <2>;
+ clk_mmc: clock-4000000 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <4000000>;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -72,6 +78,18 @@ uart0: serial@20008000 {
status = "disabled";
};
+ mmc0: mmc@22200000 {
+ compatible = "bst,c1200-sdhci";
+ reg = <0x0 0x22200000 0x0 0x1000>,
+ <0x0 0x23006000 0x0 0x1000>;
+ clocks = <&clk_mmc>;
+ clock-names = "core";
+ dma-coherent;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ max-frequency = <200000000>;
+ status = "disabled";
+ };
+
gic: interrupt-controller@32800000 {
compatible = "arm,gic-v3";
reg = <0x0 0x32800000 0x0 0x10000>,
--
2.43.0
^ permalink raw reply related
* [PATCH v8 0/2] arm64: dts/defconfig: enable BST C1200 eMMC
From: Albert Yang @ 2026-04-27 6:23 UTC (permalink / raw)
To: gordon.ge, krzk, krzk+dt, robh, conor+dt, arnd, catalin.marinas,
will
Cc: bst-upstream, linux-arm-kernel, devicetree, linux-kernel
This series adds DTS and defconfig support for the eMMC controller on
Black Sesame Technologies C1200 SoC, split from the v5 MMC series [1].
The MMC driver patches (dt-bindings, sdhci bounce buffer, BST SDHCI
driver, and MAINTAINERS update) were merged via mmc-next during the
v7.1 merge window and are now in mainline as of Linux 7.1-rc1 [2].
These remaining DTS and defconfig patches are submitted to the mailing
lists for review (per Krzysztof's feedback on v6 [3])
Both patches now carry Acked-by: Gordon Ge <gordon.ge@bst.ai> (BST
maintainer), collected from the v7 thread [4][5].
Changes since v7 [6]:
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai> on patch 1/2 [4]
- Collected Acked-by: Gordon Ge <gordon.ge@bst.ai> on patch 2/2 [5]
- Rebased onto v7.1-rc1
- No code changes
Changes since v6:
- Resend with corrected recipients: send to mailing lists for review
first, not directly to soc@ (BST has a platform maintainer in
MAINTAINERS), per Krzysztof's feedback [3].
Changes since v5:
- Patch 2 (defconfig): fix CONFIG_MMC_SDHCI_BST ordering to match
Kconfig position (between CONFIG_MMC_SDHCI_TEGRA and
CONFIG_MMC_SDHCI_F_SDH30), as pointed out by Krzysztof Kozlowski.
Confirmed via savedefconfig.
Build/check on v7.1-rc1:
- arch/arm64 defconfig: clean (savedefconfig keeps CONFIG_MMC_SDHCI_BST
at its Kconfig-ordered position; no diff in the MMC_SDHCI section)
- arch/arm64/boot/dts/bst/bstc1200-cdcu1.0-adas_4c2g.dtb: builds clean
with W=1 and CHECK_DTBS=y (no new warnings)
- checkpatch.pl --strict: 0 errors, 0 warnings, 0 checks on both patches
[1] https://lore.kernel.org/lkml/20260123095342.272505-1-yangzh0906@thundersoft.com/
[2] https://lore.kernel.org/lkml/CAPDyKFrcXFAiYouOpjDx3NN-xWACU9jAzEfTU2m_-yvQ9SpC_A@mail.gmail.com/
[3] https://lore.kernel.org/lkml/12058c14-67c7-4b43-bbbc-ef0ccb813e61@kernel.org/
[4] https://lore.kernel.org/lkml/20260417.164709-gordon.ge@bst.ai/
[5] https://lore.kernel.org/lkml/20260417.163754-gordon.ge@bst.ai/
[6] https://lore.kernel.org/lkml/20260310091211.4171307-1-yangzh0906@thundersoft.com/
Albert Yang (2):
arm64: dts: bst: enable eMMC controller in C1200 CDCU1.0 board
arm64: defconfig: enable BST SDHCI controller
.../dts/bst/bstc1200-cdcu1.0-adas_4c2g.dts | 19 +++++++++++++++++++
arch/arm64/boot/dts/bst/bstc1200.dtsi | 18 ++++++++++++++++++
arch/arm64/configs/defconfig | 1 +
3 files changed, 38 insertions(+)
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
--
2.43.0
^ permalink raw reply
* [PATCH v4 0/3] Enforce host page-size alignment for shared buffers
From: Aneesh Kumar K.V (Arm) @ 2026-04-27 6:31 UTC (permalink / raw)
To: linux-kernel, iommu, linux-coco, linux-arm-kernel, kvmarm
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Jason Gunthorpe,
Marc Zyngier, Marek Szyprowski, Robin Murphy, Steven Price,
Suzuki K Poulose, Thomas Gleixner, Will Deacon
Hi all,
This patch series addresses alignment requirements for buffers shared between
private-memory guests and the host.
When running private-memory guests, the guest kernel must apply additional
constraints when allocating buffers that are shared with the hypervisor. These
shared buffers are also accessed by the host kernel and therefore must be
aligned to the host’s page size.
Architectures such as Arm can tolerate realm physical address space PFNs being
mapped as shared memory, as incorrect accesses are detected and reported as GPC
faults. However, relying on this mechanism alone is unsafe and can still lead to
kernel crashes.
This is particularly likely when guest_memfd allocations are mmapped and
accessed from userspace. Once exposed to userspace, it is not possible to
guarantee that applications will only access the intended 4K shared region
rather than the full 64K page mapped into their address space. Such userspace
addresses may also be passed back into the kernel and accessed via the linear
map, potentially resulting in a GPC fault and a kernel crash.
To address this, the series introduces a new helpers,
mem_decrypt_granule_size() and mem_decrypt_align(), which allows callers to
enforce the required alignment for shared buffers.
Changes from v3:
https://lore.kernel.org/all/20260309102625.2315725-1-aneesh.kumar@kernel.org
* Fix build error reported by kernel test robot <lkp@intel.com>
Changes from v2:
https://lore.kernel.org/all/20251221160920.297689-1-aneesh.kumar@kernel.org
* Rebase to latest kernel
* Consider swiotlb always decrypted and don't align when allocating from swiotlb.
Changes from v1:
* Rename the helper to mem_encrypt_align
* Improve the commit message
* Handle DMA allocations from contiguous memory
* Handle DMA allocations from the pool
* swiotlb is still considered unencrypted. Support for an encrypted swiotlb pool
is left as TODO and is independent of this series.
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Jason Gunthorpe <jgg@ziepe.ca>
Cc: Marc Zyngier <maz@kernel.org>
Cc: Marek Szyprowski <m.szyprowski@samsung.com>
Cc: Robin Murphy <robin.murphy@arm.com>
Cc: Steven Price <steven.price@arm.com>
Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
Cc: Thomas Gleixner <tglx@kernel.org>
Cc: Will Deacon <will@kernel.org>
Aneesh Kumar K.V (Arm) (3):
dma-direct: swiotlb: handle swiotlb alloc/free outside
__dma_direct_alloc_pages
swiotlb: dma: its: Enforce host page-size alignment for shared buffers
coco: guest: arm64: Query host IPA-change alignment via RHI
arch/arm64/include/asm/mem_encrypt.h | 3 ++
arch/arm64/include/asm/rhi.h | 24 ++++++++++++
arch/arm64/include/asm/rsi.h | 2 +
arch/arm64/include/asm/rsi_cmds.h | 10 +++++
arch/arm64/include/asm/rsi_smc.h | 7 ++++
arch/arm64/kernel/Makefile | 2 +-
arch/arm64/kernel/rhi.c | 54 ++++++++++++++++++++++++++
arch/arm64/kernel/rsi.c | 13 +++++++
arch/arm64/mm/mem_encrypt.c | 27 +++++++++++--
drivers/irqchip/irq-gic-v3-its.c | 20 ++++++----
include/linux/mem_encrypt.h | 14 +++++++
kernel/dma/contiguous.c | 10 +++++
kernel/dma/direct.c | 58 ++++++++++++++++++++++++----
kernel/dma/pool.c | 4 +-
kernel/dma/swiotlb.c | 21 ++++++----
15 files changed, 240 insertions(+), 29 deletions(-)
create mode 100644 arch/arm64/include/asm/rhi.h
create mode 100644 arch/arm64/kernel/rhi.c
--
2.43.0
^ permalink raw reply
* [PATCH v4 1/3] dma-direct: swiotlb: handle swiotlb alloc/free outside __dma_direct_alloc_pages
From: Aneesh Kumar K.V (Arm) @ 2026-04-27 6:31 UTC (permalink / raw)
To: linux-kernel, iommu, linux-coco, linux-arm-kernel, kvmarm
Cc: Aneesh Kumar K.V (Arm), Catalin Marinas, Jason Gunthorpe,
Marc Zyngier, Marek Szyprowski, Robin Murphy, Steven Price,
Suzuki K Poulose, Thomas Gleixner, Will Deacon
In-Reply-To: <20260427063108.909019-1-aneesh.kumar@kernel.org>
Move swiotlb allocation out of __dma_direct_alloc_pages() and handle it in
dma_direct_alloc() / dma_direct_alloc_pages().
This is needed for follow-up changes that align shared decrypted buffers to
hypervisor page size. swiotlb pool memory is decrypted as a whole and does
not need per-allocation alignment handling.
swiotlb backing pages are already mapped decrypted by
swiotlb_update_mem_attributes() and rmem_swiotlb_device_init(), so
dma-direct should not call dma_set_decrypted() on allocation nor
dma_set_encrypted() on free for swiotlb-backed memory.
Update alloc/free paths to detect swiotlb-backed pages and skip
encrypt/decrypt transitions for those paths. Keep the existing highmem
rejection in dma_direct_alloc_pages() for swiotlb allocations.
Only for "restricted-dma-pool", we currently set `for_alloc = true`, while
rmem_swiotlb_device_init() decrypts the whole pool up front. This pool is
typically used together with "shared-dma-pool", where the shared region is
accessed after remap/ioremap and the returned address is suitable for
decrypted memory access. So existing code paths remain valid.
Signed-off-by: Aneesh Kumar K.V (Arm) <aneesh.kumar@kernel.org>
---
kernel/dma/direct.c | 44 +++++++++++++++++++++++++++++++++++++-------
1 file changed, 37 insertions(+), 7 deletions(-)
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 8f43a930716d..c2a43e4ef902 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -125,9 +125,6 @@ static struct page *__dma_direct_alloc_pages(struct device *dev, size_t size,
WARN_ON_ONCE(!PAGE_ALIGNED(size));
- if (is_swiotlb_for_alloc(dev))
- return dma_direct_alloc_swiotlb(dev, size);
-
gfp |= dma_direct_optimal_gfp_mask(dev, &phys_limit);
page = dma_alloc_contiguous(dev, size, gfp);
if (page) {
@@ -204,6 +201,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,
dma_addr_t *dma_handle, gfp_t gfp, unsigned long attrs)
{
bool remap = false, set_uncached = false;
+ bool mark_mem_decrypt = true;
struct page *page;
void *ret;
@@ -250,11 +248,21 @@ void *dma_direct_alloc(struct device *dev, size_t size,
dma_direct_use_pool(dev, gfp))
return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
+ if (is_swiotlb_for_alloc(dev)) {
+ page = dma_direct_alloc_swiotlb(dev, size);
+ if (page) {
+ mark_mem_decrypt = false;
+ goto setup_page;
+ }
+ return NULL;
+ }
+
/* we always manually zero the memory once we are done */
page = __dma_direct_alloc_pages(dev, size, gfp & ~__GFP_ZERO, true);
if (!page)
return NULL;
+setup_page:
/*
* dma_alloc_contiguous can return highmem pages depending on a
* combination the cma= arguments and per-arch setup. These need to be
@@ -281,7 +289,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,
goto out_free_pages;
} else {
ret = page_address(page);
- if (dma_set_decrypted(dev, ret, size))
+ if (mark_mem_decrypt && dma_set_decrypted(dev, ret, size))
goto out_leak_pages;
}
@@ -298,7 +306,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,
return ret;
out_encrypt_pages:
- if (dma_set_encrypted(dev, page_address(page), size))
+ if (mark_mem_decrypt && dma_set_encrypted(dev, page_address(page), size))
return NULL;
out_free_pages:
__dma_direct_free_pages(dev, page, size);
@@ -310,6 +318,7 @@ void *dma_direct_alloc(struct device *dev, size_t size,
void dma_direct_free(struct device *dev, size_t size,
void *cpu_addr, dma_addr_t dma_addr, unsigned long attrs)
{
+ bool mark_mem_encrypted = true;
unsigned int page_order = get_order(size);
if ((attrs & DMA_ATTR_NO_KERNEL_MAPPING) &&
@@ -338,12 +347,15 @@ void dma_direct_free(struct device *dev, size_t size,
dma_free_from_pool(dev, cpu_addr, PAGE_ALIGN(size)))
return;
+ if (swiotlb_find_pool(dev, dma_to_phys(dev, dma_addr)))
+ mark_mem_encrypted = false;
+
if (is_vmalloc_addr(cpu_addr)) {
vunmap(cpu_addr);
} else {
if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_CLEAR_UNCACHED))
arch_dma_clear_uncached(cpu_addr, size);
- if (dma_set_encrypted(dev, cpu_addr, size))
+ if (mark_mem_encrypted && dma_set_encrypted(dev, cpu_addr, size))
return;
}
@@ -359,6 +371,19 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
if (force_dma_unencrypted(dev) && dma_direct_use_pool(dev, gfp))
return dma_direct_alloc_from_pool(dev, size, dma_handle, gfp);
+ if (is_swiotlb_for_alloc(dev)) {
+ page = dma_direct_alloc_swiotlb(dev, size);
+ if (!page)
+ return NULL;
+
+ if (PageHighMem(page)) {
+ swiotlb_free(dev, page, size);
+ return NULL;
+ }
+ ret = page_address(page);
+ goto setup_page;
+ }
+
page = __dma_direct_alloc_pages(dev, size, gfp, false);
if (!page)
return NULL;
@@ -366,6 +391,7 @@ struct page *dma_direct_alloc_pages(struct device *dev, size_t size,
ret = page_address(page);
if (dma_set_decrypted(dev, ret, size))
goto out_leak_pages;
+setup_page:
memset(ret, 0, size);
*dma_handle = phys_to_dma_direct(dev, page_to_phys(page));
return page;
@@ -378,13 +404,17 @@ void dma_direct_free_pages(struct device *dev, size_t size,
enum dma_data_direction dir)
{
void *vaddr = page_address(page);
+ bool mark_mem_encrypted = true;
/* If cpu_addr is not from an atomic pool, dma_free_from_pool() fails */
if (IS_ENABLED(CONFIG_DMA_COHERENT_POOL) &&
dma_free_from_pool(dev, vaddr, size))
return;
- if (dma_set_encrypted(dev, vaddr, size))
+ if (swiotlb_find_pool(dev, page_to_phys(page)))
+ mark_mem_encrypted = false;
+
+ if (mark_mem_encrypted && dma_set_encrypted(dev, vaddr, size))
return;
__dma_direct_free_pages(dev, page, size);
}
--
2.43.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox