From rppt at kernel.org  Mon Jun  1 00:13:49 2026
From: rppt at kernel.org (Mike Rapoport)
Date: Mon, 1 Jun 2026 10:13:49 +0300
Subject: [PATCH] riscv: mm: Call mark_new_valid_map() after hotplugging
 vmemmap
In-Reply-To: <20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16@iscas.ac.cn>
References: <20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16@iscas.ac.cn>
Message-ID: <ah0xLeD1_6oRKDkx@kernel.org>

Hi,

On Mon, May 25, 2026 at 12:23:29PM +0800, Vivian Wang wrote:
> section_activate() creates new mappings in the vmemmap range without
> flushing TLB, which may cause faults on some RISC-V implementations that
> cache non-present PTEs and crashes.
> 
> This seems to be most easily reproduced with DEBUG_VM=y and
> PAGE_POISONING=y, which causes these newly mapped struct pages to be
> poisoned i.e. written to immediately after mapping.
> 
> Add a hook vmemmap_populate_finalize() in __populate_section_memmap(),
> and implement it as calling mark_new_valid_map() on RISC-V, which
> arranges for the exception handler to deal with these faults if they
> happen.
> 
> Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
> ---
> I'm not sure if this is the right place to add this hook. I didn't add
> it to vmemmap_populate because it doesn't seem to be called in all
> cases. Please advise.

Indeed it looks like we'd need a new hook to let architectures run
post-populate actions.

The explanation that says why a new hook is needed should be a part of the
changelog.
 
> Depends on my earlier kfence fixes for mark_new_valid_map() [1].
> 
> Found while testing AMD_HSA/ZONE_DEVICE on SpacemiT K3. Using
> ZONE_DEVICE requires another fix [2].
> 
> [1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn
> [2]: https://lore.kernel.org/linux-riscv/20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd at iscas.ac.cn
> ---
>  arch/riscv/mm/init.c | 6 ++++++
>  include/linux/mm.h   | 1 +
>  mm/sparse-vmemmap.c  | 6 ++++++
>  3 files changed, 13 insertions(+)
> 
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 706f43523935..cf9ae4099f82 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -1360,6 +1360,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
>  	 */
>  	return vmemmap_populate_hugepages(start, end, node, altmap);
>  }
> +
> +void __meminit vmemmap_populate_finalize(void)
> +{
> +	/* Avoid faults on cached non-present TLB entries. */
> +	mark_new_valid_map();
> +}
>  #endif
>  
>  #if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
> diff --git a/include/linux/mm.h b/include/linux/mm.h
> index 0b776907152e..65deccbd7e31 100644
> --- a/include/linux/mm.h
> +++ b/include/linux/mm.h
> @@ -4882,6 +4882,7 @@ int vmemmap_populate_hugepages(unsigned long start, unsigned long end,
>  			       int node, struct vmem_altmap *altmap);
>  int vmemmap_populate(unsigned long start, unsigned long end, int node,
>  		struct vmem_altmap *altmap);
> +void vmemmap_populate_finalize(void);
>  int vmemmap_populate_hvo(unsigned long start, unsigned long end,
>  			 unsigned int order, struct zone *zone,
>  			 unsigned long headsize);
> diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
> index 6eadb9d116e4..2b860d2b1703 100644
> --- a/mm/sparse-vmemmap.c
> +++ b/mm/sparse-vmemmap.c
> @@ -544,6 +544,10 @@ static int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn,
>  
>  #endif
>  
> +void __weak __meminit vmemmap_populate_finalize(void)
> +{
> +}
> +

The existing hooks in sparse-vmemmap use #ifdef <hook> rather than __weak
functions. Take a look at vmemmap_can_optimize() and
vmemmap_populate_compound_pages().

Let's keep it consistent.

>  struct page * __meminit __populate_section_memmap(unsigned long pfn,
>  		unsigned long nr_pages, int nid, struct vmem_altmap *altmap,
>  		struct dev_pagemap *pgmap)
> @@ -561,6 +565,8 @@ struct page * __meminit __populate_section_memmap(unsigned long pfn,
>  	else
>  		r = vmemmap_populate(start, end, nid, altmap);
>  
> +	vmemmap_populate_finalize();
> +
>  	if (r < 0)
>  		return NULL;
>  
> 
> ---
> base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
> change-id: 20260525-mark-after-vmemmap-populate-68bd790839c9
> prerequisite-message-id: <20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn>
> prerequisite-patch-id: fdc42f2647e21d111f44a6532887a6705cd470a9
> prerequisite-patch-id: 096fa339c84c36643ae4311fd8362dc63e23d950
> prerequisite-patch-id: 305c876a5f4a23a840a8142aea79b796ed297545
> prerequisite-patch-id: d78cb55d6a616b1170f06a401c8fd44acd11e5d5
> prerequisite-patch-id: b02b4a76e94f3e2821291d4c23b46f6e5ecf5203
> 
> Best regards,
> --  
> Vivian Wang <wangruikang at iscas.ac.cn>
> 

-- 
Sincerely yours,
Mike.


From namcao at linutronix.de  Mon Jun  1 01:26:40 2026
From: namcao at linutronix.de (Nam Cao)
Date: Mon, 01 Jun 2026 10:26:40 +0200
Subject: [PATCH] riscv: Remove support for XIP kernel
In-Reply-To: <05290c17-d55f-4e60-a77e-c36c3f14a89a@redhat.com>
References: <CABe3_aH6jYyoC=Jx91qATP2kOoY42NUtesyZpGbWGoQTw75OAA@mail.gmail.com>
 <05290c17-d55f-4e60-a77e-c36c3f14a89a@redhat.com>
Message-ID: <87pl2awtrz.fsf@yellow.woof>

Jesse Taube-Perrotta <jtaubepe at redhat.com> writes:
> TLDR: Is re-adding XIP to no-mmu rv32 a possibility

Paul explained the requirements to keep XIP:

https://lore.kernel.org/linux-riscv/609b889a-8bb1-d2b5-8de6-ddeec27cac04 at kernel.org/

Nam


From wangruikang at iscas.ac.cn  Mon Jun  1 01:26:33 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Mon, 1 Jun 2026 16:26:33 +0800
Subject: [PATCH] riscv: mm: Call mark_new_valid_map() after hotplugging
 vmemmap
In-Reply-To: <ah0xLeD1_6oRKDkx@kernel.org>
References: <20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16@iscas.ac.cn>
 <ah0xLeD1_6oRKDkx@kernel.org>
Message-ID: <48855978-6834-4427-ae55-e05650b1ea89@iscas.ac.cn>

Hi Mike,

Thanks for your review.

On 6/1/26 15:13, Mike Rapoport wrote:
> Hi,
>
> On Mon, May 25, 2026 at 12:23:29PM +0800, Vivian Wang wrote:
>> section_activate() creates new mappings in the vmemmap range without
>> flushing TLB, which may cause faults on some RISC-V implementations that
>> cache non-present PTEs and crashes.
>>
>> This seems to be most easily reproduced with DEBUG_VM=y and
>> PAGE_POISONING=y, which causes these newly mapped struct pages to be
>> poisoned i.e. written to immediately after mapping.
>>
>> Add a hook vmemmap_populate_finalize() in __populate_section_memmap(),
>> and implement it as calling mark_new_valid_map() on RISC-V, which
>> arranges for the exception handler to deal with these faults if they
>> happen.
>>
>> Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
>> ---
>> I'm not sure if this is the right place to add this hook. I didn't add
>> it to vmemmap_populate because it doesn't seem to be called in all
>> cases. Please advise.
> Indeed it looks like we'd need a new hook to let architectures run
> post-populate actions.
>
> The explanation that says why a new hook is needed should be a part of the
> changelog.
>  

I will reorganize this in v2.

>> Depends on my earlier kfence fixes for mark_new_valid_map() [1].
>>
>> Found while testing AMD_HSA/ZONE_DEVICE on SpacemiT K3. Using
>> ZONE_DEVICE requires another fix [2].
>>
>> [1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn
>> [2]: https://lore.kernel.org/linux-riscv/20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd at iscas.ac.cn
>> ---
>>  arch/riscv/mm/init.c | 6 ++++++
>>  include/linux/mm.h   | 1 +
>>  mm/sparse-vmemmap.c  | 6 ++++++
>>  3 files changed, 13 insertions(+)

[...]

>> diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
>> index 6eadb9d116e4..2b860d2b1703 100644
>> --- a/mm/sparse-vmemmap.c
>> +++ b/mm/sparse-vmemmap.c
>> @@ -544,6 +544,10 @@ static int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn,
>>  
>>  #endif
>>  
>> +void __weak __meminit vmemmap_populate_finalize(void)
>> +{
>> +}
>> +
> The existing hooks in sparse-vmemmap use #ifdef <hook> rather than __weak
> functions. Take a look at vmemmap_can_optimize() and
> vmemmap_populate_compound_pages().
>
> Let's keep it consistent.

I wasn't sure since it seems that both styles exist in this file.

I will change it to #ifdef in v2, as that seems to be preferable.

Vivian "dramforever" Wang

> [...]



From anup at brainfault.org  Mon Jun  1 01:28:38 2026
From: anup at brainfault.org (Anup Patel)
Date: Mon, 1 Jun 2026 13:58:38 +0530
Subject: [PATCH] RISC-V: KVM: Use flexible array for APLIC IRQ state
In-Reply-To: <20260511032144.361520-1-rosenp@gmail.com>
References: <20260511032144.361520-1-rosenp@gmail.com>
Message-ID: <CAAhSdy34CXr4cky4cpg6eVV3FdwHvnR=pJqK=Y+ZsLLx0jL1_g@mail.gmail.com>

On Mon, May 11, 2026 at 8:52?AM Rosen Penev <rosenp at gmail.com> wrote:
>
> Store the per-source APLIC IRQ state in the APLIC allocation instead
> of allocating it separately.
>
> This ties the IRQ state lifetime directly to the APLIC state, removes a
> separate allocation failure path, and lets __counted_by() describe the
> array bounds.
>
> Assisted-by: Codex:GPT-5.5
> Signed-off-by: Rosen Penev <rosenp at gmail.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this patch for Linux-7.2

Thanks,
Anup


> ---
>  arch/riscv/kvm/aia_aplic.c | 15 +++------------
>  1 file changed, 3 insertions(+), 12 deletions(-)
>
> diff --git a/arch/riscv/kvm/aia_aplic.c b/arch/riscv/kvm/aia_aplic.c
> index 3464f3351df7..748107c347d9 100644
> --- a/arch/riscv/kvm/aia_aplic.c
> +++ b/arch/riscv/kvm/aia_aplic.c
> @@ -35,7 +35,7 @@ struct aplic {
>
>         u32 nr_irqs;
>         u32 nr_words;
> -       struct aplic_irq *irqs;
> +       struct aplic_irq irqs[] __counted_by(nr_irqs);
>  };
>
>  static u32 aplic_read_sourcecfg(struct aplic *aplic, u32 irq)
> @@ -581,7 +581,7 @@ int kvm_riscv_aia_aplic_init(struct kvm *kvm)
>                 return 0;
>
>         /* Allocate APLIC global state */
> -       aplic = kzalloc_obj(*aplic);
> +       aplic = kzalloc_flex(*aplic, irqs, kvm->arch.aia.nr_sources + 1);
>         if (!aplic)
>                 return -ENOMEM;
>         kvm->arch.aia.aplic_state = aplic;
> @@ -589,11 +589,6 @@ int kvm_riscv_aia_aplic_init(struct kvm *kvm)
>         /* Setup APLIC IRQs */
>         aplic->nr_irqs = kvm->arch.aia.nr_sources + 1;
>         aplic->nr_words = DIV_ROUND_UP(aplic->nr_irqs, 32);
> -       aplic->irqs = kzalloc_objs(*aplic->irqs, aplic->nr_irqs);
> -       if (!aplic->irqs) {
> -               ret = -ENOMEM;
> -               goto fail_free_aplic;
> -       }
>         for (i = 0; i < aplic->nr_irqs; i++)
>                 raw_spin_lock_init(&aplic->irqs[i].lock);
>
> @@ -606,7 +601,7 @@ int kvm_riscv_aia_aplic_init(struct kvm *kvm)
>                                       &aplic->iodev);
>         mutex_unlock(&kvm->slots_lock);
>         if (ret)
> -               goto fail_free_aplic_irqs;
> +               goto fail_free_aplic;
>
>         /* Setup default IRQ routing */
>         ret = kvm_riscv_setup_default_irq_routing(kvm, aplic->nr_irqs);
> @@ -619,8 +614,6 @@ int kvm_riscv_aia_aplic_init(struct kvm *kvm)
>         mutex_lock(&kvm->slots_lock);
>         kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &aplic->iodev);
>         mutex_unlock(&kvm->slots_lock);
> -fail_free_aplic_irqs:
> -       kfree(aplic->irqs);
>  fail_free_aplic:
>         kvm->arch.aia.aplic_state = NULL;
>         kfree(aplic);
> @@ -638,8 +631,6 @@ void kvm_riscv_aia_aplic_cleanup(struct kvm *kvm)
>         kvm_io_bus_unregister_dev(kvm, KVM_MMIO_BUS, &aplic->iodev);
>         mutex_unlock(&kvm->slots_lock);
>
> -       kfree(aplic->irqs);
> -
>         kvm->arch.aia.aplic_state = NULL;
>         kfree(aplic);
>  }
> --
> 2.54.0
>


From anup at brainfault.org  Mon Jun  1 01:28:51 2026
From: anup at brainfault.org (Anup Patel)
Date: Mon, 1 Jun 2026 13:58:51 +0530
Subject: [PATCH v2 03/10] riscv: Standardize extension capitalization
In-Reply-To: <20260511-rva23u64-hwprobe-v2-v2-3-21c5a544f1dc@riscstar.com>
References: <20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc@riscstar.com> <20260511-rva23u64-hwprobe-v2-v2-3-21c5a544f1dc@riscstar.com>
Message-ID: <CAAhSdy0pHPAMRRR-Mri735zLu3ymr=ePQ7gA6zZ11BkHEXj+AA@mail.gmail.com>

On Mon, May 11, 2026 at 7:06?PM Guodong Xu <guodong at riscstar.com> wrote:
>
> From: Charlie Jenkins <charlie at rivosinc.com>
>
> The base extensions are often lowercase and were written as lowercase in
> hwcap, but other references to these extensions in the kernel are
> uppercase. Standardize the case to make it easier to handle macro
> expansion.
>
> Signed-off-by: Charlie Jenkins <thecharlesjenkins at gmail.com>
> [Apply KVM_ISA_EXT_ARR(), fixup all KVM use.]
> Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
> Signed-off-by: Guodong Xu <guodong at riscstar.com>

LGTM.

Acked-by: Anup Patel <anup at brainfault.org>
Reviewed-by: Anup Patel <anup at brainfault.org>

@Paul, This patch is independent of other changes
in this series. If you are okay then I can take this single
patch through KVM RISC-V tree.

Regards,
Anup



>
> ---
> v2:
> - Rebased onto v7.1-rc2.
> - KVM_ISA_EXT_ARR() consolidation moved to its new upstream location
>   (kvm/isa.c); host-side checks now use kvm_riscv_isa_check_host().
> ---
>  arch/riscv/include/asm/hwcap.h     | 18 +++++++++---------
>  arch/riscv/include/asm/switch_to.h |  4 ++--
>  arch/riscv/kernel/cpufeature.c     | 32 ++++++++++++++++----------------
>  arch/riscv/kernel/sys_hwprobe.c    |  4 ++--
>  arch/riscv/kvm/isa.c               | 16 ++++++++--------
>  arch/riscv/kvm/main.c              |  2 +-
>  arch/riscv/kvm/vcpu_fp.c           | 20 ++++++++++----------
>  arch/riscv/kvm/vcpu_onereg.c       |  6 +++---
>  arch/riscv/kvm/vcpu_vector.c       | 10 +++++-----
>  9 files changed, 56 insertions(+), 56 deletions(-)
>
> diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
> index 7ef8e5f55c8dc..44bf8c7d8acc5 100644
> --- a/arch/riscv/include/asm/hwcap.h
> +++ b/arch/riscv/include/asm/hwcap.h
> @@ -10,15 +10,15 @@
>
>  #include <uapi/asm/hwcap.h>
>
> -#define RISCV_ISA_EXT_a                ('a' - 'a')
> -#define RISCV_ISA_EXT_c                ('c' - 'a')
> -#define RISCV_ISA_EXT_d                ('d' - 'a')
> -#define RISCV_ISA_EXT_f                ('f' - 'a')
> -#define RISCV_ISA_EXT_h                ('h' - 'a')
> -#define RISCV_ISA_EXT_i                ('i' - 'a')
> -#define RISCV_ISA_EXT_m                ('m' - 'a')
> -#define RISCV_ISA_EXT_q                ('q' - 'a')
> -#define RISCV_ISA_EXT_v                ('v' - 'a')
> +#define RISCV_ISA_EXT_A                ('a' - 'a')
> +#define RISCV_ISA_EXT_C                ('c' - 'a')
> +#define RISCV_ISA_EXT_D                ('d' - 'a')
> +#define RISCV_ISA_EXT_F                ('f' - 'a')
> +#define RISCV_ISA_EXT_H                ('h' - 'a')
> +#define RISCV_ISA_EXT_I                ('i' - 'a')
> +#define RISCV_ISA_EXT_M                ('m' - 'a')
> +#define RISCV_ISA_EXT_Q                ('q' - 'a')
> +#define RISCV_ISA_EXT_V                ('v' - 'a')
>
>  /*
>   * These macros represent the logical IDs of each multi-letter RISC-V ISA
> diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
> index 0e71eb82f920c..ff35a4d04f85a 100644
> --- a/arch/riscv/include/asm/switch_to.h
> +++ b/arch/riscv/include/asm/switch_to.h
> @@ -60,8 +60,8 @@ static inline void __switch_to_fpu(struct task_struct *prev,
>
>  static __always_inline bool has_fpu(void)
>  {
> -       return riscv_has_extension_likely(RISCV_ISA_EXT_f) ||
> -               riscv_has_extension_likely(RISCV_ISA_EXT_d);
> +       return riscv_has_extension_likely(RISCV_ISA_EXT_F) ||
> +               riscv_has_extension_likely(RISCV_ISA_EXT_D);
>  }
>  #else
>  static __always_inline bool has_fpu(void) { return false; }
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 1734f9a4c2fd7..5cf463570229d 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
>  static int riscv_ext_f_depends(const struct riscv_isa_ext_data *data,
>                                const unsigned long *isa_bitmap)
>  {
> -       if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f))
> +       if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_F))
>                 return 0;
>
>         return -EPROBE_DEFER;
> @@ -146,7 +146,7 @@ static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data,
>          * Due to extension ordering, d is checked before f, so no deferral
>          * is required.
>          */
> -       if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d)) {
> +       if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D)) {
>                 pr_warn_once("This kernel does not support systems with F but not D\n");
>                 return -EINVAL;
>         }
> @@ -189,7 +189,7 @@ static int riscv_ext_vector_float_validate(const struct riscv_isa_ext_data *data
>          * Since this function validates vector only, and v/Zve* are probed
>          * after f/d, there's no need for a deferral here.
>          */
> -       if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d))
> +       if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D))
>                 return -EINVAL;
>
>         return 0;
> @@ -224,7 +224,7 @@ static int riscv_ext_zcd_validate(const struct riscv_isa_ext_data *data,
>                                   const unsigned long *isa_bitmap)
>  {
>         if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) &&
> -           __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d))
> +           __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D))
>                 return 0;
>
>         return -EPROBE_DEFER;
> @@ -237,7 +237,7 @@ static int riscv_ext_zcf_validate(const struct riscv_isa_ext_data *data,
>                 return -EINVAL;
>
>         if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) &&
> -           __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f))
> +           __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_F))
>                 return 0;
>
>         return -EPROBE_DEFER;
> @@ -490,15 +490,15 @@ static const unsigned int riscv_c_exts[] = {
>   * New entries to this struct should follow the ordering rules described above.
>   */
>  const struct riscv_isa_ext_data riscv_isa_ext[] = {
> -       __RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_i),
> -       __RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_m),
> -       __RISCV_ISA_EXT_SUPERSET(a, RISCV_ISA_EXT_a, riscv_a_exts),
> -       __RISCV_ISA_EXT_DATA_VALIDATE(f, RISCV_ISA_EXT_f, riscv_ext_f_validate),
> -       __RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_d, riscv_ext_d_validate),
> -       __RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
> -       __RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts),
> -       __RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate),
> -       __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
> +       __RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_I),
> +       __RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_M),
> +       __RISCV_ISA_EXT_SUPERSET(a, RISCV_ISA_EXT_A, riscv_a_exts),
> +       __RISCV_ISA_EXT_DATA_VALIDATE(f, RISCV_ISA_EXT_F, riscv_ext_f_validate),
> +       __RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_D, riscv_ext_d_validate),
> +       __RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_Q),
> +       __RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_C, riscv_c_exts),
> +       __RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate),
> +       __RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H),
>         __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
>         __RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
>         __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
> @@ -897,8 +897,8 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
>                  * marchid.
>                  */
>                 if (acpi_disabled && boot_vendorid == THEAD_VENDOR_ID && boot_archid == 0x0) {
> -                       this_hwcap &= ~isa2hwcap[RISCV_ISA_EXT_v];
> -                       clear_bit(RISCV_ISA_EXT_v, source_isa);
> +                       this_hwcap &= ~isa2hwcap[RISCV_ISA_EXT_V];
> +                       clear_bit(RISCV_ISA_EXT_V, source_isa);
>                 }
>
>                 riscv_resolve_isa(source_isa, isainfo->isa, &this_hwcap, isa2hwcap);
> diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
> index 1659d31fd288f..f8f68ba781b45 100644
> --- a/arch/riscv/kernel/sys_hwprobe.c
> +++ b/arch/riscv/kernel/sys_hwprobe.c
> @@ -88,10 +88,10 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair,
>         if (has_fpu())
>                 pair->value |= RISCV_HWPROBE_IMA_FD;
>
> -       if (riscv_isa_extension_available(NULL, c))
> +       if (riscv_isa_extension_available(NULL, C))
>                 pair->value |= RISCV_HWPROBE_IMA_C;
>
> -       if (has_vector() && riscv_isa_extension_available(NULL, v))
> +       if (has_vector() && riscv_isa_extension_available(NULL, V))
>                 pair->value |= RISCV_HWPROBE_IMA_V;
>
>         /*
> diff --git a/arch/riscv/kvm/isa.c b/arch/riscv/kvm/isa.c
> index 1132d909cc25c..94077117d1136 100644
> --- a/arch/riscv/kvm/isa.c
> +++ b/arch/riscv/kvm/isa.c
> @@ -17,14 +17,14 @@
>  /* Mapping between KVM ISA Extension ID & guest ISA extension ID */
>  static const unsigned long kvm_isa_ext_arr[] = {
>         /* Single letter extensions (alphabetically sorted) */
> -       [KVM_RISCV_ISA_EXT_A] = RISCV_ISA_EXT_a,
> -       [KVM_RISCV_ISA_EXT_C] = RISCV_ISA_EXT_c,
> -       [KVM_RISCV_ISA_EXT_D] = RISCV_ISA_EXT_d,
> -       [KVM_RISCV_ISA_EXT_F] = RISCV_ISA_EXT_f,
> -       [KVM_RISCV_ISA_EXT_H] = RISCV_ISA_EXT_h,
> -       [KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i,
> -       [KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m,
> -       [KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v,
> +       KVM_ISA_EXT_ARR(A),
> +       KVM_ISA_EXT_ARR(C),
> +       KVM_ISA_EXT_ARR(D),
> +       KVM_ISA_EXT_ARR(F),
> +       KVM_ISA_EXT_ARR(H),
> +       KVM_ISA_EXT_ARR(I),
> +       KVM_ISA_EXT_ARR(M),
> +       KVM_ISA_EXT_ARR(V),
>         /* Multi letter extensions (alphabetically sorted) */
>         KVM_ISA_EXT_ARR(SMNPM),
>         KVM_ISA_EXT_ARR(SMSTATEEN),
> diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c
> index cb8a65273c1f0..70640701310c8 100644
> --- a/arch/riscv/kvm/main.c
> +++ b/arch/riscv/kvm/main.c
> @@ -85,7 +85,7 @@ static int __init riscv_kvm_init(void)
>         char slist[64];
>         const char *str;
>
> -       if (!riscv_isa_extension_available(NULL, h)) {
> +       if (!riscv_isa_extension_available(NULL, H)) {
>                 kvm_info("hypervisor extension not available\n");
>                 return -ENODEV;
>         }
> diff --git a/arch/riscv/kvm/vcpu_fp.c b/arch/riscv/kvm/vcpu_fp.c
> index 6ad6df26a2fd4..bb11e6757d349 100644
> --- a/arch/riscv/kvm/vcpu_fp.c
> +++ b/arch/riscv/kvm/vcpu_fp.c
> @@ -21,8 +21,8 @@ void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu)
>         struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
>
>         cntx->sstatus &= ~SR_FS;
> -       if (riscv_isa_extension_available(vcpu->arch.isa, f) ||
> -           riscv_isa_extension_available(vcpu->arch.isa, d))
> +       if (riscv_isa_extension_available(vcpu->arch.isa, F) ||
> +           riscv_isa_extension_available(vcpu->arch.isa, D))
>                 cntx->sstatus |= SR_FS_INITIAL;
>         else
>                 cntx->sstatus |= SR_FS_OFF;
> @@ -38,9 +38,9 @@ void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx,
>                                   const unsigned long *isa)
>  {
>         if ((cntx->sstatus & SR_FS) == SR_FS_DIRTY) {
> -               if (riscv_isa_extension_available(isa, d))
> +               if (riscv_isa_extension_available(isa, D))
>                         __kvm_riscv_fp_d_save(cntx);
> -               else if (riscv_isa_extension_available(isa, f))
> +               else if (riscv_isa_extension_available(isa, F))
>                         __kvm_riscv_fp_f_save(cntx);
>                 kvm_riscv_vcpu_fp_clean(cntx);
>         }
> @@ -50,9 +50,9 @@ void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx,
>                                      const unsigned long *isa)
>  {
>         if ((cntx->sstatus & SR_FS) != SR_FS_OFF) {
> -               if (riscv_isa_extension_available(isa, d))
> +               if (riscv_isa_extension_available(isa, D))
>                         __kvm_riscv_fp_d_restore(cntx);
> -               else if (riscv_isa_extension_available(isa, f))
> +               else if (riscv_isa_extension_available(isa, F))
>                         __kvm_riscv_fp_f_restore(cntx);
>                 kvm_riscv_vcpu_fp_clean(cntx);
>         }
> @@ -89,7 +89,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu,
>         void *reg_val;
>
>         if ((rtype == KVM_REG_RISCV_FP_F) &&
> -           riscv_isa_extension_available(vcpu->arch.isa, f)) {
> +           riscv_isa_extension_available(vcpu->arch.isa, F)) {
>                 if (KVM_REG_SIZE(reg->id) != sizeof(u32))
>                         return -EINVAL;
>                 if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr))
> @@ -102,7 +102,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu,
>                 } else
>                         return -ENOENT;
>         } else if ((rtype == KVM_REG_RISCV_FP_D) &&
> -                  riscv_isa_extension_available(vcpu->arch.isa, d)) {
> +                  riscv_isa_extension_available(vcpu->arch.isa, D)) {
>                 if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) {
>                         if (KVM_REG_SIZE(reg->id) != sizeof(u32))
>                                 return -EINVAL;
> @@ -138,7 +138,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu,
>         void *reg_val;
>
>         if ((rtype == KVM_REG_RISCV_FP_F) &&
> -           riscv_isa_extension_available(vcpu->arch.isa, f)) {
> +           riscv_isa_extension_available(vcpu->arch.isa, F)) {
>                 if (KVM_REG_SIZE(reg->id) != sizeof(u32))
>                         return -EINVAL;
>                 if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr))
> @@ -151,7 +151,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu,
>                 } else
>                         return -ENOENT;
>         } else if ((rtype == KVM_REG_RISCV_FP_D) &&
> -                  riscv_isa_extension_available(vcpu->arch.isa, d)) {
> +                  riscv_isa_extension_available(vcpu->arch.isa, D)) {
>                 if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) {
>                         if (KVM_REG_SIZE(reg->id) != sizeof(u32))
>                                 return -EINVAL;
> diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
> index bb920e8923c93..5cc7ddd4aa276 100644
> --- a/arch/riscv/kvm/vcpu_onereg.c
> +++ b/arch/riscv/kvm/vcpu_onereg.c
> @@ -770,7 +770,7 @@ static inline unsigned long num_fp_f_regs(const struct kvm_vcpu *vcpu)
>  {
>         const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
>
> -       if (riscv_isa_extension_available(vcpu->arch.isa, f))
> +       if (riscv_isa_extension_available(vcpu->arch.isa, F))
>                 return sizeof(cntx->fp.f) / sizeof(u32);
>         else
>                 return 0;
> @@ -799,7 +799,7 @@ static inline unsigned long num_fp_d_regs(const struct kvm_vcpu *vcpu)
>  {
>         const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
>
> -       if (riscv_isa_extension_available(vcpu->arch.isa, d))
> +       if (riscv_isa_extension_available(vcpu->arch.isa, D))
>                 return sizeof(cntx->fp.d.f) / sizeof(u64) + 1;
>         else
>                 return 0;
> @@ -878,7 +878,7 @@ static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu)
>
>  static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu)
>  {
> -       if (!riscv_isa_extension_available(vcpu->arch.isa, v))
> +       if (!riscv_isa_extension_available(vcpu->arch.isa, V))
>                 return 0;
>
>         /* vstart, vl, vtype, vcsr, vlenb and 32 vector regs */
> diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
> index 62d2fb77bb9b9..f26108a4e601e 100644
> --- a/arch/riscv/kvm/vcpu_vector.c
> +++ b/arch/riscv/kvm/vcpu_vector.c
> @@ -26,7 +26,7 @@ void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu)
>
>         cntx->vector.vlenb = riscv_v_vsize / 32;
>
> -       if (riscv_isa_extension_available(isa, v)) {
> +       if (riscv_isa_extension_available(isa, V)) {
>                 cntx->sstatus |= SR_VS_INITIAL;
>                 WARN_ON(!cntx->vector.datap);
>                 memset(cntx->vector.datap, 0, riscv_v_vsize);
> @@ -45,7 +45,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
>                                       unsigned long *isa)
>  {
>         if ((cntx->sstatus & SR_VS) == SR_VS_DIRTY) {
> -               if (riscv_isa_extension_available(isa, v))
> +               if (riscv_isa_extension_available(isa, V))
>                         __kvm_riscv_vector_save(cntx);
>                 kvm_riscv_vcpu_vector_clean(cntx);
>         }
> @@ -55,7 +55,7 @@ void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
>                                          unsigned long *isa)
>  {
>         if ((cntx->sstatus & SR_VS) != SR_VS_OFF) {
> -               if (riscv_isa_extension_available(isa, v))
> +               if (riscv_isa_extension_available(isa, V))
>                         __kvm_riscv_vector_restore(cntx);
>                 kvm_riscv_vcpu_vector_clean(cntx);
>         }
> @@ -154,7 +154,7 @@ int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu,
>         void *reg_addr;
>         int rc;
>
> -       if (!riscv_isa_extension_available(isa, v))
> +       if (!riscv_isa_extension_available(isa, V))
>                 return -ENOENT;
>
>         rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, &reg_addr);
> @@ -180,7 +180,7 @@ int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu,
>         void *reg_addr;
>         int rc;
>
> -       if (!riscv_isa_extension_available(isa, v))
> +       if (!riscv_isa_extension_available(isa, V))
>                 return -ENOENT;
>
>         if (reg_num == KVM_REG_RISCV_VECTOR_CSR_REG(vlenb)) {
>
> --
> 2.43.0
>


From yongxuan.wang at sifive.com  Mon Jun  1 01:40:34 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 01:40:34 -0700
Subject: [PATCH v4 1/3] KVM: RISC-V: SBI FWFT: Fix stale feature exposure
 after runtime extension changes
In-Reply-To: <20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda@sifive.com>
Message-ID: <20260601-kvm-get_reg_list-v2-v4-1-c88abc81ebda@sifive.com>

Fix a bug where FWFT features could be incorrectly exposed to guests
after userspace disables their dependent ISA extensions at runtime.

The 'supported' field in kvm_sbi_fwft_config was set once during vCPU
initialization based on the initial hardware/extension availability.
However, when userspace subsequently disables ISA extensions via the KVM
ONE_REG interface, the 'supported' field was not updated. This caused
the following issues:
1. FWFT features would remain visible and accessible to guests even
   after their prerequisite ISA extensions were disabled
2. Guests could configure FWFT features that depend on disabled
   extensions, leading to undefined behavior
3. The static 'supported' flag and the dynamic supported() callback
   could disagree about feature availability

The fix introduces a two-layer checking mechanism:
1. Add an optional init() callback to the kvm_sbi_fwft_feature structure
   for features that require hardware probing during initialization. This
   separates the one-time hardware detection logic from the runtime
   availability check.
2. Add runtime checks in all FWFT-related functions that call
   feature->supported(vcpu) if the callback exists. This ensures feature
   availability is re-evaluated based on the current ISA extension state.

This approach maintains the cached 'supported' field for initialization-
time decisions while ensuring runtime availability is always determined
by the current vCPU configuration, not initialization-time snapshots.

Fixes: 6b72fd170592 ("RISC-V: KVM: add support for FWFT SBI extension")

Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
 arch/riscv/kvm/vcpu_sbi_fwft.c | 34 +++++++++++++++++++++++++++++++---
 1 file changed, 31 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index 2eab15339694..2ad269a21021 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -35,6 +35,16 @@ struct kvm_sbi_fwft_feature {
 	 */
 	bool (*supported)(struct kvm_vcpu *vcpu);
 
+	/**
+	 * @init: Probe and initialize the feature on the vcpu
+	 *
+	 * This callback is optional. If provided, it will be called during
+	 * vcpu initialization to probe the feature availability and perform
+	 * any necessary initialization. Returns true if the feature is supported
+	 * and initialized successfully, false otherwise.
+	 */
+	bool (*init)(struct kvm_vcpu *vcpu);
+
 	/**
 	 * @reset: Reset the feature value irrespective whether feature is supported or not
 	 *
@@ -137,13 +147,17 @@ static bool try_to_set_pmm(unsigned long value)
 
 static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu)
 {
-	struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
+	return riscv_isa_extension_available(vcpu->arch.isa, SMNPM);
+}
 
-	if (!riscv_isa_extension_available(vcpu->arch.isa, SMNPM))
-		return false;
+static bool kvm_sbi_fwft_pointer_masking_pmlen_init(struct kvm_vcpu *vcpu)
+{
+	struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
 
+	preempt_disable();
 	fwft->have_vs_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7);
 	fwft->have_vs_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16);
+	preempt_enable();
 
 	return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16;
 }
@@ -231,6 +245,7 @@ static const struct kvm_sbi_fwft_feature features[] = {
 		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pointer_masking.enable) /
 				 sizeof(unsigned long),
 		.supported = kvm_sbi_fwft_pointer_masking_pmlen_supported,
+		.init = kvm_sbi_fwft_pointer_masking_pmlen_init,
 		.reset = kvm_sbi_fwft_reset_pointer_masking_pmlen,
 		.set = kvm_sbi_fwft_set_pointer_masking_pmlen,
 		.get = kvm_sbi_fwft_get_pointer_masking_pmlen,
@@ -281,6 +296,8 @@ static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature,
 
 	if (!tconf->supported || !tconf->enabled)
 		return SBI_ERR_NOT_SUPPORTED;
+	else if (tconf->feature->supported && !tconf->feature->supported(vcpu))
+		return SBI_ERR_NOT_SUPPORTED;
 
 	*conf = tconf;
 
@@ -365,6 +382,9 @@ static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu)
 		else
 			conf->supported = true;
 
+		if (conf->supported && feature->init)
+			conf->supported = feature->init(vcpu);
+
 		conf->enabled = conf->supported;
 		conf->feature = feature;
 	}
@@ -408,6 +428,8 @@ static unsigned long kvm_sbi_ext_fwft_get_reg_count(struct kvm_vcpu *vcpu)
 		conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
 		if (!conf || !conf->supported)
 			continue;
+		else if (conf->feature->supported && !conf->feature->supported(vcpu))
+			continue;
 
 		ret++;
 	}
@@ -430,6 +452,8 @@ static int kvm_sbi_ext_fwft_get_reg_id(struct kvm_vcpu *vcpu, int index, u64 *re
 		conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
 		if (!conf || !conf->supported)
 			continue;
+		else if (conf->feature->supported && !conf->feature->supported(vcpu))
+			continue;
 
 		if (index == idx) {
 			*reg_id = KVM_REG_RISCV |
@@ -465,6 +489,8 @@ static int kvm_sbi_ext_fwft_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
 	conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
 	if (!conf || !conf->supported)
 		return -ENOENT;
+	else if (conf->feature->supported && !conf->feature->supported(vcpu))
+		return -ENOENT;
 
 	switch (reg_num - feature->first_reg_num) {
 	case 0:
@@ -502,6 +528,8 @@ static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
 	conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
 	if (!conf || !conf->supported)
 		return -ENOENT;
+	else if (conf->feature->supported && !conf->feature->supported(vcpu))
+		return -ENOENT;
 
 	switch (reg_num - feature->first_reg_num) {
 	case 0:

-- 
2.43.7



From yongxuan.wang at sifive.com  Mon Jun  1 01:40:33 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 01:40:33 -0700
Subject: [PATCH v4 0/3] KVM: riscv: Fix stale FWFT feature exposure and
 enhance selftests
Message-ID: <20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda@sifive.com>

This series addresses a bug in the SBI FWFT (Firmware Features) extension
where features could remain exposed to guests after their dependent ISA
extensions are disabled at runtime, and improves the related selftest
infrastructure.

The bug (patch 1) occurred because FWFT feature support was cached at vCPU
initialization time. When userspace subsequently disabled ISA extensions
via KVM ONE_REG, the cached support status was not updated, leading to
stale feature exposure.

The selftest improvements (patches 2-3) enhance the get-reg-list test by
refactoring the extension sublist infrastructure and splitting FWFT
feature testing into separate, properly-gated sublists.

---
Changes in v4:
- Rename the title of cover letter
- Disable preemption when running try_to_set_pmm() (sashiko-bot)
- Remove check_supported_reg() (sashiko-bot)
- Link to v3: https://patch.msgid.link/20260528-kvm-get_reg_list-v2-v3-0-170969a8599f at sifive.com

Changes in v3:
- Restore 'supported' field with init() callback for initialization probing
  (sashiko-bot)
- Add NULL checks before calling feature->supported() in all functions
- Fix isa_ext_enabled tracking logic and restore isa_ext_cant_disable array
- Add sbi_ext_enabled tracking and enhance dependency checking (sashiko-bot)
- Refine code organization and variable naming consistency (sashiko-bot)
- Link to v2: https://patch.msgid.link/20260526-kvm-get_reg_list-v2-v2-0-7940a401454a at sifive.com

Changes in v2:
- Fix FWFT stale feature exposure by removing static 'supported' field
- Refactor get-reg-list test to use unified extension sublist macros
- Split FWFT testing into per-feature sublists with runtime checks
  (Andrew)

To: Anup Patel <anup at brainfault.org>
To: Atish Patra <atish.patra at linux.dev>
To: Paul Walmsley <pjw at kernel.org>
To: Palmer Dabbelt <palmer at dabbelt.com>
To: Albert Ou <aou at eecs.berkeley.edu>
To: Alexandre Ghiti <alex at ghiti.fr>
To: Cl?ment L?ger <cleger at rivosinc.com>
To: Andrew Jones <ajones at ventanamicro.com>
To: Paolo Bonzini <pbonzini at redhat.com>
To: Shuah Khan <shuah at kernel.org>
Cc: greentime.hu at sifive.com
Cc: vincent.chen at sifive.com
Cc: zong.li at sifive.com
Cc: kvm at vger.kernel.org
Cc: kvm-riscv at lists.infradead.org
Cc: linux-riscv at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
Cc: linux-kselftest at vger.kernel.org

---
Yong-Xuan Wang (3):
      KVM: RISC-V: SBI FWFT: Fix stale feature exposure after runtime extension changes
      KVM: riscv: selftests: Refactor ISA and SBI extension sublist macros
      KVM: riscv: selftests: Split SBI FWFT into separate feature-specific sublists

 arch/riscv/kvm/vcpu_sbi_fwft.c                   |  34 +++++-
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 138 ++++++++++++++---------
 2 files changed, 116 insertions(+), 56 deletions(-)
---
base-commit: c7832534a8160276cccb9a8cc8cafb5614c579d0
change-id: 20260526-kvm-get_reg_list-v2-f9f36961ac6c



From yongxuan.wang at sifive.com  Mon Jun  1 01:40:35 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 01:40:35 -0700
Subject: [PATCH v4 2/3] KVM: riscv: selftests: Refactor ISA and SBI
 extension sublist macros
In-Reply-To: <20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda@sifive.com>
Message-ID: <20260601-kvm-get_reg_list-v2-v4-2-c88abc81ebda@sifive.com>

Refactor the get-reg-list test to use unified sublist macros for ISA
and SBI extensions, eliminating code duplication and improving
maintainability.

Previously, each extension had its own hand-coded sublist definition
(e.g., SUBLIST_ZICBOM, SUBLIST_AIA, etc.) and the config structures
repeated the same pattern. This made the code verbose and error-prone.

Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 78 +++++++++---------------
 1 file changed, 28 insertions(+), 50 deletions(-)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index 8d6fdb5d38b8..5033c09201ef 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -1013,7 +1013,7 @@ static __u64 fp_d_regs[] = {
 };
 
 /* Define a default vector registers with length. This will be overwritten at runtime */
-static __u64 vector_regs[] = {
+static __u64 v_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vstart),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vl),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vtype),
@@ -1057,37 +1057,17 @@ static __u64 vector_regs[] = {
 #define SUBLIST_BASE \
 	{"base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), \
 	 .skips_set = base_skips_set, .skips_set_n = ARRAY_SIZE(base_skips_set),}
-#define SUBLIST_SBI_BASE \
-	{"sbi-base", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_V01, \
-	 .regs = sbi_base_regs, .regs_n = ARRAY_SIZE(sbi_base_regs),}
-#define SUBLIST_SBI_STA \
-	{"sbi-sta", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_STA, \
-	 .regs = sbi_sta_regs, .regs_n = ARRAY_SIZE(sbi_sta_regs),}
-#define SUBLIST_SBI_FWFT \
-	{"sbi-fwft", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_FWFT, \
-	 .regs = sbi_fwft_regs, .regs_n = ARRAY_SIZE(sbi_fwft_regs),}
-#define SUBLIST_ZICBOM \
-	{"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),}
-#define SUBLIST_ZICBOP \
-	{"zicbop", .feature = KVM_RISCV_ISA_EXT_ZICBOP, .regs = zicbop_regs, .regs_n = ARRAY_SIZE(zicbop_regs),}
-#define SUBLIST_ZICBOZ \
-	{"zicboz", .feature = KVM_RISCV_ISA_EXT_ZICBOZ, .regs = zicboz_regs, .regs_n = ARRAY_SIZE(zicboz_regs),}
-#define SUBLIST_AIA \
-	{"aia", .feature = KVM_RISCV_ISA_EXT_SSAIA, .regs = aia_regs, .regs_n = ARRAY_SIZE(aia_regs),}
-#define SUBLIST_SMSTATEEN \
-	{"smstateen", .feature = KVM_RISCV_ISA_EXT_SMSTATEEN, .regs = smstateen_regs, .regs_n = ARRAY_SIZE(smstateen_regs),}
-#define SUBLIST_FP_F \
-	{"fp_f", .feature = KVM_RISCV_ISA_EXT_F, .regs = fp_f_regs, \
-		.regs_n = ARRAY_SIZE(fp_f_regs),}
-#define SUBLIST_FP_D \
-	{"fp_d", .feature = KVM_RISCV_ISA_EXT_D, .regs = fp_d_regs, \
-		.regs_n = ARRAY_SIZE(fp_d_regs),}
-
-#define SUBLIST_V \
-	{"v", .feature = KVM_RISCV_ISA_EXT_V, .regs = vector_regs, .regs_n = ARRAY_SIZE(vector_regs),}
+
+#define SUBLIST_ISA(ext, extu)				\
+	{						\
+		.name = #ext,				\
+		.feature = KVM_RISCV_ISA_EXT_##extu,	\
+		.regs = ext##_regs,			\
+		.regs_n = ARRAY_SIZE(ext##_regs),	\
+	}
 
 #define KVM_ISA_EXT_SIMPLE_CONFIG(ext, extu)			\
-static __u64 regs_##ext[] = {					\
+static __u64 ext##_regs[] = {					\
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG |			\
 	KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE |	\
 	KVM_RISCV_ISA_EXT_##extu,				\
@@ -1095,18 +1075,22 @@ static __u64 regs_##ext[] = {					\
 static struct vcpu_reg_list config_##ext = {			\
 	.sublists = {						\
 		SUBLIST_BASE,					\
-		{						\
-			.name = #ext,				\
-			.feature = KVM_RISCV_ISA_EXT_##extu,	\
-			.regs = regs_##ext,			\
-			.regs_n = ARRAY_SIZE(regs_##ext),	\
-		},						\
+		SUBLIST_ISA(ext, extu),				\
 		{0},						\
 	},							\
 }								\
 
+#define SUBLIST_SBI(ext, extu)					\
+	{							\
+		.name = "sbi-"#ext,				\
+		.feature_type = VCPU_FEATURE_SBI_EXT,		\
+		.feature = KVM_RISCV_SBI_EXT_##extu,		\
+		.regs = sbi_##ext##_regs,			\
+		.regs_n = ARRAY_SIZE(sbi_##ext##_regs),		\
+	}
+
 #define KVM_SBI_EXT_SIMPLE_CONFIG(ext, extu)			\
-static __u64 regs_sbi_##ext[] = {				\
+static __u64 sbi_##ext##_regs[] = {				\
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG |			\
 	KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE |	\
 	KVM_RISCV_SBI_EXT_##extu,				\
@@ -1114,13 +1098,7 @@ static __u64 regs_sbi_##ext[] = {				\
 static struct vcpu_reg_list config_sbi_##ext = {		\
 	.sublists = {						\
 		SUBLIST_BASE,					\
-		{						\
-			.name = "sbi-"#ext,			\
-			.feature_type = VCPU_FEATURE_SBI_EXT,	\
-			.feature = KVM_RISCV_SBI_EXT_##extu,	\
-			.regs = regs_sbi_##ext,			\
-			.regs_n = ARRAY_SIZE(regs_sbi_##ext),	\
-		},						\
+		SUBLIST_SBI(ext, extu),				\
 		{0},						\
 	},							\
 }								\
@@ -1129,7 +1107,7 @@ static struct vcpu_reg_list config_sbi_##ext = {		\
 static struct vcpu_reg_list config_##ext = {			\
 	.sublists = {						\
 		SUBLIST_BASE,					\
-		SUBLIST_##extu,					\
+		SUBLIST_ISA(ext, extu),				\
 		{0},						\
 	},							\
 }								\
@@ -1138,14 +1116,14 @@ static struct vcpu_reg_list config_##ext = {			\
 static struct vcpu_reg_list config_sbi_##ext = {		\
 	.sublists = {						\
 		SUBLIST_BASE,					\
-		SUBLIST_SBI_##extu,				\
+		SUBLIST_SBI(ext, extu),				\
 		{0},						\
 	},							\
 }								\
 
 /* Note: The below list is alphabetically sorted. */
 
-KVM_SBI_EXT_SUBLIST_CONFIG(base, BASE);
+KVM_SBI_EXT_SUBLIST_CONFIG(base, V01);
 KVM_SBI_EXT_SUBLIST_CONFIG(sta, STA);
 KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
 KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
@@ -1153,9 +1131,9 @@ KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP);
 KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY);
 KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT);
 
-KVM_ISA_EXT_SUBLIST_CONFIG(aia, AIA);
-KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, FP_F);
-KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, FP_D);
+KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA);
+KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F);
+KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, D);
 KVM_ISA_EXT_SUBLIST_CONFIG(v, V);
 KVM_ISA_EXT_SIMPLE_CONFIG(h, H);
 KVM_ISA_EXT_SIMPLE_CONFIG(smnpm, SMNPM);

-- 
2.43.7



From yongxuan.wang at sifive.com  Mon Jun  1 01:40:36 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 01:40:36 -0700
Subject: [PATCH v4 3/3] KVM: riscv: selftests: Split SBI FWFT into separate
 feature-specific sublists
In-Reply-To: <20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda@sifive.com>
Message-ID: <20260601-kvm-get_reg_list-v2-v4-3-c88abc81ebda@sifive.com>

Divide the monolithic SBI FWFT (Firmware Features) register list into
separate sublists, each testing a specific FWFT feature independently
with proper dependency checking.

Previously, all FWFT features were tested together in a single sublist.
This caused issues because:
1. Not all FWFT features are available on all platforms
2. Some features depend on specific ISA extensions (e.g., pointer_masking
requires Smnpm)
3. Tests would fail if any single feature was unavailable

Add the feature-specific SBI FWFT sublists with the following
improvements:
- Add check_fwft_feature() helper to verify FWFT feature availability
  at runtime
- Update filter_reg() to handle per-feature FWFT register filtering

Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 60 ++++++++++++++++++++++--
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index 5033c09201ef..cb86cb6b3635 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -27,6 +27,7 @@ enum {
 };
 
 static bool isa_ext_cant_disable[KVM_RISCV_ISA_EXT_MAX];
+static bool sbi_ext_enabled[KVM_RISCV_SBI_EXT_MAX];
 
 bool filter_reg(__u64 reg)
 {
@@ -149,6 +150,14 @@ bool filter_reg(__u64 reg)
 	case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1h):
 	case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio2h):
 		return isa_ext_cant_disable[KVM_RISCV_ISA_EXT_SSAIA];
+	/*
+	 * FWFT misaligned delegation registers are always visible when the SBI FWFT
+	 * extension is enable and the host supports the misaligned delegation.
+	 */
+	case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable):
+	case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags):
+	case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value):
+		return sbi_ext_enabled[KVM_RISCV_SBI_EXT_FWFT];
 	default:
 		break;
 	}
@@ -193,6 +202,27 @@ static int override_vector_reg_size(struct kvm_vcpu *vcpu, struct vcpu_reg_subli
 	return 0;
 }
 
+void check_fwft_feature(struct kvm_vcpu *vcpu, struct vcpu_reg_sublist *s, u64 feature)
+{
+	unsigned long value;
+	int rc;
+
+	/* Enable SBI FWFT extension so that we can check the supported register */
+	rc = __vcpu_set_reg(vcpu, feature, 1);
+	if (rc)
+		return;
+
+	for (int i = 0; i < s->regs_n; i++) {
+		if ((s->regs[i] & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_SBI_STATE) {
+			rc = __vcpu_get_reg(vcpu, s->regs[i], &value);
+			__TEST_REQUIRE(!rc, "%s not available, skipping tests", s->name);
+		}
+	}
+
+	/* We should assert if disabling failed here while enabling succeeded before */
+	vcpu_set_reg(vcpu, feature, 0);
+}
+
 void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
 {
 	unsigned long isa_ext_state[KVM_RISCV_ISA_EXT_MAX] = { 0 };
@@ -235,6 +265,9 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
 			break;
 		case VCPU_FEATURE_SBI_EXT:
 			feature = RISCV_SBI_EXT_REG(s->feature);
+			if (s->feature == KVM_RISCV_SBI_EXT_FWFT)
+				check_fwft_feature(vcpu, s, feature);
+			sbi_ext_enabled[s->feature] = true;
 			break;
 		default:
 			TEST_FAIL("Unknown feature type");
@@ -897,11 +930,15 @@ static __u64 sbi_sta_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_hi),
 };
 
-static __u64 sbi_fwft_regs[] = {
+static __u64 sbi_fwft_misaligned_deleg_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value),
+};
+
+static __u64 sbi_fwft_pointer_masking_regs[] = {
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value),
@@ -1129,7 +1166,6 @@ KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
 KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
 KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP);
 KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY);
-KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT);
 
 KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA);
 KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F);
@@ -1206,6 +1242,23 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zvksed, ZVKSED);
 KVM_ISA_EXT_SIMPLE_CONFIG(zvksh, ZVKSH);
 KVM_ISA_EXT_SIMPLE_CONFIG(zvkt, ZVKT);
 
+static struct vcpu_reg_list config_sbi_fwft_misaligned_deleg = {
+	.sublists = {
+		SUBLIST_BASE,
+		SUBLIST_SBI(fwft_misaligned_deleg, FWFT),
+		{0},
+	},
+};
+
+static struct vcpu_reg_list config_sbi_fwft_pointer_masking = {
+	.sublists = {
+		SUBLIST_BASE,
+		SUBLIST_ISA(smnpm, SMNPM),
+		SUBLIST_SBI(fwft_pointer_masking, FWFT),
+		{0},
+	},
+};
+
 struct vcpu_reg_list *vcpu_configs[] = {
 	&config_sbi_base,
 	&config_sbi_sta,
@@ -1213,7 +1266,8 @@ struct vcpu_reg_list *vcpu_configs[] = {
 	&config_sbi_dbcn,
 	&config_sbi_susp,
 	&config_sbi_mpxy,
-	&config_sbi_fwft,
+	&config_sbi_fwft_misaligned_deleg,
+	&config_sbi_fwft_pointer_masking,
 	&config_aia,
 	&config_fp_f,
 	&config_fp_d,

-- 
2.43.7



From inochiama at gmail.com  Mon Jun  1 01:43:28 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon,  1 Jun 2026 16:43:28 +0800
Subject: [PATCH v2 0/7] RISC-V: KVM: Add Svadu/Zicfiss/Zicfilp FWFT support
Message-ID: <20260601084336.2601675-1-inochiama@gmail.com>

This patchset based on the patchset "RISC-V: KVM: Add Zicfiss/Zicfilp
support".

The patch includes all the function of original patchset from Quan:
adding the Svadu/Zicfiss/Zicfilp FWFT for the RISC-V KVM. And this
patchset already passes the KVM unit test.

Changed from Quan's v1:
- https://lore.kernel.org/kvm/cover.1764509485.git.zhouquan at iscas.ac.cn/
1. rebase to the latest master.
2. Split Svadu change as separate patch
3. Fix all build error from the original series
4. Remove the Svadu check in kvm_riscv_vcpu_config_ran_once() and in
   favor of the FWFT.
5. Remove the LPE/SSE setting bit in kvm_riscv_vcpu_config_ran_once()
   (kvm_riscv_vcpu_setup_config() in original patchset)

Inochi Amaoto (7):
  RISC-V: KVM: Add support for Svadu FWFT features
  KVM: riscv: selftests: add Svadu FWFT extension to get-reg-list test
  RISC-V: KVM: Only enable Svadu extension when Guest/VM requests
  RISC-V: KVM: Allow Zicfiss/Zicfilp extensions for Guest/VM
  RISC-V: KVM: Handle software-check exits for VCPU
  RISC-V: KVM: Add support for control-flow integrity FWFT features
  KVM: riscv: selftests: add Zicfiss/Zicfilp extension to get-reg-list
    test

 arch/riscv/include/asm/csr.h                  |   1 +
 arch/riscv/include/uapi/asm/kvm.h             |   5 +
 arch/riscv/kvm/isa.c                          |   2 +
 arch/riscv/kvm/vcpu_config.c                  |   8 +-
 arch/riscv/kvm/vcpu_exit.c                    |   3 +
 arch/riscv/kvm/vcpu_sbi_fwft.c                | 142 ++++++++++++++++++
 .../selftests/kvm/riscv/get-reg-list.c        |  22 +++
 7 files changed, 179 insertions(+), 4 deletions(-)

--
2.54.0



From inochiama at gmail.com  Mon Jun  1 01:43:29 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon,  1 Jun 2026 16:43:29 +0800
Subject: [PATCH v2 1/7] RISC-V: KVM: Add support for Svadu FWFT features
In-Reply-To: <20260601084336.2601675-1-inochiama@gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
Message-ID: <20260601084336.2601675-2-inochiama@gmail.com>

Hardware updating of PTE A/D bits is controlled through ADUE bit in
henvcfg Expose the feature only if the Svadu is supported for VS-mode.
Allow the VMM to block access to the feature by disabling the ISA
extension in the guest.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/include/uapi/asm/kvm.h |  3 ++
 arch/riscv/kvm/vcpu_sbi_fwft.c    | 72 +++++++++++++++++++++++++++++++
 2 files changed, 75 insertions(+)

diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
index 504e73305343..501e4fc60dd2 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -240,6 +240,9 @@ struct kvm_riscv_sbi_fwft_feature {
 struct kvm_riscv_sbi_fwft {
 	struct kvm_riscv_sbi_fwft_feature misaligned_deleg;
 	struct kvm_riscv_sbi_fwft_feature pointer_masking;
+	struct kvm_riscv_sbi_fwft_feature pte_ad_hw_updating;
+	struct kvm_riscv_sbi_fwft_feature landing_pad;
+	struct kvm_riscv_sbi_fwft_feature shadow_stack;
 };
 
 /* If you need to interpret the index values, here is the key: */
diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index 2eab15339694..375269e43c13 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -84,6 +84,42 @@ static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature)
 	return false;
 }
 
+static void kvm_sbi_fwft_env_flag_reset_helper(struct kvm_vcpu *vcpu,
+					       unsigned long flag)
+{
+	vcpu->arch.cfg.henvcfg &= ~flag;
+}
+
+static long kvm_sbi_fwft_env_flag_set_helper(struct kvm_vcpu *vcpu,
+					     struct kvm_sbi_fwft_config *conf,
+					     bool one_reg_access,
+					     unsigned long value, unsigned long flag)
+{
+	struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+
+	if (value == 0)
+		cfg->henvcfg &= ~flag;
+	else if (value == 1)
+		cfg->henvcfg |= flag;
+	else
+		return SBI_ERR_INVALID_PARAM;
+
+	if (!one_reg_access)
+		csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg);
+
+	return SBI_SUCCESS;
+}
+
+static long kvm_sbi_fwft_env_flag_get_helper(struct kvm_vcpu *vcpu,
+					     struct kvm_sbi_fwft_config *conf,
+					     bool one_reg_access,
+					     unsigned long *value, unsigned long flag)
+{
+	*value = (vcpu->arch.cfg.henvcfg & flag) == flag;
+
+	return SBI_SUCCESS;
+}
+
 static bool kvm_sbi_fwft_misaligned_delegation_supported(struct kvm_vcpu *vcpu)
 {
 	return misaligned_traps_can_delegate();
@@ -127,6 +163,33 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
 	return SBI_SUCCESS;
 }
 
+static bool kvm_sbi_fwft_pte_ad_hw_updating_supported(struct kvm_vcpu *vcpu)
+{
+	return riscv_isa_extension_available(vcpu->arch.isa, SVADU) &&
+		!riscv_isa_extension_available(vcpu->arch.isa, SVADE);
+}
+
+static void kvm_sbi_fwft_reset_pte_ad_hw_updating(struct kvm_vcpu *vcpu)
+{
+	kvm_sbi_fwft_env_flag_reset_helper(vcpu, ENVCFG_ADUE);
+}
+
+static long kvm_sbi_fwft_set_pte_ad_hw_updating(struct kvm_vcpu *vcpu,
+						struct kvm_sbi_fwft_config *conf,
+						bool one_reg_access, unsigned long value)
+{
+	return kvm_sbi_fwft_env_flag_set_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_ADUE);
+}
+
+static long kvm_sbi_fwft_get_pte_ad_hw_updating(struct kvm_vcpu *vcpu,
+						struct kvm_sbi_fwft_config *conf,
+						bool one_reg_access, unsigned long *value)
+{
+	return kvm_sbi_fwft_env_flag_get_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_ADUE);
+}
+
 #ifndef CONFIG_32BIT
 
 static bool try_to_set_pmm(unsigned long value)
@@ -225,6 +288,15 @@ static const struct kvm_sbi_fwft_feature features[] = {
 		.set = kvm_sbi_fwft_set_misaligned_delegation,
 		.get = kvm_sbi_fwft_get_misaligned_delegation,
 	},
+	{
+		.id = SBI_FWFT_PTE_AD_HW_UPDATING,
+		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pte_ad_hw_updating.enable) /
+				 sizeof(unsigned long),
+		.supported = kvm_sbi_fwft_pte_ad_hw_updating_supported,
+		.reset = kvm_sbi_fwft_reset_pte_ad_hw_updating,
+		.set = kvm_sbi_fwft_set_pte_ad_hw_updating,
+		.get = kvm_sbi_fwft_get_pte_ad_hw_updating,
+	},
 #ifndef CONFIG_32BIT
 	{
 		.id = SBI_FWFT_POINTER_MASKING_PMLEN,
-- 
2.54.0



From inochiama at gmail.com  Mon Jun  1 01:43:30 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon,  1 Jun 2026 16:43:30 +0800
Subject: [PATCH v2 2/7] KVM: riscv: selftests: add Svadu FWFT extension to get-reg-list test
In-Reply-To: <20260601084336.2601675-1-inochiama@gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
Message-ID: <20260601084336.2601675-3-inochiama@gmail.com>

The KVM RISC-V allows Svadu FWFT for Guest/VM so add this extension
to get-reg-list test.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index 8d6fdb5d38b8..d88edef77ccf 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -712,6 +712,9 @@ static const char *sbi_fwft_id_to_str(__u64 reg_off)
 	case 3: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable)";
 	case 4: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags)";
 	case 5: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value)";
+	case 6: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.enable)";
+	case 7: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.flags)";
+	case 8: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.value)";
 	}
 	return strdup_printf("KVM_REG_RISCV_SBI_FWFT | %lld /* UNKNOWN */", reg_off);
 }
@@ -905,6 +908,9 @@ static __u64 sbi_fwft_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.enable),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.flags),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.value),
 };
 
 static __u64 zicbom_regs[] = {
-- 
2.54.0



From inochiama at gmail.com  Mon Jun  1 01:43:31 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon,  1 Jun 2026 16:43:31 +0800
Subject: [PATCH v2 3/7] RISC-V: KVM: Only enable Svadu extension when Guest/VM requests
In-Reply-To: <20260601084336.2601675-1-inochiama@gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
Message-ID: <20260601084336.2601675-4-inochiama@gmail.com>

Since the Svadu extension can be controlled by the FWFT, there is
no need to enable Svadu at startup. Only enable it when it is
requested.

Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/kvm/vcpu_config.c | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/arch/riscv/kvm/vcpu_config.c b/arch/riscv/kvm/vcpu_config.c
index 238418fed2b9..b2a1028106d5 100644
--- a/arch/riscv/kvm/vcpu_config.c
+++ b/arch/riscv/kvm/vcpu_config.c
@@ -53,10 +53,6 @@ void kvm_riscv_vcpu_config_ran_once(struct kvm_vcpu *vcpu)
 	if (riscv_isa_extension_available(isa, ZICBOZ))
 		cfg->henvcfg |= ENVCFG_CBZE;
 
-	if (riscv_isa_extension_available(isa, SVADU) &&
-	    !riscv_isa_extension_available(isa, SVADE))
-		cfg->henvcfg |= ENVCFG_ADUE;
-
 	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN)) {
 		cfg->hstateen0 |= SMSTATEEN0_HSENVCFG;
 		if (riscv_isa_extension_available(isa, SSAIA))
-- 
2.54.0



From inochiama at gmail.com  Mon Jun  1 01:43:32 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon,  1 Jun 2026 16:43:32 +0800
Subject: [PATCH v2 4/7] RISC-V: KVM: Allow Zicfiss/Zicfilp extensions for Guest/VM
In-Reply-To: <20260601084336.2601675-1-inochiama@gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
Message-ID: <20260601084336.2601675-5-inochiama@gmail.com>

Extend the KVM ISA extension array to allow KVM userspace to
detect and enable Zicfiss/Zicfilp extensions for Guest/VM.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/include/uapi/asm/kvm.h | 2 ++
 arch/riscv/kvm/isa.c              | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
index 501e4fc60dd2..9f9c5ababd1e 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -199,6 +199,8 @@ enum KVM_RISCV_ISA_EXT_ID {
 	KVM_RISCV_ISA_EXT_ZCLSD,
 	KVM_RISCV_ISA_EXT_ZILSD,
 	KVM_RISCV_ISA_EXT_ZALASR,
+	KVM_RISCV_ISA_EXT_ZICFILP,
+	KVM_RISCV_ISA_EXT_ZICFISS,
 	KVM_RISCV_ISA_EXT_MAX,
 };
 
diff --git a/arch/riscv/kvm/isa.c b/arch/riscv/kvm/isa.c
index 1132d909cc25..9852a91fdecc 100644
--- a/arch/riscv/kvm/isa.c
+++ b/arch/riscv/kvm/isa.c
@@ -65,6 +65,8 @@ static const unsigned long kvm_isa_ext_arr[] = {
 	KVM_ISA_EXT_ARR(ZICBOP),
 	KVM_ISA_EXT_ARR(ZICBOZ),
 	KVM_ISA_EXT_ARR(ZICCRSE),
+	KVM_ISA_EXT_ARR(ZICFILP),
+	KVM_ISA_EXT_ARR(ZICFISS),
 	KVM_ISA_EXT_ARR(ZICNTR),
 	KVM_ISA_EXT_ARR(ZICOND),
 	KVM_ISA_EXT_ARR(ZICSR),
-- 
2.54.0



From inochiama at gmail.com  Mon Jun  1 01:43:33 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon,  1 Jun 2026 16:43:33 +0800
Subject: [PATCH v2 5/7] RISC-V: KVM: Handle software-check exits for VCPU
In-Reply-To: <20260601084336.2601675-1-inochiama@gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
Message-ID: <20260601084336.2601675-6-inochiama@gmail.com>

The extension Zicfiss/Zicfilp introduces a software-check exception
to the privilege architecture. Delegate this exception to VS mode so
the CFI violations in VU/VS could be reported.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/include/asm/csr.h | 1 +
 arch/riscv/kvm/vcpu_config.c | 4 ++++
 arch/riscv/kvm/vcpu_exit.c   | 3 +++
 3 files changed, 8 insertions(+)

diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 31b8988f4488..224af9facf1f 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -117,6 +117,7 @@
 #define EXC_INST_PAGE_FAULT	12
 #define EXC_LOAD_PAGE_FAULT	13
 #define EXC_STORE_PAGE_FAULT	15
+#define EXC_SOFTWARE_CHECK		18
 #define EXC_INST_GUEST_PAGE_FAULT	20
 #define EXC_LOAD_GUEST_PAGE_FAULT	21
 #define EXC_VIRTUAL_INST_FAULT		22
diff --git a/arch/riscv/kvm/vcpu_config.c b/arch/riscv/kvm/vcpu_config.c
index b2a1028106d5..dbe4167ac4f1 100644
--- a/arch/riscv/kvm/vcpu_config.c
+++ b/arch/riscv/kvm/vcpu_config.c
@@ -65,6 +65,10 @@ void kvm_riscv_vcpu_config_ran_once(struct kvm_vcpu *vcpu)
 
 	if (vcpu->guest_debug)
 		cfg->hedeleg &= ~BIT(EXC_BREAKPOINT);
+
+	if (riscv_isa_extension_available(isa, ZICFILP) ||
+	    riscv_isa_extension_available(isa, ZICFISS))
+		cfg->hedeleg |= BIT(EXC_SOFTWARE_CHECK);
 }
 
 void kvm_riscv_vcpu_config_load(struct kvm_vcpu *vcpu)
diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c
index 0bb0c51e3c89..5ab8e87ed248 100644
--- a/arch/riscv/kvm/vcpu_exit.c
+++ b/arch/riscv/kvm/vcpu_exit.c
@@ -243,6 +243,9 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		run->exit_reason = KVM_EXIT_DEBUG;
 		ret = 0;
 		break;
+	case EXC_SOFTWARE_CHECK:
+		ret = vcpu_redirect(vcpu, trap);
+		break;
 	default:
 		break;
 	}
-- 
2.54.0



From inochiama at gmail.com  Mon Jun  1 01:43:34 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon,  1 Jun 2026 16:43:34 +0800
Subject: [PATCH v2 6/7] RISC-V: KVM: Add support for control-flow integrity FWFT features
In-Reply-To: <20260601084336.2601675-1-inochiama@gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
Message-ID: <20260601084336.2601675-7-inochiama@gmail.com>

Control-flow integrity is controlled through a WARL field in henvcfg.
Expose the feature only if the Zicfilp/Zicfiss is supported for VS-mode.
Allow the VMM to block access to the feature by disabling the ISA
extension in the guest.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/kvm/vcpu_sbi_fwft.c | 70 ++++++++++++++++++++++++++++++++++
 1 file changed, 70 insertions(+)

diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index 375269e43c13..278eb95b97de 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -163,6 +163,58 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
 	return SBI_SUCCESS;
 }
 
+static bool kvm_sbi_fwft_landing_pad_supported(struct kvm_vcpu *vcpu)
+{
+	return riscv_isa_extension_available(vcpu->arch.isa, ZICFILP);
+}
+
+static void kvm_sbi_fwft_reset_landing_pad(struct kvm_vcpu *vcpu)
+{
+	kvm_sbi_fwft_env_flag_reset_helper(vcpu, ENVCFG_LPE);
+}
+
+static long kvm_sbi_fwft_set_landing_pad(struct kvm_vcpu *vcpu,
+					 struct kvm_sbi_fwft_config *conf,
+					 bool one_reg_access, unsigned long value)
+{
+	return kvm_sbi_fwft_env_flag_set_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_LPE);
+}
+
+static long kvm_sbi_fwft_get_landing_pad(struct kvm_vcpu *vcpu,
+					 struct kvm_sbi_fwft_config *conf,
+					 bool one_reg_access, unsigned long *value)
+{
+	return kvm_sbi_fwft_env_flag_get_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_LPE);
+}
+
+static bool kvm_sbi_fwft_shadow_stack_supported(struct kvm_vcpu *vcpu)
+{
+	return riscv_isa_extension_available(vcpu->arch.isa, ZICFISS);
+}
+
+static void kvm_sbi_fwft_reset_shadow_stack(struct kvm_vcpu *vcpu)
+{
+	kvm_sbi_fwft_env_flag_reset_helper(vcpu, ENVCFG_SSE);
+}
+
+static long kvm_sbi_fwft_set_shadow_stack(struct kvm_vcpu *vcpu,
+					  struct kvm_sbi_fwft_config *conf,
+					  bool one_reg_access, unsigned long value)
+{
+	return kvm_sbi_fwft_env_flag_set_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_SSE);
+}
+
+static long kvm_sbi_fwft_get_shadow_stack(struct kvm_vcpu *vcpu,
+					  struct kvm_sbi_fwft_config *conf,
+					  bool one_reg_access, unsigned long *value)
+{
+	return kvm_sbi_fwft_env_flag_get_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_SSE);
+}
+
 static bool kvm_sbi_fwft_pte_ad_hw_updating_supported(struct kvm_vcpu *vcpu)
 {
 	return riscv_isa_extension_available(vcpu->arch.isa, SVADU) &&
@@ -288,6 +340,24 @@ static const struct kvm_sbi_fwft_feature features[] = {
 		.set = kvm_sbi_fwft_set_misaligned_delegation,
 		.get = kvm_sbi_fwft_get_misaligned_delegation,
 	},
+	{
+		.id = SBI_FWFT_LANDING_PAD,
+		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, landing_pad.enable) /
+				 sizeof(unsigned long),
+		.supported = kvm_sbi_fwft_landing_pad_supported,
+		.reset = kvm_sbi_fwft_reset_landing_pad,
+		.set = kvm_sbi_fwft_set_landing_pad,
+		.get = kvm_sbi_fwft_get_landing_pad,
+	},
+	{
+		.id = SBI_FWFT_SHADOW_STACK,
+		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, shadow_stack.enable) /
+				 sizeof(unsigned long),
+		.supported = kvm_sbi_fwft_shadow_stack_supported,
+		.reset = kvm_sbi_fwft_reset_shadow_stack,
+		.set = kvm_sbi_fwft_set_shadow_stack,
+		.get = kvm_sbi_fwft_get_shadow_stack,
+	},
 	{
 		.id = SBI_FWFT_PTE_AD_HW_UPDATING,
 		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pte_ad_hw_updating.enable) /
-- 
2.54.0



From inochiama at gmail.com  Mon Jun  1 01:43:35 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon,  1 Jun 2026 16:43:35 +0800
Subject: [PATCH v2 7/7] KVM: riscv: selftests: add Zicfiss/Zicfilp extension to get-reg-list test
In-Reply-To: <20260601084336.2601675-1-inochiama@gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
Message-ID: <20260601084336.2601675-8-inochiama@gmail.com>

The KVM RISC-V allows Zicfiss/Zicfilp extensions for Guest/VM so
add these extensions to get-reg-list test.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index d88edef77ccf..4fab3d2d0b43 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -89,6 +89,8 @@ bool filter_reg(__u64 reg)
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOP:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOZ:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICCRSE:
+	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICFILP:
+	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICFISS:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICNTR:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICOND:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICSR:
@@ -552,6 +554,8 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off)
 		KVM_ISA_EXT_ARR(ZICBOP),
 		KVM_ISA_EXT_ARR(ZICBOZ),
 		KVM_ISA_EXT_ARR(ZICCRSE),
+		KVM_ISA_EXT_ARR(ZICFILP),
+		KVM_ISA_EXT_ARR(ZICFISS),
 		KVM_ISA_EXT_ARR(ZICNTR),
 		KVM_ISA_EXT_ARR(ZICOND),
 		KVM_ISA_EXT_ARR(ZICSR),
@@ -715,6 +719,12 @@ static const char *sbi_fwft_id_to_str(__u64 reg_off)
 	case 6: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.enable)";
 	case 7: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.flags)";
 	case 8: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.value)";
+	case 9: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.enable)";
+	case 10: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.flags)";
+	case 11: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.value)";
+	case 12: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.enable)";
+	case 13: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.flags)";
+	case 14: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.value)";
 	}
 	return strdup_printf("KVM_REG_RISCV_SBI_FWFT | %lld /* UNKNOWN */", reg_off);
 }
@@ -911,6 +921,12 @@ static __u64 sbi_fwft_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.enable),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.flags),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.value),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.enable),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.flags),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.value),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.enable),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.flags),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.value),
 };
 
 static __u64 zicbom_regs[] = {
-- 
2.54.0



From guoyaxing at bosc.ac.cn  Mon Jun  1 01:45:24 2026
From: guoyaxing at bosc.ac.cn (Yaxing Guo)
Date: Mon,  1 Jun 2026 16:45:24 +0800
Subject: [PATCH v4 3/4] riscv: Stop emitting preventive sfence.vma for new vmalloc mappings
In-Reply-To: <20240717060125.139416-4-alexghiti@rivosinc.com>
References: <20240717060125.139416-4-alexghiti@rivosinc.com>
Message-ID: <20260601084524.34584-1-guoyaxing@bosc.ac.cn>

Hi Alexandre,

We are looking at commit 503638e0babf ("riscv: Stop emitting
preventive sfence.vma for new vmalloc mappings") and ran into a case
that I do not think the current early new_vmalloc_check covers.

The commit removes the preventive sfence.vma after installing a vmalloc
mapping and relies on a later kernel page fault to run
new_vmalloc_check. That works if the first stale-translation fault is
taken while sscratch is still zero. On our core, however, invalid PTE
results may be cached/prefetched before the vmalloc PTE is installed.
Without an sfence.vma, an old negative translation for the vmalloc VA can
remain cached for ASID A.

A sequence we can reproduce is:

  1. Before the vmalloc PTE is installed, the walker/prefetcher observes
     the VA and caches an invalid result for ASID A.
  2. The vmalloc PTE is installed as a global kernel mapping, but no
     sfence.vma is issued.
  3. A different task/ASID B accesses the same VA and installs a valid
     global translation.
  4. The same hart later has both the stale invalid result for ASID A and
     the valid global translation available for that VA. Which one is used
     is implementation-dependent until an sfence.vma is executed.

The failure we see happens in ret_from_exception while returning to user
mode:

  ret_from_exception:
      REG_L s0, PT_STATUS(sp)   /* succeeds via the valid global entry */
      ...
      csrw CSR_SCRATCH, tp      /* returning to user; sscratch is now non-zero */
  1:
      REG_L a0, PT_STATUS(sp)   /* hits the stale invalid entry and faults */

The second load takes a kernel page fault on the vmalloc stack. But
because sscratch has already been restored to tp for the upcoming return
to user mode, handle_exception takes the bnez tp, .Lsave_context path and
does not execute new_vmalloc_check. The fault is then not converted into
the intended sfence.vma + retry path.

Our understanding is that this CPU behavior is allowed: without an
sfence.vma after changing the PTE, software cannot require the MMU to stop
using a stale invalid translation result. Caching invalid translation
results can also be useful for performance.

Is the delayed-vmalloc-fence scheme intended to rely on stale invalid
entries not coexisting with a later valid global entry for the same VA?
Or should new_vmalloc_check also cover the short return-to-user window
after sscratch is made non-zero but before the final sret?

If the latter, would you prefer a fix that delays writing sscratch until
after the last access through the vmalloc stack in ret_from_exception, or
a fix that detects this S-mode vmalloc fault even when sscratch is
non-zero?

Thanks,
Yaxing


From songmuchun at bytedance.com  Mon Jun  1 01:48:39 2026
From: songmuchun at bytedance.com (Muchun Song)
Date: Mon,  1 Jun 2026 16:48:39 +0800
Subject: [PATCH v3 0/5] mm/sparse-vmemmap: Provide generic vmemmap_set_pmd() and vmemmap_check_pmd()
Message-ID: <20260601084845.3792171-1-songmuchun@bytedance.com>

The weak vmemmap_set_pmd() and vmemmap_check_pmd() hooks are
currently no-ops in the generic code, which leaves architectures that
need PMD-level handling to open-code the same logic locally.

This series provides generic implementations for both helpers in
mm/sparse-vmemmap.c. vmemmap_set_pmd() installs a huge PMD with
PAGE_KERNEL protection, and vmemmap_check_pmd() verifies a present
leaf PMD before reusing the existing vmemmap_verify() helper.

With those generic helpers in place, patches 2-5 remove the now
redundant arch-specific implementations from arm64, riscv, loongarch,
and sparc.

v2 -> v3:
- Replace BUG_ON() with WARN_ON_ONCE() in patch 1
- Add Will Deacon's Acked-by to patch 2

Muchun Song (5):
  mm/sparse-vmemmap: provide generic vmemmap_set_pmd() and
    vmemmap_check_pmd()
  arm64/mm: drop vmemmap_pmd helpers and use generic code
  riscv/mm: drop vmemmap_pmd helpers and use generic code
  loongarch/mm: drop vmemmap_check_pmd helper and use generic code
  sparc/mm: drop vmemmap_check_pmd helper and use generic code

 arch/arm64/mm/mmu.c      | 14 --------------
 arch/loongarch/mm/init.c | 11 -----------
 arch/riscv/mm/init.c     | 13 -------------
 arch/sparc/mm/init_64.c  | 11 -----------
 mm/sparse-vmemmap.c      |  7 ++++++-
 5 files changed, 6 insertions(+), 50 deletions(-)


base-commit: 7da7f07112610a520567421dd2ffcb51beaefbcc
-- 
2.54.0



From songmuchun at bytedance.com  Mon Jun  1 01:48:40 2026
From: songmuchun at bytedance.com (Muchun Song)
Date: Mon,  1 Jun 2026 16:48:40 +0800
Subject: [PATCH v3 1/5] mm/sparse-vmemmap: provide generic vmemmap_set_pmd() and vmemmap_check_pmd()
In-Reply-To: <20260601084845.3792171-1-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
Message-ID: <20260601084845.3792171-2-songmuchun@bytedance.com>

The two weak functions are currently no-ops on every architecture,
forcing each platform that needs them to duplicate the same handful
of lines.  Provide a generic implementation:

- vmemmap_set_pmd() simply sets a huge PMD with PAGE_KERNEL protection.

- vmemmap_check_pmd() verifies that the PMD is present and leaf,
  then calls the existing vmemmap_verify() helper.

Architectures that need special handling can continue to override the
weak symbols; everyone else gets the standard version for free.

Signed-off-by: Muchun Song <songmuchun at bytedance.com>
---
v2->v3:
- Replace BUG_ON() with WARN_ON_ONCE() in vmemmap_set_pmd()
---
 mm/sparse-vmemmap.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 112ccf9c71ca..99e2be39671b 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -386,12 +386,17 @@ int __meminit vmemmap_populate_hvo(unsigned long addr, unsigned long end,
 void __weak __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,
 				      unsigned long addr, unsigned long next)
 {
+	WARN_ON_ONCE(!pmd_set_huge(pmd, virt_to_phys(p), PAGE_KERNEL));
 }
 
 int __weak __meminit vmemmap_check_pmd(pmd_t *pmd, int node,
 				       unsigned long addr, unsigned long next)
 {
-	return 0;
+	if (!pmd_leaf(pmdp_get(pmd)))
+		return 0;
+	vmemmap_verify((pte_t *)pmd, node, addr, next);
+
+	return 1;
 }
 
 int __meminit vmemmap_populate_hugepages(unsigned long start, unsigned long end,
-- 
2.54.0



From songmuchun at bytedance.com  Mon Jun  1 01:48:41 2026
From: songmuchun at bytedance.com (Muchun Song)
Date: Mon,  1 Jun 2026 16:48:41 +0800
Subject: [PATCH v3 2/5] arm64/mm: drop vmemmap_pmd helpers and use generic code
In-Reply-To: <20260601084845.3792171-1-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
Message-ID: <20260601084845.3792171-3-songmuchun@bytedance.com>

The generic implementations now suffice; remove the arm64 copies.

Signed-off-by: Muchun Song <songmuchun at bytedance.com>
Acked-by: Will Deacon <will at kernel.org>
---
v2->v3:
- Collect Acked-by from Will Deacon
---
 arch/arm64/mm/mmu.c | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 24388e5c727d..ea10b0ebecd7 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -1776,20 +1776,6 @@ static void free_empty_tables(unsigned long addr, unsigned long end,
 }
 #endif
 
-void __meminit vmemmap_set_pmd(pmd_t *pmdp, void *p, int node,
-			       unsigned long addr, unsigned long next)
-{
-	pmd_set_huge(pmdp, __pa(p), __pgprot(PROT_SECT_NORMAL));
-}
-
-int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node,
-				unsigned long addr, unsigned long next)
-{
-	vmemmap_verify((pte_t *)pmdp, node, addr, next);
-
-	return pmd_leaf(READ_ONCE(*pmdp));
-}
-
 int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
 		struct vmem_altmap *altmap)
 {
-- 
2.54.0



From songmuchun at bytedance.com  Mon Jun  1 01:48:42 2026
From: songmuchun at bytedance.com (Muchun Song)
Date: Mon,  1 Jun 2026 16:48:42 +0800
Subject: [PATCH v3 3/5] riscv/mm: drop vmemmap_pmd helpers and use generic code
In-Reply-To: <20260601084845.3792171-1-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
Message-ID: <20260601084845.3792171-4-songmuchun@bytedance.com>

The generic implementations now suffice; remove the riscv copies.

Signed-off-by: Muchun Song <songmuchun at bytedance.com>
---
 arch/riscv/mm/init.c | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 885f1db4e9bf..5f680eb83e86 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1359,19 +1359,6 @@ void __init misc_mem_init(void)
 }
 
 #ifdef CONFIG_SPARSEMEM_VMEMMAP
-void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,
-			       unsigned long addr, unsigned long next)
-{
-	pmd_set_huge(pmd, virt_to_phys(p), PAGE_KERNEL);
-}
-
-int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node,
-				unsigned long addr, unsigned long next)
-{
-	vmemmap_verify((pte_t *)pmdp, node, addr, next);
-	return 1;
-}
-
 int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
 			       struct vmem_altmap *altmap)
 {
-- 
2.54.0



From songmuchun at bytedance.com  Mon Jun  1 01:48:43 2026
From: songmuchun at bytedance.com (Muchun Song)
Date: Mon,  1 Jun 2026 16:48:43 +0800
Subject: [PATCH v3 4/5] loongarch/mm: drop vmemmap_check_pmd helper and use generic code
In-Reply-To: <20260601084845.3792171-1-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
Message-ID: <20260601084845.3792171-5-songmuchun@bytedance.com>

The generic implementations now suffice; remove the loongarch copies.

Signed-off-by: Muchun Song <songmuchun at bytedance.com>
---
 arch/loongarch/mm/init.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/arch/loongarch/mm/init.c b/arch/loongarch/mm/init.c
index 687980b6e91f..3407030f3e7a 100644
--- a/arch/loongarch/mm/init.c
+++ b/arch/loongarch/mm/init.c
@@ -140,17 +140,6 @@ void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,
 	set_pmd_at(&init_mm, addr, pmd, entry);
 }
 
-int __meminit vmemmap_check_pmd(pmd_t *pmd, int node,
-				unsigned long addr, unsigned long next)
-{
-	int huge = pmd_val(pmdp_get(pmd)) & _PAGE_HUGE;
-
-	if (huge)
-		vmemmap_verify((pte_t *)pmd, node, addr, next);
-
-	return huge;
-}
-
 int __meminit vmemmap_populate(unsigned long start, unsigned long end,
 			       int node, struct vmem_altmap *altmap)
 {
-- 
2.54.0



From songmuchun at bytedance.com  Mon Jun  1 01:48:44 2026
From: songmuchun at bytedance.com (Muchun Song)
Date: Mon,  1 Jun 2026 16:48:44 +0800
Subject: [PATCH v3 5/5] sparc/mm: drop vmemmap_check_pmd helper and use generic code
In-Reply-To: <20260601084845.3792171-1-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
Message-ID: <20260601084845.3792171-6-songmuchun@bytedance.com>

The generic implementations now suffice; remove the sparc copies.

Signed-off-by: Muchun Song <songmuchun at bytedance.com>
---
 arch/sparc/mm/init_64.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/arch/sparc/mm/init_64.c b/arch/sparc/mm/init_64.c
index 3b679b1d1d72..103db4683b16 100644
--- a/arch/sparc/mm/init_64.c
+++ b/arch/sparc/mm/init_64.c
@@ -2559,17 +2559,6 @@ void __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,
 	pmd_val(*pmd) = pte_base | __pa(p);
 }
 
-int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node,
-				unsigned long addr, unsigned long next)
-{
-	int large = pmd_leaf(*pmdp);
-
-	if (large)
-		vmemmap_verify((pte_t *)pmdp, node, addr, next);
-
-	return large;
-}
-
 int __meminit vmemmap_populate(unsigned long vstart, unsigned long vend,
 			       int node, struct vmem_altmap *altmap)
 {
-- 
2.54.0



From nutty.liu at hotmail.com  Mon Jun  1 01:53:02 2026
From: nutty.liu at hotmail.com (Nutty.Liu)
Date: Mon, 1 Jun 2026 16:53:02 +0800
Subject: [PATCH 1/3] KVM: riscv: Pass the target size to huge G-stage
 checks
In-Reply-To: <20260520152148.131272-2-tjytimi@163.com>
References: <20260520152148.131272-1-tjytimi@163.com>
 <20260520152148.131272-2-tjytimi@163.com>
Message-ID: <SE3PR04MB8922FD6348F0F4426A3E2F46F3152@SE3PR04MB8922.apcprd04.prod.outlook.com>


On 5/20/2026 11:21 PM, Jinyu Tang wrote:
> fault_supports_gstage_huge_mapping() already contains the two checks
> needed before installing a G-stage block mapping: the userspace address
> and GPA must have matching offsets within the block, and the whole block
> must be contained within the memslot.
>
> The helper currently hard-codes PMD_SIZE because its only caller is the
> transparent hugepage path. The hugetlb path needs the same checks, but
> the target block size can be either PMD_SIZE or PUD_SIZE depending on the
> hugetlb VMA.
>
> So pass the target mapping size into the helper and use it for the
> alignment and bounds checks. This keeps the existing THP PMD behavior
> unchanged and prepares the helper to be reused for the following hugetlb
> fix.
>
> Signed-off-by: Jinyu Tang <tjytimi at 163.com>
> ---
>   arch/riscv/kvm/mmu.c | 14 ++++++++------
>   1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 2d3def024..10be8f683 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -286,7 +286,8 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
>   }
>   
>   static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
> -					       unsigned long hva)
> +					       unsigned long hva,
> +					       unsigned long map_size)
>   {
>   	hva_t uaddr_start, uaddr_end;
>   	gpa_t gpa_start;
> @@ -300,8 +301,8 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>   
>   	/*
>   	 * Pages belonging to memslots that don't have the same alignment
> -	 * within a PMD for userspace and GPA cannot be mapped with g-stage
> -	 * PMD entries, because we'll end up mapping the wrong pages.
> +	 * within a huge page for userspace and GPA cannot be mapped with
> +	 * g-stage block entries, because we'll end up mapping the wrong pages.
>   	 *
>   	 * Consider a layout like the following:
>   	 *
> @@ -321,7 +322,7 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>   	 *   e -> g
>   	 *   f -> h
>   	 */
> -	if ((gpa_start & (PMD_SIZE - 1)) != (uaddr_start & (PMD_SIZE - 1)))
> +	if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1)))
>   		return false;
>   
>   	/*
> @@ -336,7 +337,8 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>   	 * userspace_addr or the base_gfn, as both are equally aligned (per
>   	 * the check above) and equally sized.
>   	 */
> -	return (hva >= ALIGN(uaddr_start, PMD_SIZE)) && (hva < ALIGN_DOWN(uaddr_end, PMD_SIZE));
> +	return (hva & ~(map_size - 1)) >= uaddr_start &&
> +	       (hva & ~(map_size - 1)) + map_size <= uaddr_end;
Seems they are not exactly the same.
Should be like this ?

+	return (hva >= ALIGN(uaddr_start, map_size)) && (hva < ALIGN_DOWN(uaddr_end, map_size));

Otherwise,
Reviewed-by: Nutty Liu <nutty.liu at hotmail.com>

Thanks,
Nutty
>   }
>   
>   static int get_hva_mapping_size(struct kvm *kvm,
> @@ -404,7 +406,7 @@ static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
>   	 * sure that the HVA and GPA are sufficiently aligned and that the
>   	 * block map is contained within the memslot.
>   	 */
> -	if (fault_supports_gstage_huge_mapping(memslot, hva)) {
> +	if (fault_supports_gstage_huge_mapping(memslot, hva, PMD_SIZE)) {
>   		int sz;
>   
>   		sz = get_hva_mapping_size(kvm, hva);


From ruanjinjie at huawei.com  Mon Jun  1 02:47:42 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:42 +0800
Subject: [PATCH v15 00/23] arm64/riscv: Add support for crashkernel CMA reservation
Message-ID: <20260601094805.2928614-1-ruanjinjie@huawei.com>

The crash memory allocation, and the exclude of crashk_res, crashk_low_res
and crashk_cma memory are almost identical across different architectures,
This patch set handle them in crash core in a general way, which eliminate
a lot of duplication code.

And add support for crashkernel CMA reservation for arm64 and riscv.

Also add support for arm64 crash hotplug.

This patch set is rebased on v7.1-rc1.

Basic second kernel boot test were performed on QEMU platforms for x86,
ARM64 and RISC-V architectures with the following parameters:

        "cma=256M crashkernel=4G crashkernel=64M,cma"

For first kernel, there will be such log:

        # dmesg | grep crash
        [    0.000000] crashkernel low memory reserved: 0xe8000000 - 0xf0000000 (128 MB)
        [    0.000000] crashkernel reserved: 0x000000023e600000 - 0x000000033e600000 (4096 MB)
        [    0.000000] crashkernel CMA reserved: 64 MB in 1 ranges

        # dmesg | grep cma
        [    0.000000] cma: Reserved 256 MiB at 0x00000000f0000000
        [    0.000000] cma: Reserved 64 MiB at 0x0000000100000000

For second kernel, there will be such log:

        [    0.000000] OF: fdt: Looking for usable-memory-range property...
        [    0.000000] OF: fdt: cap_mem_regions[0]: base=0x000000023e600000, size=0x0000000100000000
        [    0.000000] OF: fdt: cap_mem_regions[1]: base=0x00000000e8000000, size=0x0000000008000000
        [    0.000000] OF: fdt: cap_mem_regions[2]: base=0x0000000100000000, size=0x0000000004000000

Changes in v15:
- Unify the subject prefix formats as Huacai suggested.
- Fix powerpc pre-existing NULL pointer dereference [Sashiko [1]]
- Fix powerpc pre-existing __merge_memory_ranges() memory range
  truncation [Sashiko [1]].
- Fix pre-existing arm64 CMA page leaks [Sashiko[2]].
- Fix pre-existing crash_load_dm_crypt_keys() Use-After-Free and
  Double Free issue [Sashiko[3]].
- Fix vfree(headers) and uninitialized variables issue
  and simplify the fix [Sashiko[2]].
- As walk_system_ram_res() and for_each_mem_range() use different
  lock, unify and simplify the fix of TOCTOU buffer overflow via memory
  region padding [Sashiko[4]].
- Fix the arm64 crash dump issues in Sashiko[5].
- Link to v14: https://lore.kernel.org/all/20260525084932.934910-1-ruanjinjie at huawei.com/

[1]: https://lore.kernel.org/all/20260525092207.96B9D1F000E9 at smtp.kernel.org/
[2]: https://lore.kernel.org/all/20260525091149.1A1E01F00A3D at smtp.kernel.org/
[3]: https://lore.kernel.org/all/20260525105227.3C2421F000E9 at smtp.kernel.org/
[4]: https://lore.kernel.org/all/20260525095447.944E11F000E9 at smtp.kernel.org/
[5]: https://lore.kernel.org/all/20260525101746.9959D1F000E9 at smtp.kernel.org/

Changes in v14:
- Fix image->elf_headers memory leak during retry loop for arm64 as Sashiko
  AI code review pointed out.
- Solve the hotplug notifier arch_crash_handle_hotplug_event() AA
  self-deadlock problem as Sashiko AI code review pointed out.
- Fix the TOCTOU issue in prepare_elf_headers() by get_online_mems().
- -ENOMEM -> -EAGAIN as Breno suggested.
- Add support for arm64 crash hotplug.
- Link to v13: https://lore.kernel.org/all/20260511030454.1730881-1-ruanjinjie at huawei.com/

Changes in v13:
- Rebased on v7.1-rc1.
- Update the commit message.
- Add Reviewed-by.
- Link to v12: https://lore.kernel.org/all/20260402072701.628293-1-ruanjinjie at huawei.com/

Changes in v12:
- Remove the unused "nr_mem_ranges" for x86.
- Add "Fix crashk_low_res not exclude bug" test log.
- Provide a separate patch for each architecture for using
  crash_prepare_headers(), which will make the review more convenient.
- Add Reviewed-by and Tested-by.
- Link to v11: https://lore.kernel.org/all/20260328074013.3589544-1-ruanjinjie at huawei.com/

Changes in v11:
- Avoid silently drop crash memory if the crash kernel is built without
  CONFIG_CMA.
- Remove unnecessary "cmem->nr_ranges = 0" for arch_crash_populate_cmem()
  as we use kvzalloc().
- Provide a separate patch for each architecture to fix the existing
  buffer overflow issue.
- Add Acked-bys for arm64.

Changes in v10:
- Fix crashk_low_res not excluded bug in the existing
  RISC-V code.
- Fix an existing memory leak issue in the existing PowerPC code.
- Fix the ordering issue of adding CMA ranges to
  "linux,usable-memory-range".
- Fix an existing concurrency issue. A Concurrent memory hotplug may occur
  between reading memblock and attempting to fill cmem during kexec_load()
  for almost all existing architectures.
- Link to v9: https://lore.kernel.org/all/20260323072745.2481719-1-ruanjinjie at huawei.com/

Changes in v9:
- Collect Reviewed-by and Acked-by, and prepare for Sashiko AI review.
- Link to v8: https://lore.kernel.org/all/20260302035315.3892241-1-ruanjinjie at huawei.com/

Changes in v8:
- Fix the build issues reported by kernel test robot and Sourabh.
- Link to v7: https://lore.kernel.org/all/20260226130437.1867658-1-ruanjinjie at huawei.com/

Changes in v7:
- Correct the inclusion of CMA-reserved ranges for kdump kernel in of/kexec
  for arm64 and riscv.
- Add Acked-by.
- Link to v6: https://lore.kernel.org/all/20260224085342.387996-1-ruanjinjie at huawei.com/

Changes in v6:
- Update the crash core exclude code as Mike suggested.
- Rebased on v7.0-rc1.
- Add acked-by.
- Link to v5: https://lore.kernel.org/all/20260212101001.343158-1-ruanjinjie at huawei.com/

Jinjie Ruan (22):
  riscv: kexec_file: Fix crashk_low_res not exclude bug
  powerpc/crash: Fix possible memory leak in update_crash_elfcorehdr()
  powerpc/kexec_file: Fix NULL pointer dereference in
    kexec_extra_fdt_size_ppc64()
  powerpc/kexec_file: Fix memory range truncation in
    __merge_memory_ranges()
  kexec: Extract kexec_free_segment_cma() from kimage_free_cma()
  arm64: kexec_file: Fix CMA page leaks during segment placement retry
    loops
  arm64: kexec_file: Fix image->elf_headers memory leak during retry
    loop
  kexec: Fix UAF and Double Free in crash_load_dm_crypt_keys()
  crash_core: Introduce CRASH_HOTPLUG_SAFETY_PADDING for memory hotplug
    safety
  x86: kexec_file: Fix TOCTOU buffer overflow via memory region padding
  arm64: kexec_file: Fix TOCTOU buffer overflow via memory region
    padding
  riscv: kexec_file: Fix TOCTOU buffer overflow via memory region
    padding
  LoongArch: kexec_file: Fix TOCTOU buffer overflow via memory region
    padding
  crash: Add crash_prepare_headers() to exclude crash kernel memory
  arm64: kexec_file: Use crash_prepare_headers() helper to simplify code
  x86: kexec_file: Use crash_prepare_headers() helper to simplify code
  riscv: kexec_file: Use crash_prepare_headers() helper to simplify code
  LoongArch: kexec_file: Use crash_prepare_headers() helper to simplify
    code
  powerpc/kexec_file: Use crash_exclude_core_ranges() helper
  arm64: kexec_file: Add support for crashkernel CMA reservation
  riscv: kexec_file: Add support for crashkernel CMA reservation
  arm64: crash: Add crash hotplug support

Sourabh Jain (1):
  powerpc/crash: sort crash memory ranges before preparing elfcorehdr

 .../admin-guide/kernel-parameters.txt         |  16 +-
 arch/arm64/Kconfig                            |   3 +
 arch/arm64/include/asm/kexec.h                |  13 ++
 arch/arm64/kernel/Makefile                    |   2 +-
 arch/arm64/kernel/crash.c                     | 152 ++++++++++++++++++
 arch/arm64/kernel/kexec_image.c               |  34 ++++
 arch/arm64/kernel/machine_kexec_file.c        |  78 ++-------
 arch/arm64/mm/init.c                          |   5 +-
 arch/loongarch/kernel/machine_kexec_file.c    |  44 ++---
 arch/powerpc/include/asm/kexec_ranges.h       |   1 -
 arch/powerpc/kexec/crash.c                    |   7 +-
 arch/powerpc/kexec/file_load_64.c             |   3 +
 arch/powerpc/kexec/ranges.c                   | 113 ++-----------
 arch/riscv/kernel/machine_kexec_file.c        |  43 ++---
 arch/riscv/mm/init.c                          |   5 +-
 arch/x86/kernel/crash.c                       |  92 ++---------
 drivers/of/fdt.c                              |   9 +-
 drivers/of/kexec.c                            |   9 ++
 include/linux/crash_core.h                    |  15 ++
 include/linux/crash_reserve.h                 |   4 +-
 include/linux/kexec.h                         |   2 +
 kernel/crash_core.c                           |  89 +++++++++-
 kernel/crash_dump_dm_crypt.c                  |   4 +-
 kernel/kexec_core.c                           |  25 +--
 24 files changed, 430 insertions(+), 338 deletions(-)
 create mode 100644 arch/arm64/kernel/crash.c

-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:44 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:44 +0800
Subject: [PATCH v15 02/23] powerpc/crash: Fix possible memory leak in update_crash_elfcorehdr()
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-3-ruanjinjie@huawei.com>

In get_crash_memory_ranges(), if crash_exclude_mem_range() failed
after realloc_mem_ranges() has successfully allocated the cmem
memory, it just returns an error but leaves cmem pointing to
the allocated memory, nor is it freed in the caller
update_crash_elfcorehdr(), which cause a memory leak, goto out
to free the cmem.

Cc: Sourabh Jain <sourabhjain at linux.ibm.com>
Cc: Hari Bathini <hbathini at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Fixes: 849599b702ef ("powerpc/crash: add crash memory hotplug support")
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/powerpc/kexec/crash.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index e6539f213b3d..a520f851c3a6 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -502,7 +502,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
 	ret = get_crash_memory_ranges(&cmem);
 	if (ret) {
 		pr_err("Failed to get crash mem range\n");
-		return;
+		goto out;
 	}
 
 	/*
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:45 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:45 +0800
Subject: [PATCH v15 03/23] powerpc/kexec_file: Fix NULL pointer dereference in kexec_extra_fdt_size_ppc64()
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-4-ruanjinjie@huawei.com>

A static Sashiko AI review identified a potential NULL pointer dereference
in kexec_extra_fdt_size_ppc64().

When get_reserved_memory_ranges() successfully returns 0 on platforms
without any reserved memory regions, the allocated 'rmem' pointer remains
NULL. Passing this unallocated pointer directly to
kexec_extra_fdt_size_ppc64() leads to a kernel panic when evaluating
'rmem->nr_ranges'.

Fix this by adding a defensive NULL pointer check at the beginning of
kexec_extra_fdt_size_ppc64(), returning 0 extra space immediately if
no reserved memory structure exists.

Cc: Sourabh Jain <sourabhjain at linux.ibm.com>
Cc: Hari Bathini <hbathini at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: stable at vger.kernel.org
Fixes: 0d3ff067331e ("powerpc/kexec_file: fix extra size calculation for kexec FDT")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/powerpc/kexec/file_load_64.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c
index 8c72e12ea44e..fdeedf102c38 100644
--- a/arch/powerpc/kexec/file_load_64.c
+++ b/arch/powerpc/kexec/file_load_64.c
@@ -649,6 +649,9 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *
 	struct device_node *dn;
 	unsigned int cpu_nodes = 0, extra_size = 0;
 
+	if (!rmem)
+		return 0;
+
 	// Budget some space for the password blob. There's already extra space
 	// for the key name
 	if (plpks_is_available())
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:46 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:46 +0800
Subject: [PATCH v15 04/23] powerpc/kexec_file: Fix memory range truncation in __merge_memory_ranges()
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-5-ruanjinjie@huawei.com>

Sashiko AI review pointed out the following issue.

The __merge_memory_ranges() function incorrectly handles overlapping
memory ranges when merging them. Although sort_memory_ranges() sorts all
ranges by their start address in ascending order beforehand, the merge
logic remains defective in two ways:

1. It compares the current range's start against the previous element (i-1)
   instead of the running target index (idx)

2. It unconditionally overwrites 'ranges[idx].end' with 'ranges[i].end'.

This logic flaw leads to critical memory truncation when a larger memory
range completely subsumes subsequent smaller ranges.

For example, consider a sorted input array with three ranges:
  Range A (idx=0): [0x1000 - 0x9000]
  Range B (i=1):   [0x2000 - 0x5000] (completely inside Range A)
  Range C (i=2):   [0x6000 - 0x8000] (completely inside Range A)

1. When i=1 (Range B):
   ranges[1].start (0x2000) <= ranges[0].end + 1 (0x9001) is TRUE.
   The code executes: ranges[0].end = ranges[1].end, which erroneously
   shrinks Range A's end from 0x9000 down to 0x5000.

2. When i=2 (Range C):
   ranges[2].start (0x6000) <= ranges[1].end + 1 (0x5001) is FALSE.
   The code falls into the else block, creating a broken new range.

As a result, valid memory fragments [0x5001 - 0x5fff] and [0x8001 - 0x9000]
are completely lost from the kexec exclude lists, potentially allowing
the crash kernel to overwrite active memory, causing data corruption
or crashes.

Fix this by ensuring the start of the current range is compared against the
end of the active merged range (idx), and use max() to safely prevent the
outer boundary from being truncated.

Cc: Sourabh Jain <sourabhjain at linux.ibm.com>
Cc: Hari Bathini <hbathini at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: stable at vger.kernel.org
Fixes: 180adfc532a8 ("powerpc/kexec_file: Add helper functions for getting memory ranges")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/powerpc/kexec/ranges.c | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c
index 867135560e5c..eb45e89502ca 100644
--- a/arch/powerpc/kexec/ranges.c
+++ b/arch/powerpc/kexec/ranges.c
@@ -21,6 +21,7 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/memblock.h>
+#include <linux/minmax.h>
 #include <linux/crash_core.h>
 #include <asm/sections.h>
 #include <asm/kexec_ranges.h>
@@ -105,19 +106,16 @@ static void __merge_memory_ranges(struct crash_mem *mem_rngs)
 	struct range *ranges;
 	int i, idx;
 
-	if (!mem_rngs)
+	if (!mem_rngs || mem_rngs->nr_ranges <= 1)
 		return;
 
 	idx = 0;
-	ranges = &(mem_rngs->ranges[0]);
+	ranges = mem_rngs->ranges;
 	for (i = 1; i < mem_rngs->nr_ranges; i++) {
-		if (ranges[i].start <= (ranges[i-1].end + 1))
-			ranges[idx].end = ranges[i].end;
+		if (ranges[i].start <= (ranges[idx].end + 1))
+			ranges[idx].end = max(ranges[idx].end, ranges[i].end);
 		else {
 			idx++;
-			if (i == idx)
-				continue;
-
 			ranges[idx] = ranges[i];
 		}
 	}
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:43 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:43 +0800
Subject: [PATCH v15 01/23] riscv: kexec_file: Fix crashk_low_res not exclude bug
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-2-ruanjinjie@huawei.com>

As done in commit 944a45abfabc ("arm64: kdump: Reimplement crashkernel=X")
and commit 4831be702b95 ("arm64/kexec: Fix missing extra range for
crashkres_low.") for arm64, while implementing crashkernel=X,[high,low],
riscv should have excluded the "crashk_low_res" reserved ranges from
the crash kernel memory to prevent them from being exported through
/proc/vmcore, and the exclusion would need an extra crash_mem range.

Just simply tested on qemu with crashkernel=4G with kexec in [1] mentioned
in [2]. And the second kernel can be started normally.

	# dmesg | grep crash
	[    0.000000] crashkernel low memory reserved: 0xf8000000 - 0x100000000 (128 MB)
	[    0.000000] crashkernel reserved: 0x000000017fe00000 - 0x000000027fe00000 (4096 MB)

Cc: Guo Ren <guoren at kernel.org>
Cc: Baoquan He <bhe at redhat.com>
[1]: https://github.com/chenjh005/kexec-tools/tree/build-test-riscv-v2
[2]: https://lore.kernel.org/all/20230726175000.2536220-1-chenjiahao16 at huawei.com/
Fixes: 5882e5acf18d ("riscv: kdump: Implement crashkernel=X,[high,low]")
Reviewed-by: Guo Ren <guoren at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/riscv/kernel/machine_kexec_file.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 54e2d9552e93..3f7766057cac 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -61,7 +61,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
 	unsigned int nr_ranges;
 	int ret;
 
-	nr_ranges = 1; /* For exclusion of crashkernel region */
+	nr_ranges = 2; /* For exclusion of crashkernel region */
 	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
 
 	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
@@ -76,8 +76,16 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
 
 	/* Exclude crashkernel region */
 	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (!ret)
-		ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
+	if (ret)
+		goto out;
+
+	if (crashk_low_res.end) {
+		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+		if (ret)
+			goto out;
+	}
+
+	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
 
 out:
 	kfree(cmem);
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:47 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:47 +0800
Subject: [PATCH v15 05/23] powerpc/crash: sort crash memory ranges before preparing elfcorehdr
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-6-ruanjinjie@huawei.com>

From: Sourabh Jain <sourabhjain at linux.ibm.com>

During a memory hot-remove event, the elfcorehdr is rebuilt to exclude
the removed memory. While updating the crash memory ranges for this
operation, the crash memory ranges array can become unsorted. This
happens because remove_mem_range() may split a memory range into two
parts and append the higher-address part as a separate range at the end
of the array.

So far, no issues have been observed due to the unsorted crash memory
ranges. However, this could lead to problems once crash memory range
removal is handled by generic code, as introduced in the upcoming
patches in this series.

Currently, powerpc uses a platform-specific function,
remove_mem_range(), to exclude hot-removed memory from the crash memory
ranges. This function performs the same task as the generic
crash_exclude_mem_range() in crash_core.c. The generic helper also
ensures that the crash memory ranges remain sorted. So remove the
redundant powerpc-specific implementation and instead call
crash_exclude_mem_range_guarded() (which internally calls
crash_exclude_mem_range()) to exclude the hot-removed memory ranges.

Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Baoquan he <bhe at redhat.com>
Cc: Jinjie Ruan <ruanjinjie at huawei.com>
Cc: Hari Bathini <hbathini at linux.ibm.com>
Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
Cc: Mahesh Salgaonkar <mahesh at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Cc: Shivang Upadhyay <shivangu at linux.ibm.com>
Cc: linux-kernel at vger.kernel.org
Acked-by: Baoquan He <bhe at redhat.com>
Reviewed-by: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/powerpc/include/asm/kexec_ranges.h |  4 +-
 arch/powerpc/kexec/crash.c              |  5 +-
 arch/powerpc/kexec/ranges.c             | 87 +------------------------
 3 files changed, 7 insertions(+), 89 deletions(-)

diff --git a/arch/powerpc/include/asm/kexec_ranges.h b/arch/powerpc/include/asm/kexec_ranges.h
index 14055896cbcb..ad95e3792d10 100644
--- a/arch/powerpc/include/asm/kexec_ranges.h
+++ b/arch/powerpc/include/asm/kexec_ranges.h
@@ -7,7 +7,9 @@
 void sort_memory_ranges(struct crash_mem *mrngs, bool merge);
 struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges);
 int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
-int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
+int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
+				    unsigned long long mstart,
+				    unsigned long long mend);
 int get_exclude_memory_ranges(struct crash_mem **mem_ranges);
 int get_reserved_memory_ranges(struct crash_mem **mem_ranges);
 int get_crash_memory_ranges(struct crash_mem **mem_ranges);
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index a520f851c3a6..d634db67becc 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -493,7 +493,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
 	struct crash_mem *cmem = NULL;
 	struct kexec_segment *ksegment;
 	void *ptr, *mem, *elfbuf = NULL;
-	unsigned long elfsz, memsz, base_addr, size;
+	unsigned long elfsz, memsz, base_addr, size, end;
 
 	ksegment = &image->segment[image->elfcorehdr_index];
 	mem = (void *) ksegment->mem;
@@ -512,7 +512,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
 	if (image->hp_action == KEXEC_CRASH_HP_REMOVE_MEMORY) {
 		base_addr = PFN_PHYS(mn->start_pfn);
 		size = mn->nr_pages * PAGE_SIZE;
-		ret = remove_mem_range(&cmem, base_addr, size);
+		end = base_addr + size - 1;
+		ret = crash_exclude_mem_range_guarded(&cmem, base_addr, end);
 		if (ret) {
 			pr_err("Failed to remove hot-unplugged memory from crash memory ranges\n");
 			goto out;
diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c
index eb45e89502ca..b2fb78562cdc 100644
--- a/arch/powerpc/kexec/ranges.c
+++ b/arch/powerpc/kexec/ranges.c
@@ -551,7 +551,7 @@ int get_usable_memory_ranges(struct crash_mem **mem_ranges)
 #endif /* CONFIG_KEXEC_FILE */
 
 #ifdef CONFIG_CRASH_DUMP
-static int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
+int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
 					   unsigned long long mstart,
 					   unsigned long long mend)
 {
@@ -639,89 +639,4 @@ int get_crash_memory_ranges(struct crash_mem **mem_ranges)
 		pr_err("Failed to setup crash memory ranges\n");
 	return ret;
 }
-
-/**
- * remove_mem_range - Removes the given memory range from the range list.
- * @mem_ranges:    Range list to remove the memory range to.
- * @base:          Base address of the range to remove.
- * @size:          Size of the memory range to remove.
- *
- * (Re)allocates memory, if needed.
- *
- * Returns 0 on success, negative errno on error.
- */
-int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
-{
-	u64 end;
-	int ret = 0;
-	unsigned int i;
-	u64 mstart, mend;
-	struct crash_mem *mem_rngs = *mem_ranges;
-
-	if (!size)
-		return 0;
-
-	/*
-	 * Memory range are stored as start and end address, use
-	 * the same format to do remove operation.
-	 */
-	end = base + size - 1;
-
-	for (i = 0; i < mem_rngs->nr_ranges; i++) {
-		mstart = mem_rngs->ranges[i].start;
-		mend = mem_rngs->ranges[i].end;
-
-		/*
-		 * Memory range to remove is not part of this range entry
-		 * in the memory range list
-		 */
-		if (!(base >= mstart && end <= mend))
-			continue;
-
-		/*
-		 * Memory range to remove is equivalent to this entry in the
-		 * memory range list. Remove the range entry from the list.
-		 */
-		if (base == mstart && end == mend) {
-			for (; i < mem_rngs->nr_ranges - 1; i++) {
-				mem_rngs->ranges[i].start = mem_rngs->ranges[i+1].start;
-				mem_rngs->ranges[i].end = mem_rngs->ranges[i+1].end;
-			}
-			mem_rngs->nr_ranges--;
-			goto out;
-		}
-		/*
-		 * Start address of the memory range to remove and the
-		 * current memory range entry in the list is same. Just
-		 * move the start address of the current memory range
-		 * entry in the list to end + 1.
-		 */
-		else if (base == mstart) {
-			mem_rngs->ranges[i].start = end + 1;
-			goto out;
-		}
-		/*
-		 * End address of the memory range to remove and the
-		 * current memory range entry in the list is same.
-		 * Just move the end address of the current memory
-		 * range entry in the list to base - 1.
-		 */
-		else if (end == mend)  {
-			mem_rngs->ranges[i].end = base - 1;
-			goto out;
-		}
-		/*
-		 * Memory range to remove is not at the edge of current
-		 * memory range entry. Split the current memory entry into
-		 * two half.
-		 */
-		else {
-			size = mem_rngs->ranges[i].end - end + 1;
-			mem_rngs->ranges[i].end = base - 1;
-			ret = add_mem_range(mem_ranges, end + 1, size);
-		}
-	}
-out:
-	return ret;
-}
 #endif /* CONFIG_CRASH_DUMP */
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:48 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:48 +0800
Subject: [PATCH v15 06/23] kexec: Extract kexec_free_segment_cma() from kimage_free_cma()
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-7-ruanjinjie@huawei.com>

The generic kimage_free_cma() relies on `image->nr_segments` to iterate
and free allocated CMA pages. However, during architecture-specific
segment placement retry loops (e.g., arm64's image_load()), a mid-way
failure will truncate `image->nr_segments` back to its initial value.
This truncation permanently hides any CMA pages allocated outside the
new boundary from global cleanup, causing silent background memory leaks.

To allow architecture-specific loaders to execute fine-grained memory
reclamation before truncation occurs, extract the single-pass CMA release
logic into a dedicated and exported helper:

	void kexec_free_segment_cma(struct kimage *image, unsigned long idx);

Refactor the main kimage_free_cma() to invoke this helper sequentially
to maintain backward compatibility while expanding single-slot flexibility.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/kexec.h |  2 ++
 kernel/kexec_core.c   | 25 ++++++++++++++-----------
 2 files changed, 16 insertions(+), 11 deletions(-)

diff --git a/include/linux/kexec.h b/include/linux/kexec.h
index 8a22bc9b8c6c..6f1eabda0300 100644
--- a/include/linux/kexec.h
+++ b/include/linux/kexec.h
@@ -532,6 +532,7 @@ extern bool kexec_file_dbg_print;
 
 extern void *kimage_map_segment(struct kimage *image, int idx);
 extern void kimage_unmap_segment(void *buffer);
+extern void kexec_free_segment_cma(struct kimage *image, unsigned long idx);
 #else /* !CONFIG_KEXEC_CORE */
 struct pt_regs;
 struct task_struct;
@@ -543,6 +544,7 @@ static inline int kexec_crash_loaded(void) { return 0; }
 static inline void *kimage_map_segment(struct kimage *image, int idx)
 { return NULL; }
 static inline void kimage_unmap_segment(void *buffer) { }
+static inline void kexec_free_segment_cma(struct kimage *image, unsigned long idx) { }
 #define kexec_in_progress false
 #endif /* CONFIG_KEXEC_CORE */
 
diff --git a/kernel/kexec_core.c b/kernel/kexec_core.c
index a43d2da0fe3e..9195f81e53c4 100644
--- a/kernel/kexec_core.c
+++ b/kernel/kexec_core.c
@@ -554,22 +554,25 @@ static void kimage_free_entry(kimage_entry_t entry)
 	kimage_free_pages(page);
 }
 
-static void kimage_free_cma(struct kimage *image)
+void kexec_free_segment_cma(struct kimage *image, unsigned long idx)
 {
-	unsigned long i;
+	u32 nr_pages = image->segment[idx].memsz >> PAGE_SHIFT;
+	struct page *cma = image->segment_cma[idx];
 
-	for (i = 0; i < image->nr_segments; i++) {
-		struct page *cma = image->segment_cma[i];
-		u32 nr_pages = image->segment[i].memsz >> PAGE_SHIFT;
+	if (!cma)
+		return;
 
-		if (!cma)
-			continue;
+	arch_kexec_pre_free_pages(page_address(cma), nr_pages);
+	dma_release_from_contiguous(NULL, cma, nr_pages);
+	image->segment_cma[idx] = NULL;
+}
 
-		arch_kexec_pre_free_pages(page_address(cma), nr_pages);
-		dma_release_from_contiguous(NULL, cma, nr_pages);
-		image->segment_cma[i] = NULL;
-	}
+static void kimage_free_cma(struct kimage *image)
+{
+	unsigned long i;
 
+	for (i = 0; i < image->nr_segments; i++)
+		kexec_free_segment_cma(image, i);
 }
 
 void kimage_free(struct kimage *image)
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:49 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:49 +0800
Subject: [PATCH v15 07/23] arm64: kexec_file: Fix CMA page leaks during segment placement retry loops
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-8-ruanjinjie@huawei.com>

Sashiko AI code review pointed out, during arm64 kexec image placement
retry loops in image_load(), the loader repeatedly attempts to find
a suitable memory hole for the kernel and its associated segments
(initrd, dtb, etc.). When a placement attempt fails midway, the core
framework rolls back `image->nr_segments` to its initial state to purge
the failed segments logically.

However, this truncation causes a severe background memory leak. Any CMA
pages successfully allocated via kexec_add_buffer() during the failed
attempt are recorded in the `image->segment_cma` array. Since
the subsequent global kimage_free_cma() cleanup only iterates up to
the truncated (smaller) `nr_segments` boundary, these allocated CMA pages
outside the new boundary become completely orphaned and permanently leaked.

Fix this by leverage the newly introduced generic kexec_free_segment_cma()
helper to execute fine-grained memory reclamation before any truncation
occurs:

1. In image_load(), explicitly invoke kexec_free_segment_cma() to release
   the CMA buffer allocated for the current failed kernel segment before
   decrementing `image->nr_segments`.

2. In the error path of load_other_segments(), iterate backward from the
   failed segment index down to `orig_segments`, sequentially freeing each
   orphan CMA segment allocation before restoring the initial segment
   count.

This guarantees that all temporary CMA pages allocated during placement
failures are cleanly returned to the contiguous memory allocator,
eliminating silent background memory leaks across all retry paths.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Breno Leitao <leitao at debian.org>
Cc: Pratyush Yadav <pratyush at kernel.org>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Yeoreum Yun <yeoreum.yun at arm.com>
Cc: Kees Cook <kees at kernel.org>
Cc: "Rob Herring (Arm)" <robh at kernel.org>
Cc: Baoquan He <bhe at redhat.com>
Cc: Coiby Xu <coxu at redhat.com>
Cc: Alexander Graf <graf at amazon.com>
Cc: Pasha Tatashin <pasha.tatashin at soleen.com>
Cc: stable at vger.kernel.org
Fixes: 07d24902977e4 ("kexec: enable CMA based contiguous allocation")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/kexec_image.c        | 1 +
 arch/arm64/kernel/machine_kexec_file.c | 5 ++++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
index b70f4df15a1a..ffcb7f9075e6 100644
--- a/arch/arm64/kernel/kexec_image.c
+++ b/arch/arm64/kernel/kexec_image.c
@@ -107,6 +107,7 @@ static void *image_load(struct kimage *image,
 		 * We couldn't find space for the other segments; erase the
 		 * kernel segment and try the next available hole.
 		 */
+		kexec_free_segment_cma(image, kernel_segment_number);
 		image->nr_segments -= 1;
 		kbuf.buf_min = kernel_segment->mem + kernel_segment->memsz;
 		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index e31fabed378a..13c247c28866 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -195,7 +195,10 @@ int load_other_segments(struct kimage *image,
 	return 0;
 
 out_err:
-	image->nr_segments = orig_segments;
+	while (image->nr_segments > orig_segments) {
+		kexec_free_segment_cma(image, image->nr_segments - 1);
+		image->nr_segments--;
+	}
 	kvfree(dtb);
 	return ret;
 }
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:50 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:50 +0800
Subject: [PATCH v15 08/23] arm64: kexec_file: Fix image->elf_headers memory leak during retry loop
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-9-ruanjinjie@huawei.com>

Sashiko AI code review pointed out a potential memory leak of
image->elf_headers when load_other_segments() fails on error paths.

In the arm64 kexec_file file-load path, kexec_image.c runs a retry loop
calling kexec_add_buffer() to find a suitable location for the kernel
segment. On each iteration, load_other_segments() is invoked to allocate
and populate alternative segments such as initrd, DTB, and ELF headers.

However, if a placement or allocation failure occurs later in
load_other_segments() (e.g., when adding initrd or dtb), the execution
jumps to the out_err label. While this path restores image->nr_segments
via orig_segments, it returns an error back to the caller without freeing
the previously allocated image->elf_headers vmalloc buffer.

As a result, the retry loop in image_load() unconditionally allocates
new ELF headers on the next iteration and overwrites image->elf_headers,
permanently leaking the memory blocks allocated in previous iterations.

To fix this, decouple the ELF header allocation from the target-seeking
retry loop. Since the contents and size of ELF headers only depend on
the host memory layout and do not change with the kernel's physical
placement, move prepare_elf_headers() completely outside and prior to
the while retry loop in image_load().

And if kexec_add_buffer() for elf headers fails, not need to vfree
headers, because the err path will vfree `image->elf_headers` by calling
arch_kimage_file_post_load_cleanup().

This optimization eliminates redundant memory allocation/deallocation
overhead during kexec placement retries and eradicates the Use-After-Free
and memory leak risk.

Concurrently, remove the prepare_elf_headers() call from inside
load_other_segments() and have it directly reuse the single, pre-allocated
image->elf_headers.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Thomas Huth <thuth at redhat.com>
Cc: Breno Leitao <leitao at debian.org>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Yeoreum Yun <yeoreum.yun at arm.com>
Cc: Coiby Xu <coxu at redhat.com>
Cc: Baoquan He <bhe at redhat.com>
Cc: Kees Cook <kees at kernel.org>
Cc: Benjamin Gwin <bgwin at google.com>
Cc: stable at vger.kernel.org
Fixes: 108aa503657e ("arm64: kexec_file: try more regions if loading segments fails")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
v15:
- Use image->elf_headers and image->elf_headers_sz instead of adding function
  parameters for load_other_segments() to simplify the fix.
---
 arch/arm64/include/asm/kexec.h         |  1 +
 arch/arm64/kernel/kexec_image.c        | 16 ++++++++++++++++
 arch/arm64/kernel/machine_kexec_file.c | 23 +++++------------------
 3 files changed, 22 insertions(+), 18 deletions(-)

diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 892e5bebda95..7ffa2ff5fcfd 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -128,6 +128,7 @@ extern int load_other_segments(struct kimage *image,
 		unsigned long kernel_load_addr, unsigned long kernel_size,
 		char *initrd, unsigned long initrd_len,
 		char *cmdline);
+extern int prepare_elf_headers(void **addr, unsigned long *sz);
 #endif
 
 #endif /* __ASSEMBLER__ */
diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
index ffcb7f9075e6..424b9527db09 100644
--- a/arch/arm64/kernel/kexec_image.c
+++ b/arch/arm64/kernel/kexec_image.c
@@ -89,6 +89,22 @@ static void *image_load(struct kimage *image,
 
 	kernel_segment_number = image->nr_segments;
 
+#ifdef CONFIG_CRASH_DUMP
+	if (image->type == KEXEC_TYPE_CRASH) {
+		/* load elf core header */
+		unsigned long headers_sz;
+		void *headers;
+
+		ret = prepare_elf_headers(&headers, &headers_sz);
+		if (ret) {
+			pr_err("Preparing elf core header failed\n");
+			return ERR_PTR(ret);
+		}
+		image->elf_headers = headers;
+		image->elf_headers_sz = headers_sz;
+	}
+#endif
+
 	/*
 	 * The location of the kernel segment may make it impossible to satisfy
 	 * the other segment requirements, so we try repeatedly to find a
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 13c247c28866..4cbb71e1f8ed 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -40,7 +40,7 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 }
 
 #ifdef CONFIG_CRASH_DUMP
-static int prepare_elf_headers(void **addr, unsigned long *sz)
+int prepare_elf_headers(void **addr, unsigned long *sz)
 {
 	struct crash_mem *cmem;
 	unsigned int nr_ranges;
@@ -105,32 +105,19 @@ int load_other_segments(struct kimage *image,
 	kbuf.buf_min = kernel_load_addr + kernel_size;
 
 #ifdef CONFIG_CRASH_DUMP
-	/* load elf core header */
-	void *headers;
-	unsigned long headers_sz;
 	if (image->type == KEXEC_TYPE_CRASH) {
-		ret = prepare_elf_headers(&headers, &headers_sz);
-		if (ret) {
-			pr_err("Preparing elf core header failed\n");
-			goto out_err;
-		}
-
-		kbuf.buffer = headers;
-		kbuf.bufsz = headers_sz;
+		kbuf.buffer = image->elf_headers;
+		kbuf.bufsz = image->elf_headers_sz;
 		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
-		kbuf.memsz = headers_sz;
+		kbuf.memsz = image->elf_headers_sz;
 		kbuf.buf_align = SZ_64K; /* largest supported page size */
 		kbuf.buf_max = ULONG_MAX;
 		kbuf.top_down = true;
 
 		ret = kexec_add_buffer(&kbuf);
-		if (ret) {
-			vfree(headers);
+		if (ret)
 			goto out_err;
-		}
-		image->elf_headers = headers;
 		image->elf_load_addr = kbuf.mem;
-		image->elf_headers_sz = headers_sz;
 
 		kexec_dprintk("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
 			      image->elf_load_addr, kbuf.bufsz, kbuf.memsz);
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:51 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:51 +0800
Subject: [PATCH v15 09/23] kexec: Fix UAF and Double Free in crash_load_dm_crypt_keys()
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-10-ruanjinjie@huawei.com>

A static memory safety review by Sashiko AI identified a high-severity
Use-After-Free (UAF) and Double Free vulnerability in the dm-crypt keys
handling path during arm64 kexec image placement retry loops.

In crash_load_dm_crypt_keys(), when the segment allocation fails via
kexec_add_buffer(), the error path invokes `kvfree((void *)kbuf.buffer)`
to reclaim the keys buffer. However, the global pointer `keys_header` is
left dangling with a stale address, creating an insecure memory trap.

When the top-level loader image_load() retries the next available placement
hole, crash_load_dm_crypt_keys() is re-entered. Since `is_dm_key_reused`
is a read-only global configuration managed by user-space configfs,
it cannot be mutated by the kernel. If it remains true, the loader skips
build_keys_header() and blindly reuses the stale `keys_header` pointer
for kbuf.buffer, triggering a severe Use-After-Free or a Null pointer
dereference during kexec_add_buffer(). Alternatively, a new headers build
can trigger a recursive Double Free inside build_keys_header().

Fix this by setting the global `keys_header` to NULL immediately after
it is freed in the failure path. Concurrently, upgrade the header
regeneration check to a composite condition:
	`if (!is_dm_key_reused || !keys_header)`

This ensures that if a previous retry attempt wiped the buffer, the kernel
will automatically and safely trigger a fresh header regeneration
internally without modifying the user-configured `is_dm_key_reused` state
flag, achieving absolute data consistency and memory safety across all
retry paths.

Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Baoquan He <bhe at redhat.com>
Cc: Mike Rapoport <rppt at kernel.org>
Cc: Pasha Tatashin <pasha.tatashin at soleen.com>
Cc: Pratyush Yadav <pratyush at kernel.org>
Cc: Dave Young <ruirui.yang at linux.dev>
Cc: stable at vger.kernel.org
Fixes: e3a84be1ec2f ("arm64,ppc64le/kdump: pass dm-crypt keys to kdump kernel")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 kernel/crash_dump_dm_crypt.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/crash_dump_dm_crypt.c b/kernel/crash_dump_dm_crypt.c
index cb875ddb6ba6..2c5462876337 100644
--- a/kernel/crash_dump_dm_crypt.c
+++ b/kernel/crash_dump_dm_crypt.c
@@ -412,13 +412,12 @@ int crash_load_dm_crypt_keys(struct kimage *image)
 	};
 	int r;
 
-
 	if (key_count <= 0) {
 		kexec_dprintk("No dm-crypt keys\n");
 		return 0;
 	}
 
-	if (!is_dm_key_reused) {
+	if (!is_dm_key_reused || unlikely(!keys_header)) {
 		image->dm_crypt_keys_addr = 0;
 		r = build_keys_header();
 		if (r) {
@@ -437,6 +436,7 @@ int crash_load_dm_crypt_keys(struct kimage *image)
 	if (r) {
 		pr_err("Failed to call kexec_add_buffer, ret=%d\n", r);
 		kvfree((void *)kbuf.buffer);
+		keys_header = NULL;
 		return r;
 	}
 	image->dm_crypt_keys_addr = kbuf.mem;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:52 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:52 +0800
Subject: [PATCH v15 10/23] crash_core: Introduce CRASH_HOTPLUG_SAFETY_PADDING for memory hotplug safety
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-11-ruanjinjie@huawei.com>

Introduce CRASH_HOTPLUG_SAFETY_PADDING to allocate extra slots
for the crash memory ranges array, mitigating potential TOCTOU races
caused by concurrent memory hotplug events. When CONFIG_MEMORY_HOTPLUG
is disabled, the padding safely defaults to 0 as the memory
layout remains static.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/crash_core.h | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index c1dee3f971a9..d4762e000098 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -14,6 +14,12 @@ struct crash_mem {
 	struct range ranges[] __counted_by(max_nr_ranges);
 };
 
+#ifdef CONFIG_MEMORY_HOTPLUG
+#define CRASH_HOTPLUG_SAFETY_PADDING 128
+#else
+#define CRASH_HOTPLUG_SAFETY_PADDING 0
+#endif
+
 #ifdef CONFIG_CRASH_DUMP
 
 int crash_shrink_memory(unsigned long new_size);
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:53 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:53 +0800
Subject: [PATCH v15 11/23] x86: kexec_file: Fix TOCTOU buffer overflow via memory region padding
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-12-ruanjinjie@huawei.com>

Sashiko AI code review pointed out there is a TOCTOU (Time-of-Check to
Time-of-Use) race condition in prepare_elf_headers() between the initial
pass that counts System RAM ranges and the second pass that populates them.
If a memory hotplug event occurs between these two steps, the number of
memory regions may increase, causing an out-of-bounds write to
the cmem->ranges[] array.

Fix this fundamentally by using `CRASH_HOTPLUG_SAFETY_PADDING`(128 slots)
to expand the flexible array allocation ceiling upfront. This safely
absorbs any concurrent memory region expansion. Concurrently, add
a defensive boundary check inside the callback to return -EAGAIN
on unexpected overrun, fully eradicating the overflow window and ensuring
system stability.

Cc: AKASHI Takahiro <takahiro.akashi at linaro.org>
Cc: Thomas Gleixner <tglx at kernel.org>
Cc: Ingo Molnar <mingo at redhat.com>
Cc: Borislav Petkov <bp at alien8.de>
Cc: "H. Peter Anvin" <hpa at zytor.com>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Baoquan He <bhe at redhat.com>
Cc: Mike Rapoport <rppt at kernel.org>
Cc: stable at vger.kernel.org
Fixes: 8d5f894a3108 ("x86: kexec_file: lift CRASH_MAX_RANGES limit on crash_mem buffer")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/x86/kernel/crash.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index cd796818d94d..a1089907728d 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -177,7 +177,7 @@ static struct crash_mem *fill_up_crash_elf_data(void)
 	 * But in order to lest the low 1M could be changed in the future,
 	 * (e.g. [start, 1M]), add a extra slot.
 	 */
-	nr_ranges += 3 + crashk_cma_cnt;
+	nr_ranges += 3 + crashk_cma_cnt + CRASH_HOTPLUG_SAFETY_PADDING;
 	cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
 	if (!cmem)
 		return NULL;
@@ -226,6 +226,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 {
 	struct crash_mem *cmem = arg;
 
+	if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges))
+		return -EAGAIN;
+
 	cmem->ranges[cmem->nr_ranges].start = res->start;
 	cmem->ranges[cmem->nr_ranges].end = res->end;
 	cmem->nr_ranges++;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:54 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:54 +0800
Subject: [PATCH v15 12/23] arm64: kexec_file: Fix TOCTOU buffer overflow via memory region padding
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-13-ruanjinjie@huawei.com>

Sashiko AI code review pointed out there is a TOCTOU (Time-of-Check to
Time-of-Use) race condition in prepare_elf_headers() between the initial
pass that counts System RAM ranges and the second pass that populates them.
If a memory hotplug event occurs between these two steps, the number of
memory regions may increase, causing an out-of-bounds write to
the cmem->ranges[] array.

Fix this fundamentally by using `CRASH_HOTPLUG_SAFETY_PADDING`
(128 slots) to expand the flexible array allocation ceiling upfront.
This safely absorbs any concurrent memory region expansion. Concurrently,
add a defensive boundary check to return -EAGAIN on unexpected overrun,
fully eradicating the overflow window and ensuring system stability.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will.deacon at arm.com>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Baoquan He <bhe at redhat.com>
Cc: Breno Leitao <leitao at debian.org>
Cc: stable at vger.kernel.org
Fixes: 3751e728cef2 ("arm64: kexec_file: add crash dump support")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/machine_kexec_file.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 4cbb71e1f8ed..8a96fb68b88d 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -48,7 +48,8 @@ int prepare_elf_headers(void **addr, unsigned long *sz)
 	u64 i;
 	phys_addr_t start, end;
 
-	nr_ranges = 2; /* for exclusion of crashkernel region */
+	/* for exclusion of crashkernel region */
+	nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
 	for_each_mem_range(i, &start, &end)
 		nr_ranges++;
 
@@ -59,6 +60,11 @@ int prepare_elf_headers(void **addr, unsigned long *sz)
 	cmem->max_nr_ranges = nr_ranges;
 	cmem->nr_ranges = 0;
 	for_each_mem_range(i, &start, &end) {
+		if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges)) {
+			ret = -EAGAIN;
+			goto out;
+		}
+
 		cmem->ranges[cmem->nr_ranges].start = start;
 		cmem->ranges[cmem->nr_ranges].end = end - 1;
 		cmem->nr_ranges++;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:55 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:55 +0800
Subject: [PATCH v15 13/23] riscv: kexec_file: Fix TOCTOU buffer overflow via memory region padding
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-14-ruanjinjie@huawei.com>

Sashiko AI code review pointed out there is a TOCTOU (Time-of-Check to
Time-of-Use) race condition in prepare_elf_headers() between the initial
pass that counts System RAM ranges and the second pass that populates them.
If a memory hotplug event occurs between these two steps, the number of
memory regions may increase, causing an out-of-bounds write to
the cmem->ranges[] array.

Fix this fundamentally by using `CRASH_HOTPLUG_SAFETY_PADDING` (128 slots)
to expand the flexible array allocation ceiling upfront. This safely
absorbs any concurrent memory region expansion. Concurrently, add
a defensive boundary check inside the callback to return -EAGAIN on
unexpected overrun, fully eradicating the overflow window and ensuring
system stability.

Cc: Paul Walmsley <pjw at kernel.org>
Cc: Palmer Dabbelt <palmer at dabbelt.com>
Cc: Albert Ou <aou at eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex at ghiti.fr>
Cc: songshuaishuai at tinylab.org
Cc: bjorn at rivosinc.com
Cc: leitao at debian.org
Fixes: 8acea455fafa ("RISC-V: Support for kexec_file on panic")
Reviewed-by: Guo Ren <guoren at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/riscv/kernel/machine_kexec_file.c | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 3f7766057cac..f3576dc0513f 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -48,6 +48,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 {
 	struct crash_mem *cmem = arg;
 
+	if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges))
+		return -EAGAIN;
+
 	cmem->ranges[cmem->nr_ranges].start = res->start;
 	cmem->ranges[cmem->nr_ranges].end = res->end;
 	cmem->nr_ranges++;
@@ -61,7 +64,8 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
 	unsigned int nr_ranges;
 	int ret;
 
-	nr_ranges = 2; /* For exclusion of crashkernel region */
+	/* For exclusion of crashkernel region */
+	nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
 	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
 
 	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:56 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:56 +0800
Subject: [PATCH v15 14/23] LoongArch: kexec_file: Fix TOCTOU buffer overflow via memory region padding
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-15-ruanjinjie@huawei.com>

Sashiko AI code review pointed out there is a TOCTOU (Time-of-Check to
Time-of-Use) race condition in prepare_elf_headers() between the initial
pass that counts System RAM ranges and the second pass that populates them.
If a memory hotplug event occurs between these two steps, the number of
memory regions may increase, causing an out-of-bounds write to
the cmem->ranges[] array.

Fix this fundamentally by using `CRASH_HOTPLUG_SAFETY_PADDING` (128 slots)
to expand the flexible array allocation ceiling upfront. This safely
absorbs any concurrent memory region expansion. Concurrently, add
a defensive boundary check to return -EAGAIN on unexpected overrun,
fully eradicating the overflow window and ensuring system stability.

Cc: Youling Tang <tangyouling at kylinos.cn>
Cc: Huacai Chen <chenhuacai at loongson.cn>
Cc: WANG Xuerui <kernel at xen0n.name>
Cc: stable at vger.kernel.org
Fixes: 1bcca8620a91 ("LoongArch: Add crash dump support for kexec_file")
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/loongarch/kernel/machine_kexec_file.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
index 5584b798ba46..3c369124586e 100644
--- a/arch/loongarch/kernel/machine_kexec_file.c
+++ b/arch/loongarch/kernel/machine_kexec_file.c
@@ -64,7 +64,8 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
 	phys_addr_t start, end;
 	struct crash_mem *cmem;
 
-	nr_ranges = 2; /* for exclusion of crashkernel region */
+	/* for exclusion of crashkernel region */
+	nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
 	for_each_mem_range(i, &start, &end)
 		nr_ranges++;
 
@@ -75,6 +76,11 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
 	cmem->max_nr_ranges = nr_ranges;
 	cmem->nr_ranges = 0;
 	for_each_mem_range(i, &start, &end) {
+		if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges)) {
+			ret = -EAGAIN;
+			goto out;
+		}
+
 		cmem->ranges[cmem->nr_ranges].start = start;
 		cmem->ranges[cmem->nr_ranges].end = end - 1;
 		cmem->nr_ranges++;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:57 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:57 +0800
Subject: [PATCH v15 15/23] crash: Add crash_prepare_headers() to exclude crash kernel memory
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-16-ruanjinjie@huawei.com>

The crash memory alloc, and the exclude of crashk_res, crashk_low_res
and crashk_cma memory are almost identical across different architectures,
handling them in the crash core would eliminate a lot of duplication, so
add crash_prepare_headers() helper to handle them in the common code.

To achieve the above goal, three architecture-specific functions are
introduced:

- arch_get_system_nr_ranges(). Pre-counts the max number of memory ranges.

- arch_crash_populate_cmem(). Collects the memory ranges and fills them
  into cmem.

- arch_crash_exclude_ranges(). Architecture's additional crash memory
  ranges exclusion, defaulting to empty.

Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/crash_core.h |  5 +++
 kernel/crash_core.c        | 82 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index d4762e000098..43baf9c87355 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -65,6 +65,8 @@ extern int crash_exclude_mem_range(struct crash_mem *mem,
 				   unsigned long long mend);
 extern int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
 				       void **addr, unsigned long *sz);
+extern int crash_prepare_headers(int need_kernel_map, void **addr,
+				 unsigned long *sz, unsigned long *nr_mem_ranges);
 
 struct kimage;
 struct kexec_segment;
@@ -82,6 +84,9 @@ int kexec_should_crash(struct task_struct *p);
 int kexec_crash_loaded(void);
 void crash_save_cpu(struct pt_regs *regs, int cpu);
 extern int kimage_crash_copy_vmcoreinfo(struct kimage *image);
+extern unsigned int arch_get_system_nr_ranges(void);
+extern int arch_crash_populate_cmem(struct crash_mem *cmem);
+extern int arch_crash_exclude_ranges(struct crash_mem *cmem);
 
 #else /* !CONFIG_CRASH_DUMP*/
 struct pt_regs;
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4f21fc3b108b..481babc29131 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -168,9 +168,6 @@ static inline resource_size_t crash_resource_size(const struct resource *res)
 	return !res->end ? 0 : resource_size(res);
 }
 
-
-
-
 int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
 			  void **addr, unsigned long *sz)
 {
@@ -272,6 +269,85 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
 	return 0;
 }
 
+static struct crash_mem *alloc_cmem(unsigned int nr_ranges)
+{
+	struct crash_mem *cmem;
+
+	cmem = kvzalloc_flex(*cmem, ranges, nr_ranges);
+	if (!cmem)
+		return NULL;
+
+	cmem->max_nr_ranges = nr_ranges;
+	return cmem;
+}
+
+unsigned int __weak arch_get_system_nr_ranges(void) { return 0; }
+int __weak arch_crash_populate_cmem(struct crash_mem *cmem) { return -1; }
+int __weak arch_crash_exclude_ranges(struct crash_mem *cmem) { return 0; }
+
+static int crash_exclude_core_ranges(struct crash_mem *cmem)
+{
+	int ret, i;
+
+	/* Exclude crashkernel region */
+	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
+	if (ret)
+		return ret;
+
+	if (crashk_low_res.end) {
+		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < crashk_cma_cnt; ++i) {
+		ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
+					      crashk_cma_ranges[i].end);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
+			  unsigned long *nr_mem_ranges)
+{
+	unsigned int max_nr_ranges;
+	struct crash_mem *cmem;
+	int ret;
+
+	max_nr_ranges = arch_get_system_nr_ranges();
+	if (!max_nr_ranges)
+		return -ENOMEM;
+
+	cmem = alloc_cmem(max_nr_ranges);
+	if (!cmem)
+		return -ENOMEM;
+
+	ret = arch_crash_populate_cmem(cmem);
+	if (ret)
+		goto out;
+
+	ret = crash_exclude_core_ranges(cmem);
+	if (ret)
+		goto out;
+
+	ret = arch_crash_exclude_ranges(cmem);
+	if (ret)
+		goto out;
+
+	/* Return the computed number of memory ranges, for hotplug usage */
+	if (nr_mem_ranges)
+		*nr_mem_ranges = cmem->nr_ranges;
+
+	ret = crash_prepare_elf64_headers(cmem, need_kernel_map, addr, sz);
+
+out:
+	kvfree(cmem);
+	return ret;
+}
+
 /**
  * crash_exclude_mem_range - exclude a mem range for existing ranges
  * @mem: mem->range contains an array of ranges sorted in ascending order
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:58 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:58 +0800
Subject: [PATCH v15 16/23] arm64: kexec_file: Use crash_prepare_headers() helper to simplify code
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-17-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash
kernel memory in the crash core, which reduce code duplication.

Only the following two architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Use for_each_mem_range() to traverse
  and pre-count the max number of memory ranges.

- arch_crash_populate_cmem(). Use for_each_mem_range to traverse
  and collect the memory ranges and fills them into cmem.

Acked-by: Catalin Marinas <catalin.marinas at arm.com>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/kexec.h         |  1 -
 arch/arm64/kernel/kexec_image.c        |  2 +-
 arch/arm64/kernel/machine_kexec_file.c | 46 ++++++++------------------
 3 files changed, 15 insertions(+), 34 deletions(-)

diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 7ffa2ff5fcfd..892e5bebda95 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -128,7 +128,6 @@ extern int load_other_segments(struct kimage *image,
 		unsigned long kernel_load_addr, unsigned long kernel_size,
 		char *initrd, unsigned long initrd_len,
 		char *cmdline);
-extern int prepare_elf_headers(void **addr, unsigned long *sz);
 #endif
 
 #endif /* __ASSEMBLER__ */
diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
index 424b9527db09..93c36a3aa618 100644
--- a/arch/arm64/kernel/kexec_image.c
+++ b/arch/arm64/kernel/kexec_image.c
@@ -95,7 +95,7 @@ static void *image_load(struct kimage *image,
 		unsigned long headers_sz;
 		void *headers;
 
-		ret = prepare_elf_headers(&headers, &headers_sz);
+		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
 		if (ret) {
 			pr_err("Preparing elf core header failed\n");
 			return ERR_PTR(ret);
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 8a96fb68b88d..14e65351133e 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -40,52 +40,34 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 }
 
 #ifdef CONFIG_CRASH_DUMP
-int prepare_elf_headers(void **addr, unsigned long *sz)
+unsigned int arch_get_system_nr_ranges(void)
 {
-	struct crash_mem *cmem;
-	unsigned int nr_ranges;
-	int ret;
-	u64 i;
+	/* for exclusion of crashkernel region */
+	unsigned int nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
 	phys_addr_t start, end;
+	u64 i;
 
-	/* for exclusion of crashkernel region */
-	nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
 	for_each_mem_range(i, &start, &end)
 		nr_ranges++;
 
-	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
-	if (!cmem)
-		return -ENOMEM;
+	return nr_ranges;
+}
+
+int arch_crash_populate_cmem(struct crash_mem *cmem)
+{
+	phys_addr_t start, end;
+	u64 i;
 
-	cmem->max_nr_ranges = nr_ranges;
-	cmem->nr_ranges = 0;
 	for_each_mem_range(i, &start, &end) {
-		if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges)) {
-			ret = -EAGAIN;
-			goto out;
-		}
+		if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges))
+			return -EAGAIN;
 
 		cmem->ranges[cmem->nr_ranges].start = start;
 		cmem->ranges[cmem->nr_ranges].end = end - 1;
 		cmem->nr_ranges++;
 	}
 
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret)
-		goto out;
-
-	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
-		if (ret)
-			goto out;
-	}
-
-	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
-
-out:
-	kfree(cmem);
-	return ret;
+	return 0;
 }
 #endif
 
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:47:59 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:47:59 +0800
Subject: [PATCH v15 17/23] x86: kexec_file: Use crash_prepare_headers() helper to simplify code
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-18-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
memory in the crash core, which reduce code duplication.

Only the following three architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Call get_nr_ram_ranges_callback()
  to pre-count the max number of memory ranges.

- arch_crash_populate_cmem(). Use prepare_elf64_ram_headers_callback()
  to collect the memory ranges and fills them into cmem.

- arch_crash_exclude_ranges(). Exclude the low 1M for x86.

By the way, remove the unused "nr_mem_ranges" in
arch_crash_handle_hotplug_event().

Cc: Thomas Gleixner <tglx at kernel.org>
Cc: Ingo Molnar <mingo at redhat.com>
Cc: Borislav Petkov <bp at alien8.de>
Cc: Dave Hansen <dave.hansen at linux.intel.com>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Vivek Goyal <vgoyal at redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/x86/kernel/crash.c | 89 +++++------------------------------------
 1 file changed, 11 insertions(+), 78 deletions(-)

diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index a1089907728d..7145b00da4ee 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -153,16 +153,8 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
 	return 0;
 }
 
-/* Gather all the required information to prepare elf headers for ram regions */
-static struct crash_mem *fill_up_crash_elf_data(void)
+unsigned int arch_get_system_nr_ranges(void)
 {
-	unsigned int nr_ranges = 0;
-	struct crash_mem *cmem;
-
-	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
-	if (!nr_ranges)
-		return NULL;
-
 	/*
 	 * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges
 	 * may cause range splits. So add extra slots here.
@@ -177,49 +169,16 @@ static struct crash_mem *fill_up_crash_elf_data(void)
 	 * But in order to lest the low 1M could be changed in the future,
 	 * (e.g. [start, 1M]), add a extra slot.
 	 */
-	nr_ranges += 3 + crashk_cma_cnt + CRASH_HOTPLUG_SAFETY_PADDING;
-	cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
-	if (!cmem)
-		return NULL;
-
-	cmem->max_nr_ranges = nr_ranges;
+	unsigned int nr_ranges = 3 + crashk_cma_cnt + CRASH_HOTPLUG_SAFETY_PADDING;
 
-	return cmem;
+	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
+	return nr_ranges;
 }
 
-/*
- * Look for any unwanted ranges between mstart, mend and remove them. This
- * might lead to split and split ranges are put in cmem->ranges[] array
- */
-static int elf_header_exclude_ranges(struct crash_mem *cmem)
+int arch_crash_exclude_ranges(struct crash_mem *cmem)
 {
-	int ret = 0;
-	int i;
-
 	/* Exclude the low 1M because it is always reserved */
-	ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
-	if (ret)
-		return ret;
-
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret)
-		return ret;
-
-	if (crashk_low_res.end)
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start,
-					      crashk_low_res.end);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < crashk_cma_cnt; ++i) {
-		ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
-					      crashk_cma_ranges[i].end);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
+	return crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
 }
 
 static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
@@ -236,35 +195,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 	return 0;
 }
 
-/* Prepare elf headers. Return addr and size */
-static int prepare_elf_headers(void **addr, unsigned long *sz,
-			       unsigned long *nr_mem_ranges)
+int arch_crash_populate_cmem(struct crash_mem *cmem)
 {
-	struct crash_mem *cmem;
-	int ret;
-
-	cmem = fill_up_crash_elf_data();
-	if (!cmem)
-		return -ENOMEM;
-
-	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
-	if (ret)
-		goto out;
-
-	/* Exclude unwanted mem ranges */
-	ret = elf_header_exclude_ranges(cmem);
-	if (ret)
-		goto out;
-
-	/* Return the computed number of memory ranges, for hotplug usage */
-	*nr_mem_ranges = cmem->nr_ranges;
-
-	/* By default prepare 64bit headers */
-	ret = crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), addr, sz);
-
-out:
-	vfree(cmem);
-	return ret;
+	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
 }
 #endif
 
@@ -422,7 +355,8 @@ int crash_load_segments(struct kimage *image)
 				  .buf_max = ULONG_MAX, .top_down = false };
 
 	/* Prepare elf headers and add a segment */
-	ret = prepare_elf_headers(&kbuf.buffer, &kbuf.bufsz, &pnum);
+	ret = crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &kbuf.buffer,
+				    &kbuf.bufsz, &pnum);
 	if (ret)
 		return ret;
 
@@ -515,7 +449,6 @@ unsigned int arch_crash_get_elfcorehdr_size(void)
 void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
 {
 	void *elfbuf = NULL, *old_elfcorehdr;
-	unsigned long nr_mem_ranges;
 	unsigned long mem, memsz;
 	unsigned long elfsz = 0;
 
@@ -533,7 +466,7 @@ void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
 	 * Create the new elfcorehdr reflecting the changes to CPU and/or
 	 * memory resources.
 	 */
-	if (prepare_elf_headers(&elfbuf, &elfsz, &nr_mem_ranges)) {
+	if (crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &elfbuf, &elfsz, NULL)) {
 		pr_err("unable to create new elfcorehdr");
 		goto out;
 	}
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:48:00 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:48:00 +0800
Subject: [PATCH v15 18/23] riscv: kexec_file: Use crash_prepare_headers() helper to simplify code
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-19-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
memory in the crash core, which reduce code duplication.

Only the following two architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Call get_nr_ram_ranges_callback()
  to pre-counts the max number of memory ranges.

- arch_crash_populate_cmem(). Use prepare_elf64_ram_headers_callback()
  to collects the memory ranges and fills them into cmem.

Cc: Paul Walmsley <pjw at kernel.org>
Cc: Palmer Dabbelt <palmer at dabbelt.com>
Cc: Albert Ou <aou at eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex at ghiti.fr>
Cc: Guo Ren <guoren at kernel.org>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/riscv/kernel/machine_kexec_file.c | 49 +++++++-------------------
 1 file changed, 13 insertions(+), 36 deletions(-)

diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index f3576dc0513f..6e2a6747d187 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -44,6 +44,16 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
 	return 0;
 }
 
+unsigned int arch_get_system_nr_ranges(void)
+{
+	/* For exclusion of crashkernel region */
+	unsigned int nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
+
+	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
+
+	return nr_ranges;
+}
+
 static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 {
 	struct crash_mem *cmem = arg;
@@ -58,42 +68,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 	return 0;
 }
 
-static int prepare_elf_headers(void **addr, unsigned long *sz)
+int arch_crash_populate_cmem(struct crash_mem *cmem)
 {
-	struct crash_mem *cmem;
-	unsigned int nr_ranges;
-	int ret;
-
-	/* For exclusion of crashkernel region */
-	nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
-	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
-
-	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
-	if (!cmem)
-		return -ENOMEM;
-
-	cmem->max_nr_ranges = nr_ranges;
-	cmem->nr_ranges = 0;
-	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
-	if (ret)
-		goto out;
-
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret)
-		goto out;
-
-	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
-		if (ret)
-			goto out;
-	}
-
-	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
-
-out:
-	kfree(cmem);
-	return ret;
+	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
 }
 
 static char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
@@ -285,7 +262,7 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start,
 	if (image->type == KEXEC_TYPE_CRASH) {
 		void *headers;
 		unsigned long headers_sz;
-		ret = prepare_elf_headers(&headers, &headers_sz);
+		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
 		if (ret) {
 			pr_err("Preparing elf core header failed\n");
 			goto out;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:48:01 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:48:01 +0800
Subject: [PATCH v15 19/23] LoongArch: kexec_file: Use crash_prepare_headers() helper to simplify code
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-20-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
memory in the crash core, which reduce code duplication.

Only the following two architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Use for_each_mem_range to traverse
  and pre-count the max number of memory ranges.

- arch_crash_populate_cmem(). Use for_each_mem_range to traverse
  and collect the memory ranges and fills them into cmem.

Cc: Huacai Chen <chenhuacai at kernel.org>
Cc: WANG Xuerui <kernel at xen0n.name>
Cc: Youling Tang <tangyouling at kylinos.cn>
Cc: Baoquan He <bhe at redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/loongarch/kernel/machine_kexec_file.c | 48 +++++++---------------
 1 file changed, 15 insertions(+), 33 deletions(-)

diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
index 3c369124586e..f3101bea9e45 100644
--- a/arch/loongarch/kernel/machine_kexec_file.c
+++ b/arch/loongarch/kernel/machine_kexec_file.c
@@ -56,52 +56,34 @@ static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl
 }
 
 #ifdef CONFIG_CRASH_DUMP
-
-static int prepare_elf_headers(void **addr, unsigned long *sz)
+unsigned int arch_get_system_nr_ranges(void)
 {
-	int ret, nr_ranges;
-	uint64_t i;
+	/* for exclusion of crashkernel region */
+	int nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
 	phys_addr_t start, end;
-	struct crash_mem *cmem;
+	uint64_t i;
 
-	/* for exclusion of crashkernel region */
-	nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
 	for_each_mem_range(i, &start, &end)
 		nr_ranges++;
 
-	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
-	if (!cmem)
-		return -ENOMEM;
+	return nr_ranges;
+}
+
+int arch_crash_populate_cmem(struct crash_mem *cmem)
+{
+	phys_addr_t start, end;
+	uint64_t i;
 
-	cmem->max_nr_ranges = nr_ranges;
-	cmem->nr_ranges = 0;
 	for_each_mem_range(i, &start, &end) {
-		if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges)) {
-			ret = -EAGAIN;
-			goto out;
-		}
+		if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges))
+			return -EAGAIN;
 
 		cmem->ranges[cmem->nr_ranges].start = start;
 		cmem->ranges[cmem->nr_ranges].end = end - 1;
 		cmem->nr_ranges++;
 	}
 
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret < 0)
-		goto out;
-
-	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
-		if (ret < 0)
-			goto out;
-	}
-
-	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
-
-out:
-	kfree(cmem);
-	return ret;
+	return 0;
 }
 
 /*
@@ -169,7 +151,7 @@ int load_other_segments(struct kimage *image,
 		void *headers;
 		unsigned long headers_sz;
 
-		ret = prepare_elf_headers(&headers, &headers_sz);
+		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
 		if (ret < 0) {
 			pr_err("Preparing elf core header failed\n");
 			goto out_err;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:48:02 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:48:02 +0800
Subject: [PATCH v15 20/23] powerpc/kexec_file: Use crash_exclude_core_ranges() helper
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-21-ruanjinjie@huawei.com>

The crash memory exclude of crashk_res and crashk_cma memory on powerpc
are almost identical to the generic crash_exclude_core_ranges().

By introducing the architecture-specific arch_crash_exclude_mem_range()
function with a default implementation of crash_exclude_mem_range(),
and using crash_exclude_mem_range_guarded as powerpc's separate
implementation, the generic crash_exclude_core_ranges() helper function
can be reused.

Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Hari Bathini <hbathini at linux.ibm.com>
Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
Cc: Mahesh Salgaonkar <mahesh at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Cc: Shivang Upadhyay <shivangu at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/powerpc/include/asm/kexec_ranges.h |  3 ---
 arch/powerpc/kexec/crash.c              |  2 +-
 arch/powerpc/kexec/ranges.c             | 16 ++++------------
 include/linux/crash_core.h              |  4 ++++
 kernel/crash_core.c                     | 19 +++++++++++++------
 5 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/arch/powerpc/include/asm/kexec_ranges.h b/arch/powerpc/include/asm/kexec_ranges.h
index ad95e3792d10..8489e844b447 100644
--- a/arch/powerpc/include/asm/kexec_ranges.h
+++ b/arch/powerpc/include/asm/kexec_ranges.h
@@ -7,9 +7,6 @@
 void sort_memory_ranges(struct crash_mem *mrngs, bool merge);
 struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges);
 int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
-int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
-				    unsigned long long mstart,
-				    unsigned long long mend);
 int get_exclude_memory_ranges(struct crash_mem **mem_ranges);
 int get_reserved_memory_ranges(struct crash_mem **mem_ranges);
 int get_crash_memory_ranges(struct crash_mem **mem_ranges);
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index d634db67becc..775895f31037 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -513,7 +513,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
 		base_addr = PFN_PHYS(mn->start_pfn);
 		size = mn->nr_pages * PAGE_SIZE;
 		end = base_addr + size - 1;
-		ret = crash_exclude_mem_range_guarded(&cmem, base_addr, end);
+		ret = arch_crash_exclude_mem_range(&cmem, base_addr, end);
 		if (ret) {
 			pr_err("Failed to remove hot-unplugged memory from crash memory ranges\n");
 			goto out;
diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c
index b2fb78562cdc..539061d14a77 100644
--- a/arch/powerpc/kexec/ranges.c
+++ b/arch/powerpc/kexec/ranges.c
@@ -551,9 +551,9 @@ int get_usable_memory_ranges(struct crash_mem **mem_ranges)
 #endif /* CONFIG_KEXEC_FILE */
 
 #ifdef CONFIG_CRASH_DUMP
-int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
-					   unsigned long long mstart,
-					   unsigned long long mend)
+int arch_crash_exclude_mem_range(struct crash_mem **mem_ranges,
+				 unsigned long long mstart,
+				 unsigned long long mend)
 {
 	struct crash_mem *tmem = *mem_ranges;
 
@@ -602,18 +602,10 @@ int get_crash_memory_ranges(struct crash_mem **mem_ranges)
 			sort_memory_ranges(*mem_ranges, true);
 	}
 
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_res.start, crashk_res.end);
+	ret = crash_exclude_core_ranges(mem_ranges);
 	if (ret)
 		goto out;
 
-	for (i = 0; i < crashk_cma_cnt; ++i) {
-		ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_cma_ranges[i].start,
-					      crashk_cma_ranges[i].end);
-		if (ret)
-			goto out;
-	}
-
 	/*
 	 * FIXME: For now, stay in parity with kexec-tools but if RTAS/OPAL
 	 *        regions are exported to save their context at the time of
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index 43baf9c87355..1ae2c0eb2eb3 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -67,6 +67,7 @@ extern int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_ma
 				       void **addr, unsigned long *sz);
 extern int crash_prepare_headers(int need_kernel_map, void **addr,
 				 unsigned long *sz, unsigned long *nr_mem_ranges);
+extern int crash_exclude_core_ranges(struct crash_mem **cmem);
 
 struct kimage;
 struct kexec_segment;
@@ -87,6 +88,9 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image);
 extern unsigned int arch_get_system_nr_ranges(void);
 extern int arch_crash_populate_cmem(struct crash_mem *cmem);
 extern int arch_crash_exclude_ranges(struct crash_mem *cmem);
+extern int arch_crash_exclude_mem_range(struct crash_mem **mem,
+					unsigned long long mstart,
+					unsigned long long mend);
 
 #else /* !CONFIG_CRASH_DUMP*/
 struct pt_regs;
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 481babc29131..2b36aa9fade0 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -285,24 +285,31 @@ unsigned int __weak arch_get_system_nr_ranges(void) { return 0; }
 int __weak arch_crash_populate_cmem(struct crash_mem *cmem) { return -1; }
 int __weak arch_crash_exclude_ranges(struct crash_mem *cmem) { return 0; }
 
-static int crash_exclude_core_ranges(struct crash_mem *cmem)
+int __weak arch_crash_exclude_mem_range(struct crash_mem **mem,
+					unsigned long long mstart,
+					unsigned long long mend)
+{
+	return crash_exclude_mem_range(*mem, mstart, mend);
+}
+
+int crash_exclude_core_ranges(struct crash_mem **cmem)
 {
 	int ret, i;
 
 	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
+	ret = arch_crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
 	if (ret)
 		return ret;
 
 	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+		ret = arch_crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
 		if (ret)
 			return ret;
 	}
 
 	for (i = 0; i < crashk_cma_cnt; ++i) {
-		ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
-					      crashk_cma_ranges[i].end);
+		ret = arch_crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
+						   crashk_cma_ranges[i].end);
 		if (ret)
 			return ret;
 	}
@@ -329,7 +336,7 @@ int crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
 	if (ret)
 		goto out;
 
-	ret = crash_exclude_core_ranges(cmem);
+	ret = crash_exclude_core_ranges(&cmem);
 	if (ret)
 		goto out;
 
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:48:03 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:48:03 +0800
Subject: [PATCH v15 21/23] arm64: kexec_file: Add support for crashkernel CMA reservation
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-22-ruanjinjie@huawei.com>

Commit 35c18f2933c5 ("Add a new optional ",cma" suffix to the
crashkernel= command line option") and commit ab475510e042 ("kdump:
implement reserve_crashkernel_cma") added CMA support for kdump
crashkernel reservation.

Crash kernel memory reservation wastes production resources if too
large, risks kdump failure if too small, and faces allocation difficulties
on fragmented systems due to contiguous block constraints. The new
CMA-based crashkernel reservation scheme splits the "large fixed
reservation" into a "small fixed region + large CMA dynamic region": the
CMA memory is available to userspace during normal operation to avoid
waste, and is reclaimed for kdump upon crash?saving memory while
improving reliability.

So extend crashkernel CMA reservation support to arm64. The following
changes are made to enable CMA reservation:

- Parse and obtain the CMA reservation size along with other crashkernel
  parameters.
- Call reserve_crashkernel_cma() to allocate the CMA region for kdump.
- Include the CMA-reserved ranges for kdump kernel to use.
- Exclude the CMA-reserved ranges from the crash kernel memory to
  prevent them from being exported through /proc/vmcore, which is already
  done in the crash core.

Update kernel-parameters.txt to document CMA support for crashkernel on
arm64 architecture.

Tested-by: Breno Leitao <leitao at debian.org>
Acked-by: Catalin Marinas <catalin.marinas at arm.com>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Acked-by: Ard Biesheuvel <ardb at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
v7:
- Correct the inclusion of CMA-reserved ranges for kdump
  kernel in of/kexec.
v3:
- Add Acked-by.
v2:
- Free cmem in prepare_elf_headers()
- Add the mtivation.
---
 Documentation/admin-guide/kernel-parameters.txt | 2 +-
 arch/arm64/kernel/machine_kexec_file.c          | 2 +-
 arch/arm64/mm/init.c                            | 5 +++--
 drivers/of/fdt.c                                | 9 +++++----
 drivers/of/kexec.c                              | 9 +++++++++
 include/linux/crash_reserve.h                   | 4 +++-
 6 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..52742fab49a9 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1119,7 +1119,7 @@ Kernel parameters
 			It will be ignored when crashkernel=X,high is not used
 			or memory reserved is below 4G.
 	crashkernel=size[KMG],cma
-			[KNL, X86, ppc] Reserve additional crash kernel memory from
+			[KNL, X86, ARM64, PPC] Reserve additional crash kernel memory from
 			CMA. This reservation is usable by the first system's
 			userspace memory and kernel movable allocations (memory
 			balloon, zswap). Pages allocated from this memory range
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 14e65351133e..d0f73eb3f856 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -43,7 +43,7 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 unsigned int arch_get_system_nr_ranges(void)
 {
 	/* for exclusion of crashkernel region */
-	unsigned int nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
+	unsigned int nr_ranges = 2 + crashk_cma_cnt + CRASH_HOTPLUG_SAFETY_PADDING;
 	phys_addr_t start, end;
 	u64 i;
 
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 97987f850a33..227f58522dad 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -96,8 +96,8 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;
 
 static void __init arch_reserve_crashkernel(void)
 {
+	unsigned long long crash_base, crash_size, cma_size = 0;
 	unsigned long long low_size = 0;
-	unsigned long long crash_base, crash_size;
 	bool high = false;
 	int ret;
 
@@ -106,11 +106,12 @@ static void __init arch_reserve_crashkernel(void)
 
 	ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
 				&crash_size, &crash_base,
-				&low_size, NULL, &high);
+				&low_size, &cma_size, &high);
 	if (ret)
 		return;
 
 	reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
+	reserve_crashkernel_cma(cma_size);
 }
 
 static phys_addr_t __init max_zone_phys(phys_addr_t zone_limit)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 82f7327c59ea..0470acbd1fcf 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -880,11 +880,12 @@ static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND;
 /*
  * The main usage of linux,usable-memory-range is for crash dump kernel.
  * Originally, the number of usable-memory regions is one. Now there may
- * be two regions, low region and high region.
- * To make compatibility with existing user-space and older kdump, the low
- * region is always the last range of linux,usable-memory-range if exist.
+ * be 2 + CRASHK_CMA_RANGES_MAX regions, low region, high region and cma
+ * regions. To make compatibility with existing user-space and older kdump,
+ * the high and low region are always the first two ranges of
+ * linux,usable-memory-range if exist.
  */
-#define MAX_USABLE_RANGES		2
+#define MAX_USABLE_RANGES		(2 + CRASHK_CMA_RANGES_MAX)
 
 /**
  * early_init_dt_check_for_usable_mem_range - Decode usable memory range
diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
index b6837e299e7f..029903b986cb 100644
--- a/drivers/of/kexec.c
+++ b/drivers/of/kexec.c
@@ -458,6 +458,15 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
 			if (ret)
 				goto out;
 		}
+
+		for (int i = 0; i < crashk_cma_cnt; i++) {
+			ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
+					"linux,usable-memory-range",
+					crashk_cma_ranges[i].start,
+					crashk_cma_ranges[i].end - crashk_cma_ranges[i].start + 1);
+			if (ret)
+				goto out;
+		}
 #endif
 	}
 
diff --git a/include/linux/crash_reserve.h b/include/linux/crash_reserve.h
index f0dc03d94ca2..30864d90d7f5 100644
--- a/include/linux/crash_reserve.h
+++ b/include/linux/crash_reserve.h
@@ -14,9 +14,11 @@
 extern struct resource crashk_res;
 extern struct resource crashk_low_res;
 extern struct range crashk_cma_ranges[];
+
+#define CRASHK_CMA_RANGES_MAX 4
 #if defined(CONFIG_CMA) && defined(CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION)
 #define CRASHKERNEL_CMA
-#define CRASHKERNEL_CMA_RANGES_MAX 4
+#define CRASHKERNEL_CMA_RANGES_MAX (CRASHK_CMA_RANGES_MAX)
 extern int crashk_cma_cnt;
 #else
 #define crashk_cma_cnt 0
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:48:04 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:48:04 +0800
Subject: [PATCH v15 22/23] riscv: kexec_file: Add support for crashkernel CMA reservation
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-23-ruanjinjie@huawei.com>

Commit 35c18f2933c5 ("Add a new optional ",cma" suffix to the
crashkernel= command line option") and commit ab475510e042 ("kdump:
implement reserve_crashkernel_cma") added CMA support for kdump
crashkernel reservation. This allows the kernel to dynamically allocate
contiguous memory for crash dumping when needed, rather than permanently
reserving a fixed region at boot time.

So extend crashkernel CMA reservation support to riscv. The following
changes are made to enable CMA reservation:

- Parse and obtain the CMA reservation size along with other crashkernel
  parameters.
- Call reserve_crashkernel_cma() to allocate the CMA region for kdump.
- Include the CMA-reserved ranges for kdump kernel to use, which was
  already done in of_kexec_alloc_and_setup_fdt().
- Exclude the CMA-reserved ranges from the crash kernel memory to
  prevent them from being exported through /proc/vmcore, which was
  already done in the crash core.

Update kernel-parameters.txt to document CMA support for crashkernel on
riscv architecture.

Cc: Paul Walmsley <pjw at kernel.org>
Cc: Palmer Dabbelt <palmer at dabbelt.com>
Cc: Albert Ou <aou at eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex at ghiti.fr>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Acked-by: Paul Walmsley <pjw at kernel.org> # arch/riscv
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 Documentation/admin-guide/kernel-parameters.txt | 16 ++++++++--------
 arch/riscv/kernel/machine_kexec_file.c          |  2 +-
 arch/riscv/mm/init.c                            |  5 +++--
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 52742fab49a9..3ff3ddd516cf 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1119,14 +1119,14 @@ Kernel parameters
 			It will be ignored when crashkernel=X,high is not used
 			or memory reserved is below 4G.
 	crashkernel=size[KMG],cma
-			[KNL, X86, ARM64, PPC] Reserve additional crash kernel memory from
-			CMA. This reservation is usable by the first system's
-			userspace memory and kernel movable allocations (memory
-			balloon, zswap). Pages allocated from this memory range
-			will not be included in the vmcore so this should not
-			be used if dumping of userspace memory is intended and
-			it has to be expected that some movable kernel pages
-			may be missing from the dump.
+			[KNL, X86, ARM64, RISCV, PPC] Reserve additional crash
+			kernel memory from CMA. This reservation is usable by
+			the first system's userspace memory and kernel movable
+			allocations (memory balloon, zswap). Pages allocated
+			from this memory range will not be included in the vmcore
+			so this should not be used if dumping of userspace memory
+			is intended and it has to be expected that some movable
+			kernel pages may be missing from the dump.
 
 			A standard crashkernel reservation, as described above,
 			is still needed to hold the crash kernel and initrd.
diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 6e2a6747d187..42d847154e19 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -47,7 +47,7 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
 unsigned int arch_get_system_nr_ranges(void)
 {
 	/* For exclusion of crashkernel region */
-	unsigned int nr_ranges = 2 + CRASH_HOTPLUG_SAFETY_PADDING;
+	unsigned int nr_ranges = 2 + crashk_cma_cnt + CRASH_HOTPLUG_SAFETY_PADDING;
 
 	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
 
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index decd7df40fa4..c848454b8349 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1295,7 +1295,7 @@ static inline void setup_vm_final(void)
  */
 static void __init arch_reserve_crashkernel(void)
 {
-	unsigned long long low_size = 0;
+	unsigned long long low_size = 0, cma_size = 0;
 	unsigned long long crash_base, crash_size;
 	bool high = false;
 	int ret;
@@ -1305,11 +1305,12 @@ static void __init arch_reserve_crashkernel(void)
 
 	ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
 				&crash_size, &crash_base,
-				&low_size, NULL, &high);
+				&low_size, &cma_size, &high);
 	if (ret)
 		return;
 
 	reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
+	reserve_crashkernel_cma(cma_size);
 }
 
 void __init paging_init(void)
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  1 02:48:05 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 1 Jun 2026 17:48:05 +0800
Subject: [PATCH v15 23/23] arm64: crash: Add crash hotplug support
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <20260601094805.2928614-24-ruanjinjie@huawei.com>

Due to CPU/Memory hotplug or online/offline events, the elfcorehdr
(which describes the CPUs and memory of the crashed kernel) of kdump
image becomes outdated. Consequently, attempting dump collection with
an outdated elfcorehdr can lead to inaccurate dump collection.

The current solution to address the above issue involves monitoring
the CPU/Memory add/remove events in userspace using udev rules and
whenever there are changes in CPU and memory resources, the entire
kdump image is loaded again. The kdump image includes kernel, initrd,
elfcorehdr, FDT, purgatory. Given that only elfcorehdr gets outdated
due to CPU/Memory add/remove events, reloading the entire kdump image
is inefficient. More importantly, kdump remains inactive for a
substantial amount of time until the kdump reload completes.

To address the aforementioned issue, commit 247262756121 ("crash: add
generic infrastructure for crash hotplug support") added a generic
infrastructure that allows architectures to selectively update the
kdump image component during CPU or memory add/remove events within
the kernel itself.

In the event of a CPU or memory add/remove events, the generic crash
hotplug event handler, crash_handle_hotplug_event(), is triggered. It
then acquires the necessary locks to update the kdump image and invokes
the architecture-specific crash hotplug handler,
arch_crash_handle_hotplug_event(), to update the required kdump image
components.

[1] has supported virtual CPU hotplug in virtual machines for ARM64,
allowing vCPUs to be added or removed at runtime to meet Kubernetes
demands.

On ARM64, only memory add/remove events are handled. Here's why:

1. Physical CPU hotplug: Not supported on ARM64 hardware.

2. ACPI vCPU hotplug (KVM virtual machine):
   - vCPU hotplug is implemented as a static firmware policy where all
     possible vCPUs are pre-described in the MADT table at boot.
   - The vCPU status will be automatically updated after vCPU hotplug.
   - No FDT or elfcorehdr update needed.

3. Device tree booted Virtual Machine vCPU hotplug:
  - The elfcorehdr is built using for_each_possible_cpu(), so it
    already includes all possible CPUs and doesn't need updates.

For memory add/remove events, the elfcorehdr is updated to reflect
the current memory layout.

This patch adds the ARCH_SUPPORTS_CRASH_HOTPLUG config option and
implements:
- arch_crash_hotplug_support(): Check if hotplug update is supported
- arch_crash_get_elfcorehdr_size(): Return elfcorehdr buffer size
- arch_crash_handle_hotplug_event(): Handle memory hotplug events

This follows the same approach as x86 commit
ea53ad9cf73b ("x86/crash: add x86 crash hotplug support") and powerpc
commit b741092d5976 ("powerpc/crash: add crash CPU hotplug support")
and commit 849599b702ef ("powerpc/crash: add crash memory hotplug
support").

The test is based on the following QEMU version:
	https://github.com/salil-mehta/qemu.git virt-cpuhp-armv8/rfc-v2

Replace your '-smp' argument with something like:
 | -smp cpus=1,maxcpus=3,cores=3,threads=1,sockets=1

then feed the following to the Qemu montior to hotplug vCPU;
 | (qemu) device_add driver=host-arm-cpu,core-id=1,id=cpu1
 | (qemu) device_del cpu1

feed the following to the Qemu montior to hotplug memory;
 | (qemu) object_add memory-backend-ram,id=mem1,size=256M
 | (qemu) device_add pc-dimm,id=dimm1,memdev=mem1
 | (qemu) device_del dimm1

The qemu startup configuration is as follows:
qemu-system-aarch64 \
		-M virt,gic-version=3,acpi=on,highmem=on \
		-enable-kvm \
		-cpu host \
		-kernel Image \
		-smp cpus=1,maxcpus=3,cores=3,threads=1,sockets=1 \
		-bios /usr/share/edk2/aarch64/QEMU_EFI.fd \
		-m 2G,slots=64,maxmem=16G \
		-nographic \
		-no-reboot \
		-device virtio-rng-pci \
		-append "root=/dev/vda rw console=ttyAMA0 kgdboc=ttyAMA0,115200 \
			earlycon acpi=on crashkernel=512M" \
		-drive if=none,file=images/rootfs.ext4,format=raw,id=hd0 \
		-device virtio-blk-device,drive=hd0 \

There are two system calls, `kexec_file_load` and `kexec_load`, used to
load the kdump image. Only kexec_file_load syscall way is tested now.

Cc: Catalin Marinas <catalin.marinas at arm.com>
Cc: Will Deacon <will at kernel.org>
Cc: Baoquan He <bhe at redhat.com>
Cc: "Mike Rapoport (Microsoft)" <rppt at kernel.org>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Breno Leitao <leitao at debian.org>
Cc: Kees Cook <kees at kernel.org>
[1]: https://lore.kernel.org/all/20240529133446.28446-1-Jonathan.Cameron at huawei.com/
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/Kconfig                     |   3 +
 arch/arm64/include/asm/kexec.h         |  13 +++
 arch/arm64/kernel/Makefile             |   2 +-
 arch/arm64/kernel/crash.c              | 152 +++++++++++++++++++++++++
 arch/arm64/kernel/kexec_image.c        |  21 +++-
 arch/arm64/kernel/machine_kexec_file.c |  40 ++-----
 6 files changed, 195 insertions(+), 36 deletions(-)
 create mode 100644 arch/arm64/kernel/crash.c

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fe60738e5943..9091c67e1cc2 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -1609,6 +1609,9 @@ config ARCH_DEFAULT_CRASH_DUMP
 config ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION
 	def_bool CRASH_RESERVE
 
+config ARCH_SUPPORTS_CRASH_HOTPLUG
+	def_bool y
+
 config TRANS_TABLE
 	def_bool y
 	depends on HIBERNATION || KEXEC_CORE
diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 892e5bebda95..4f3d4fc2807e 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -130,6 +130,19 @@ extern int load_other_segments(struct kimage *image,
 		char *cmdline);
 #endif
 
+#ifdef CONFIG_CRASH_HOTPLUG
+#define pnum_hdr_sz(pnum) ((pnum) * sizeof(Elf64_Phdr) + sizeof(Elf64_Ehdr))
+
+void arch_crash_handle_hotplug_event(struct kimage *image, void *arg);
+#define arch_crash_handle_hotplug_event arch_crash_handle_hotplug_event
+
+int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags);
+#define arch_crash_hotplug_support arch_crash_hotplug_support
+
+unsigned int arch_crash_get_elfcorehdr_size(void);
+#define crash_get_elfcorehdr_size arch_crash_get_elfcorehdr_size
+#endif
+
 #endif /* __ASSEMBLER__ */
 
 #endif
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 74b76bb70452..0625422fc528 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -64,7 +64,7 @@ obj-$(CONFIG_KEXEC_CORE)		+= machine_kexec.o relocate_kernel.o	\
 obj-$(CONFIG_KEXEC_FILE)		+= machine_kexec_file.o kexec_image.o
 obj-$(CONFIG_ARM64_RELOC_TEST)		+= arm64-reloc-test.o
 arm64-reloc-test-y := reloc_test_core.o reloc_test_syms.o
-obj-$(CONFIG_CRASH_DUMP)		+= crash_dump.o
+obj-$(CONFIG_CRASH_DUMP)		+= crash_dump.o crash.o
 obj-$(CONFIG_VMCORE_INFO)		+= vmcore_info.o
 obj-$(CONFIG_ARM_SDE_INTERFACE)		+= sdei.o
 obj-$(CONFIG_ARM64_PTR_AUTH)		+= pointer_auth.o
diff --git a/arch/arm64/kernel/crash.c b/arch/arm64/kernel/crash.c
new file mode 100644
index 000000000000..5882b9b5a90e
--- /dev/null
+++ b/arch/arm64/kernel/crash.c
@@ -0,0 +1,152 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Architecture specific functions for kexec based crash dumps.
+ */
+
+#define pr_fmt(fmt)	"crash hp: " fmt
+
+#include <linux/kexec.h>
+#include <linux/elf.h>
+#include <linux/memblock.h>
+#include <linux/vmalloc.h>
+#include <linux/cacheflush.h>
+#include <linux/crash_core.h>
+
+#include <asm/kexec.h>
+
+#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_HOTPLUG)
+unsigned int arch_get_system_nr_ranges(void)
+{
+	/* for exclusion of crashkernel region */
+	unsigned int nr_ranges = 2 + crashk_cma_cnt + CRASH_HOTPLUG_SAFETY_PADDING;
+	phys_addr_t start, end;
+	u64 i;
+
+	for_each_mem_range(i, &start, &end)
+		nr_ranges++;
+
+	return nr_ranges;
+}
+
+int arch_crash_populate_cmem(struct crash_mem *cmem)
+{
+	phys_addr_t start, end;
+	u64 i;
+
+	for_each_mem_range(i, &start, &end) {
+		if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges))
+			return -EAGAIN;
+
+		cmem->ranges[cmem->nr_ranges].start = start;
+		cmem->ranges[cmem->nr_ranges].end = end - 1;
+		cmem->nr_ranges++;
+	}
+
+	return 0;
+}
+#endif
+
+#ifdef CONFIG_CRASH_HOTPLUG
+int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags)
+{
+#ifdef CONFIG_KEXEC_FILE
+	if (image->file_mode)
+		return 1;
+#endif
+	/*
+	 * For kexec_load syscall, crash hotplug support requires
+	 * KEXEC_CRASH_HOTPLUG_SUPPORT flag to be passed by userspace.
+	 */
+	return kexec_flags & KEXEC_CRASH_HOTPLUG_SUPPORT;
+}
+
+unsigned int arch_crash_get_elfcorehdr_size(void)
+{
+	unsigned int phdr_cnt;
+
+	/* A program header for possible CPUs, vmcoreinfo and kernel_map */
+	phdr_cnt = 2 + num_possible_cpus();
+	if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG))
+		phdr_cnt += CONFIG_CRASH_MAX_MEMORY_RANGES;
+
+	return pnum_hdr_sz(phdr_cnt);
+}
+
+/**
+ * update_crash_elfcorehdr() - Recreate the elfcorehdr and replace it with old
+ *			       elfcorehdr in the kexec segment array.
+ * @image: the active struct kimage
+ */
+static void update_crash_elfcorehdr(struct kimage *image)
+{
+	void *elfbuf = NULL, *old_elfcorehdr;
+	unsigned long mem, memsz;
+	unsigned long elfsz = 0;
+
+	/*
+	 * Create the new elfcorehdr reflecting the changes to CPU and/or
+	 * memory resources.
+	 */
+	if (crash_prepare_headers(true, &elfbuf, &elfsz, NULL)) {
+		pr_err("unable to create new elfcorehdr");
+		goto out;
+	}
+
+	/*
+	 * Obtain address and size of the elfcorehdr segment, and
+	 * check it against the new elfcorehdr buffer.
+	 */
+	mem = image->segment[image->elfcorehdr_index].mem;
+	memsz = image->segment[image->elfcorehdr_index].memsz;
+	if (elfsz > memsz) {
+		pr_err("update elfcorehdr elfsz %lu > memsz %lu",
+			elfsz, memsz);
+		goto out;
+	}
+
+	/*
+	 * Copy new elfcorehdr over the old elfcorehdr at destination.
+	 */
+	old_elfcorehdr = (void *)__va(mem);
+	if (!old_elfcorehdr) {
+		pr_err("mapping elfcorehdr segment failed\n");
+		goto out;
+	}
+
+	/*
+	 * Temporarily invalidate the crash image while the
+	 * elfcorehdr is updated.
+	 */
+	xchg(&kexec_crash_image, NULL);
+	memcpy((void *)old_elfcorehdr, elfbuf, elfsz);
+	dcache_clean_inval_poc((unsigned long)old_elfcorehdr,
+			       (unsigned long)old_elfcorehdr + elfsz);
+	xchg(&kexec_crash_image, image);
+	pr_debug("updated elfcorehdr\n");
+
+out:
+	vfree(elfbuf);
+}
+
+/**
+ * arch_crash_handle_hotplug_event() - Handle hotplug elfcorehdr changes
+ * @image: a pointer to kexec_crash_image
+ * @arg: struct memory_notify handler for memory hotplug case and
+ *       NULL for CPU hotplug case.
+ *
+ * Update the kdump image based on the type of hotplug event:
+ * - CPU add and remove: No action is needed.
+ * - Memory add/remove: Update the elfcorehdr to reflect the current memory layout.
+ *
+ * Prepare the new elfcorehdr and replace the existing elfcorehdr.
+ */
+void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
+{
+	if ((image->file_mode || image->elfcorehdr_updated) &&
+		((image->hp_action == KEXEC_CRASH_HP_ADD_CPU) ||
+		(image->hp_action == KEXEC_CRASH_HP_REMOVE_CPU)))
+		return;
+
+	update_crash_elfcorehdr(image);
+}
+#endif /* CONFIG_CRASH_HOTPLUG */
diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
index 93c36a3aa618..21f38de7a8b6 100644
--- a/arch/arm64/kernel/kexec_image.c
+++ b/arch/arm64/kernel/kexec_image.c
@@ -8,6 +8,7 @@
 
 #define pr_fmt(fmt)	"kexec_file(Image): " fmt
 
+#include <linux/elf.h>
 #include <linux/err.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -92,16 +93,32 @@ static void *image_load(struct kimage *image,
 #ifdef CONFIG_CRASH_DUMP
 	if (image->type == KEXEC_TYPE_CRASH) {
 		/* load elf core header */
-		unsigned long headers_sz;
+		unsigned long headers_sz, pnum = 0;
 		void *headers;
 
-		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
+		ret = crash_prepare_headers(true, &headers, &headers_sz, &pnum);
 		if (ret) {
 			pr_err("Preparing elf core header failed\n");
 			return ERR_PTR(ret);
 		}
 		image->elf_headers = headers;
 		image->elf_headers_sz = headers_sz;
+
+#ifdef CONFIG_CRASH_HOTPLUG
+		/*
+		 * The elfcorehdr segment size accounts for VMCOREINFO, kernel_map
+		 * maximum CPUs and maximum memory ranges.
+		 */
+		if (IS_ENABLED(CONFIG_MEMORY_HOTPLUG))
+			pnum = 2 + num_possible_cpus() + CONFIG_CRASH_MAX_MEMORY_RANGES;
+		else
+			pnum += 2 + num_possible_cpus();
+
+		if (pnum < (unsigned long)PN_XNUM)
+			image->elf_headers_sz = max(pnum_hdr_sz(pnum), headers_sz);
+		else
+			pr_err("number of Phdrs %lu exceeds max\n", pnum);
+#endif
 	}
 #endif
 
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index d0f73eb3f856..0016001f4d00 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -10,11 +10,11 @@
 
 #define pr_fmt(fmt) "kexec_file: " fmt
 
+#include <linux/elf.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/kexec.h>
 #include <linux/libfdt.h>
-#include <linux/memblock.h>
 #include <linux/of.h>
 #include <linux/of_fdt.h>
 #include <linux/slab.h>
@@ -39,38 +39,6 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 	return kexec_image_post_load_cleanup_default(image);
 }
 
-#ifdef CONFIG_CRASH_DUMP
-unsigned int arch_get_system_nr_ranges(void)
-{
-	/* for exclusion of crashkernel region */
-	unsigned int nr_ranges = 2 + crashk_cma_cnt + CRASH_HOTPLUG_SAFETY_PADDING;
-	phys_addr_t start, end;
-	u64 i;
-
-	for_each_mem_range(i, &start, &end)
-		nr_ranges++;
-
-	return nr_ranges;
-}
-
-int arch_crash_populate_cmem(struct crash_mem *cmem)
-{
-	phys_addr_t start, end;
-	u64 i;
-
-	for_each_mem_range(i, &start, &end) {
-		if (unlikely(cmem->nr_ranges >= cmem->max_nr_ranges))
-			return -EAGAIN;
-
-		cmem->ranges[cmem->nr_ranges].start = start;
-		cmem->ranges[cmem->nr_ranges].end = end - 1;
-		cmem->nr_ranges++;
-	}
-
-	return 0;
-}
-#endif
-
 /*
  * Tries to add the initrd and DTB to the image. If it is not possible to find
  * valid locations, this function will undo changes to the image and return non
@@ -98,6 +66,12 @@ int load_other_segments(struct kimage *image,
 		kbuf.bufsz = image->elf_headers_sz;
 		kbuf.mem = KEXEC_BUF_MEM_UNKNOWN;
 		kbuf.memsz = image->elf_headers_sz;
+
+#ifdef CONFIG_CRASH_HOTPLUG
+		if (image->elf_headers_sz < pnum_hdr_sz(PN_XNUM))
+			image->elfcorehdr_index = image->nr_segments;
+#endif
+
 		kbuf.buf_align = SZ_64K; /* largest supported page size */
 		kbuf.buf_max = ULONG_MAX;
 		kbuf.top_down = true;
-- 
2.34.1



From yongxuan.wang at sifive.com  Mon Jun  1 03:26:21 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 03:26:21 -0700
Subject: [PATCH v5 0/5] KVM: riscv: Fix stale FWFT feature exposure and
 enhance selftests
Message-ID: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>

This series fixes three bugs in the SBI FWFT (Firmware Features) extension
and improves the related selftest infrastructure.
The bugs are:
1. Missing CSR dirty marking: When userspace sets FWFT feature values via
   KVM_SET_ONE_REG, modified CSRs (e.g., henvcfg.PMM for pointer masking)
   are not marked dirty, leading to stale state after vCPU scheduling or
   migration.
2. Hardware probing side effects: The try_to_set_pmm() function modifies
   HENVCFG.PMM during hardware capability detection but fails to restore
   the original value, leaving the CSR in an altered state that affects
   subsequent operations.
3. Stale feature exposure: FWFT feature support is cached at vCPU
   initialization time. When userspace subsequently disables ISA extensions
   via KVM_SET_ONE_REG, the cached support status is not updated, allowing
   guests to access features that depend on disabled extensions.
Patches 1-3 fix these bugs separately.

The selftest improvements (patches 4-5) enhance the get-reg-list test by
refactoring the extension sublist infrastructure and splitting FWFT
feature testing into separate, properly-gated sublists.

---
Changes in v5:
- Add CSR dirty marking fix (new patch 1/5) (sashiko-bot)
- Split original FWFT bug fix into two focused patches
  - Add init() callback with try_to_set_pmm() restoration fix (new patch
    2/5) (sashiko-bot)
  - Keep runtime supported() checks as separate patch (patch 3/5)
- Link to v4: https://patch.msgid.link/20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda at sifive.com

Changes in v4:
- Rename the title of cover letter
- Disable preemption when running try_to_set_pmm() (sashiko-bot)
- Remove check_supported_reg() (sashiko-bot)
- Link to v3: https://patch.msgid.link/20260528-kvm-get_reg_list-v2-v3-0-170969a8599f at sifive.com

Changes in v3:
- Restore 'supported' field with init() callback for initialization probing
  (sashiko-bot)
- Add NULL checks before calling feature->supported() in all functions
- Fix isa_ext_enabled tracking logic and restore isa_ext_cant_disable array
- Add sbi_ext_enabled tracking and enhance dependency checking (sashiko-bot)
- Refine code organization and variable naming consistency (sashiko-bot)
- Link to v2: https://patch.msgid.link/20260526-kvm-get_reg_list-v2-v2-0-7940a401454a at sifive.com

Changes in v2:
- Fix FWFT stale feature exposure by removing static 'supported' field
- Refactor get-reg-list test to use unified extension sublist macros
- Split FWFT testing into per-feature sublists with runtime checks
  (Andrew)

To: Anup Patel <anup at brainfault.org>
To: Atish Patra <atish.patra at linux.dev>
To: Paul Walmsley <pjw at kernel.org>
To: Palmer Dabbelt <palmer at dabbelt.com>
To: Albert Ou <aou at eecs.berkeley.edu>
To: Alexandre Ghiti <alex at ghiti.fr>
To: Cl?ment L?ger <cleger at rivosinc.com>
To: Andrew Jones <ajones at ventanamicro.com>
To: Paolo Bonzini <pbonzini at redhat.com>
To: Shuah Khan <shuah at kernel.org>
Cc: greentime.hu at sifive.com
Cc: vincent.chen at sifive.com
Cc: zong.li at sifive.com
Cc: kvm at vger.kernel.org
Cc: kvm-riscv at lists.infradead.org
Cc: linux-riscv at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
Cc: linux-kselftest at vger.kernel.org

---
Yong-Xuan Wang (5):
      KVM: RISC-V: SBI FWFT: Mark vCPU CSRs dirty after setting feature value
      KVM: RISC-V: SBI FWFT: Add optional init() callback for hardware probing
      KVM: RISC-V: SBI FWFT: Fix stale feature exposure after runtime extension changes
      KVM: riscv: selftests: Refactor ISA and SBI extension sublist macros
      KVM: riscv: selftests: Split SBI FWFT into separate feature-specific sublists

 arch/riscv/kvm/vcpu_sbi_fwft.c                   |  44 +++++++-
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 138 ++++++++++++++---------
 2 files changed, 125 insertions(+), 57 deletions(-)
---
base-commit: c7832534a8160276cccb9a8cc8cafb5614c579d0
change-id: 20260526-kvm-get_reg_list-v2-f9f36961ac6c



From yongxuan.wang at sifive.com  Mon Jun  1 03:26:23 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 03:26:23 -0700
Subject: [PATCH v5 2/5] KVM: RISC-V: SBI FWFT: Add optional init() callback
 for hardware probing
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
Message-ID: <20260601-kvm-get_reg_list-v2-v5-2-415d08a2813b@sifive.com>

Add an optional init() callback to separate one-time hardware probing
from runtime availability checks. For pointer masking, this allows
probing supported PMM lengths during initialization while checking ISA
extension availability at runtime.

Fix try_to_set_pmm() to restore the previous HENVCFG.PMM value after
probing, preventing side effects from hardware detection. Add preemption
protection to ensure CSR probe sequences complete atomically on the same
CPU.

Fixes: 6f576fc0aeb9 ("RISC-V: KVM: Add support for SBI_FWFT_POINTER_MASKING_PMLEN")

Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
 arch/riscv/kvm/vcpu_sbi_fwft.c | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index 5e4aafb0cbf1..aee951f2b8e6 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -35,6 +35,16 @@ struct kvm_sbi_fwft_feature {
 	 */
 	bool (*supported)(struct kvm_vcpu *vcpu);
 
+	/**
+	 * @init: Probe and initialize the feature on the vcpu
+	 *
+	 * This callback is optional. If provided, it will be called during
+	 * vcpu initialization to probe the feature availability and perform
+	 * any necessary initialization. Returns true if the feature is supported
+	 * and initialized successfully, false otherwise.
+	 */
+	bool (*init)(struct kvm_vcpu *vcpu);
+
 	/**
 	 * @reset: Reset the feature value irrespective whether feature is supported or not
 	 *
@@ -131,19 +141,30 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
 
 static bool try_to_set_pmm(unsigned long value)
 {
+	unsigned long prev;
+	bool ret;
+
+	prev = csr_read_clear(CSR_HENVCFG, ENVCFG_PMM);
 	csr_set(CSR_HENVCFG, value);
-	return (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
+	ret = (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
+	csr_write(CSR_HENVCFG, prev);
+
+	return ret;
 }
 
 static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu)
 {
-	struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
+	return riscv_isa_extension_available(vcpu->arch.isa, SMNPM);
+}
 
-	if (!riscv_isa_extension_available(vcpu->arch.isa, SMNPM))
-		return false;
+static bool kvm_sbi_fwft_pointer_masking_pmlen_init(struct kvm_vcpu *vcpu)
+{
+	struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
 
+	preempt_disable();
 	fwft->have_vs_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7);
 	fwft->have_vs_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16);
+	preempt_enable();
 
 	return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16;
 }
@@ -231,6 +252,7 @@ static const struct kvm_sbi_fwft_feature features[] = {
 		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pointer_masking.enable) /
 				 sizeof(unsigned long),
 		.supported = kvm_sbi_fwft_pointer_masking_pmlen_supported,
+		.init = kvm_sbi_fwft_pointer_masking_pmlen_init,
 		.reset = kvm_sbi_fwft_reset_pointer_masking_pmlen,
 		.set = kvm_sbi_fwft_set_pointer_masking_pmlen,
 		.get = kvm_sbi_fwft_get_pointer_masking_pmlen,
@@ -365,6 +387,9 @@ static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu)
 		else
 			conf->supported = true;
 
+		if (conf->supported && feature->init)
+			conf->supported = feature->init(vcpu);
+
 		conf->enabled = conf->supported;
 		conf->feature = feature;
 	}

-- 
2.43.7



From yongxuan.wang at sifive.com  Mon Jun  1 03:26:25 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 03:26:25 -0700
Subject: [PATCH v5 4/5] KVM: riscv: selftests: Refactor ISA and SBI
 extension sublist macros
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
Message-ID: <20260601-kvm-get_reg_list-v2-v5-4-415d08a2813b@sifive.com>

Refactor the get-reg-list test to use unified sublist macros for ISA
and SBI extensions, eliminating code duplication and improving
maintainability.

Previously, each extension had its own hand-coded sublist definition
(e.g., SUBLIST_ZICBOM, SUBLIST_AIA, etc.) and the config structures
repeated the same pattern. This made the code verbose and error-prone.

Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 78 +++++++++---------------
 1 file changed, 28 insertions(+), 50 deletions(-)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index 8d6fdb5d38b8..5033c09201ef 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -1013,7 +1013,7 @@ static __u64 fp_d_regs[] = {
 };
 
 /* Define a default vector registers with length. This will be overwritten at runtime */
-static __u64 vector_regs[] = {
+static __u64 v_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vstart),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vl),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vtype),
@@ -1057,37 +1057,17 @@ static __u64 vector_regs[] = {
 #define SUBLIST_BASE \
 	{"base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), \
 	 .skips_set = base_skips_set, .skips_set_n = ARRAY_SIZE(base_skips_set),}
-#define SUBLIST_SBI_BASE \
-	{"sbi-base", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_V01, \
-	 .regs = sbi_base_regs, .regs_n = ARRAY_SIZE(sbi_base_regs),}
-#define SUBLIST_SBI_STA \
-	{"sbi-sta", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_STA, \
-	 .regs = sbi_sta_regs, .regs_n = ARRAY_SIZE(sbi_sta_regs),}
-#define SUBLIST_SBI_FWFT \
-	{"sbi-fwft", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_FWFT, \
-	 .regs = sbi_fwft_regs, .regs_n = ARRAY_SIZE(sbi_fwft_regs),}
-#define SUBLIST_ZICBOM \
-	{"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),}
-#define SUBLIST_ZICBOP \
-	{"zicbop", .feature = KVM_RISCV_ISA_EXT_ZICBOP, .regs = zicbop_regs, .regs_n = ARRAY_SIZE(zicbop_regs),}
-#define SUBLIST_ZICBOZ \
-	{"zicboz", .feature = KVM_RISCV_ISA_EXT_ZICBOZ, .regs = zicboz_regs, .regs_n = ARRAY_SIZE(zicboz_regs),}
-#define SUBLIST_AIA \
-	{"aia", .feature = KVM_RISCV_ISA_EXT_SSAIA, .regs = aia_regs, .regs_n = ARRAY_SIZE(aia_regs),}
-#define SUBLIST_SMSTATEEN \
-	{"smstateen", .feature = KVM_RISCV_ISA_EXT_SMSTATEEN, .regs = smstateen_regs, .regs_n = ARRAY_SIZE(smstateen_regs),}
-#define SUBLIST_FP_F \
-	{"fp_f", .feature = KVM_RISCV_ISA_EXT_F, .regs = fp_f_regs, \
-		.regs_n = ARRAY_SIZE(fp_f_regs),}
-#define SUBLIST_FP_D \
-	{"fp_d", .feature = KVM_RISCV_ISA_EXT_D, .regs = fp_d_regs, \
-		.regs_n = ARRAY_SIZE(fp_d_regs),}
-
-#define SUBLIST_V \
-	{"v", .feature = KVM_RISCV_ISA_EXT_V, .regs = vector_regs, .regs_n = ARRAY_SIZE(vector_regs),}
+
+#define SUBLIST_ISA(ext, extu)				\
+	{						\
+		.name = #ext,				\
+		.feature = KVM_RISCV_ISA_EXT_##extu,	\
+		.regs = ext##_regs,			\
+		.regs_n = ARRAY_SIZE(ext##_regs),	\
+	}
 
 #define KVM_ISA_EXT_SIMPLE_CONFIG(ext, extu)			\
-static __u64 regs_##ext[] = {					\
+static __u64 ext##_regs[] = {					\
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG |			\
 	KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE |	\
 	KVM_RISCV_ISA_EXT_##extu,				\
@@ -1095,18 +1075,22 @@ static __u64 regs_##ext[] = {					\
 static struct vcpu_reg_list config_##ext = {			\
 	.sublists = {						\
 		SUBLIST_BASE,					\
-		{						\
-			.name = #ext,				\
-			.feature = KVM_RISCV_ISA_EXT_##extu,	\
-			.regs = regs_##ext,			\
-			.regs_n = ARRAY_SIZE(regs_##ext),	\
-		},						\
+		SUBLIST_ISA(ext, extu),				\
 		{0},						\
 	},							\
 }								\
 
+#define SUBLIST_SBI(ext, extu)					\
+	{							\
+		.name = "sbi-"#ext,				\
+		.feature_type = VCPU_FEATURE_SBI_EXT,		\
+		.feature = KVM_RISCV_SBI_EXT_##extu,		\
+		.regs = sbi_##ext##_regs,			\
+		.regs_n = ARRAY_SIZE(sbi_##ext##_regs),		\
+	}
+
 #define KVM_SBI_EXT_SIMPLE_CONFIG(ext, extu)			\
-static __u64 regs_sbi_##ext[] = {				\
+static __u64 sbi_##ext##_regs[] = {				\
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG |			\
 	KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE |	\
 	KVM_RISCV_SBI_EXT_##extu,				\
@@ -1114,13 +1098,7 @@ static __u64 regs_sbi_##ext[] = {				\
 static struct vcpu_reg_list config_sbi_##ext = {		\
 	.sublists = {						\
 		SUBLIST_BASE,					\
-		{						\
-			.name = "sbi-"#ext,			\
-			.feature_type = VCPU_FEATURE_SBI_EXT,	\
-			.feature = KVM_RISCV_SBI_EXT_##extu,	\
-			.regs = regs_sbi_##ext,			\
-			.regs_n = ARRAY_SIZE(regs_sbi_##ext),	\
-		},						\
+		SUBLIST_SBI(ext, extu),				\
 		{0},						\
 	},							\
 }								\
@@ -1129,7 +1107,7 @@ static struct vcpu_reg_list config_sbi_##ext = {		\
 static struct vcpu_reg_list config_##ext = {			\
 	.sublists = {						\
 		SUBLIST_BASE,					\
-		SUBLIST_##extu,					\
+		SUBLIST_ISA(ext, extu),				\
 		{0},						\
 	},							\
 }								\
@@ -1138,14 +1116,14 @@ static struct vcpu_reg_list config_##ext = {			\
 static struct vcpu_reg_list config_sbi_##ext = {		\
 	.sublists = {						\
 		SUBLIST_BASE,					\
-		SUBLIST_SBI_##extu,				\
+		SUBLIST_SBI(ext, extu),				\
 		{0},						\
 	},							\
 }								\
 
 /* Note: The below list is alphabetically sorted. */
 
-KVM_SBI_EXT_SUBLIST_CONFIG(base, BASE);
+KVM_SBI_EXT_SUBLIST_CONFIG(base, V01);
 KVM_SBI_EXT_SUBLIST_CONFIG(sta, STA);
 KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
 KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
@@ -1153,9 +1131,9 @@ KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP);
 KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY);
 KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT);
 
-KVM_ISA_EXT_SUBLIST_CONFIG(aia, AIA);
-KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, FP_F);
-KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, FP_D);
+KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA);
+KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F);
+KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, D);
 KVM_ISA_EXT_SUBLIST_CONFIG(v, V);
 KVM_ISA_EXT_SIMPLE_CONFIG(h, H);
 KVM_ISA_EXT_SIMPLE_CONFIG(smnpm, SMNPM);

-- 
2.43.7



From yongxuan.wang at sifive.com  Mon Jun  1 03:26:22 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 03:26:22 -0700
Subject: [PATCH v5 1/5] KVM: RISC-V: SBI FWFT: Mark vCPU CSRs dirty after
 setting feature value
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
Message-ID: <20260601-kvm-get_reg_list-v2-v5-1-415d08a2813b@sifive.com>

Mark the vCPU CSRs as dirty after successfully setting an FWFT feature
value. FWFT features may modify CSRs (e.g., pointer masking modifies
henvcfg.PMM), and failing to mark them dirty can lead to the guest
observing stale CSR state after vCPU scheduling or migration.

Fixes: 1323a5cfe52c ("KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core")

Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
 arch/riscv/kvm/vcpu_sbi_fwft.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index 2eab15339694..5e4aafb0cbf1 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -521,6 +521,7 @@ static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
 		break;
 	case 2:
 		ret = conf->feature->set(vcpu, conf, true, value);
+		vcpu->arch.csr_dirty = true;
 		break;
 	default:
 		return -ENOENT;

-- 
2.43.7



From yongxuan.wang at sifive.com  Mon Jun  1 03:26:24 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 03:26:24 -0700
Subject: [PATCH v5 3/5] KVM: RISC-V: SBI FWFT: Fix stale feature exposure
 after runtime extension changes
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
Message-ID: <20260601-kvm-get_reg_list-v2-v5-3-415d08a2813b@sifive.com>

Fix a bug where FWFT features could be incorrectly exposed to guests
after userspace disables their dependent ISA extensions at runtime.

The 'supported' field in kvm_sbi_fwft_config was set once during vCPU
initialization based on the initial hardware/extension availability.
However, when userspace subsequently disables ISA extensions via the KVM
ONE_REG interface, the 'supported' field was not updated. This caused
the following issues:
1. FWFT features would remain visible and accessible to guests even
   after their prerequisite ISA extensions were disabled
2. Guests could configure FWFT features that depend on disabled
   extensions, leading to undefined behavior
3. The static 'supported' flag and the dynamic supported() callback
   could disagree about feature availability

The fix introduces a two-layer checking mechanism:
1. Add an optional init() callback to the kvm_sbi_fwft_feature structure
   for features that require hardware probing during initialization. This
   separates the one-time hardware detection logic from the runtime
   availability check.
2. Add runtime checks in all FWFT-related functions that call
   feature->supported(vcpu) if the callback exists. This ensures feature
   availability is re-evaluated based on the current ISA extension state.

This approach maintains the cached 'supported' field for initialization-
time decisions while ensuring runtime availability is always determined
by the current vCPU configuration, not initialization-time snapshots.

Fixes: 6b72fd170592 ("RISC-V: KVM: add support for FWFT SBI extension")

Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
 arch/riscv/kvm/vcpu_sbi_fwft.c | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index aee951f2b8e6..ab39ac464ffd 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -303,6 +303,8 @@ static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature,
 
 	if (!tconf->supported || !tconf->enabled)
 		return SBI_ERR_NOT_SUPPORTED;
+	else if (tconf->feature->supported && !tconf->feature->supported(vcpu))
+		return SBI_ERR_NOT_SUPPORTED;
 
 	*conf = tconf;
 
@@ -433,6 +435,8 @@ static unsigned long kvm_sbi_ext_fwft_get_reg_count(struct kvm_vcpu *vcpu)
 		conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
 		if (!conf || !conf->supported)
 			continue;
+		else if (conf->feature->supported && !conf->feature->supported(vcpu))
+			continue;
 
 		ret++;
 	}
@@ -455,6 +459,8 @@ static int kvm_sbi_ext_fwft_get_reg_id(struct kvm_vcpu *vcpu, int index, u64 *re
 		conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
 		if (!conf || !conf->supported)
 			continue;
+		else if (conf->feature->supported && !conf->feature->supported(vcpu))
+			continue;
 
 		if (index == idx) {
 			*reg_id = KVM_REG_RISCV |
@@ -490,6 +496,8 @@ static int kvm_sbi_ext_fwft_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
 	conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
 	if (!conf || !conf->supported)
 		return -ENOENT;
+	else if (conf->feature->supported && !conf->feature->supported(vcpu))
+		return -ENOENT;
 
 	switch (reg_num - feature->first_reg_num) {
 	case 0:
@@ -527,6 +535,8 @@ static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
 	conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
 	if (!conf || !conf->supported)
 		return -ENOENT;
+	else if (conf->feature->supported && !conf->feature->supported(vcpu))
+		return -ENOENT;
 
 	switch (reg_num - feature->first_reg_num) {
 	case 0:

-- 
2.43.7



From yongxuan.wang at sifive.com  Mon Jun  1 03:26:26 2026
From: yongxuan.wang at sifive.com (Yong-Xuan Wang)
Date: Mon, 01 Jun 2026 03:26:26 -0700
Subject: [PATCH v5 5/5] KVM: riscv: selftests: Split SBI FWFT into separate
 feature-specific sublists
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
Message-ID: <20260601-kvm-get_reg_list-v2-v5-5-415d08a2813b@sifive.com>

Divide the monolithic SBI FWFT (Firmware Features) register list into
separate sublists, each testing a specific FWFT feature independently
with proper dependency checking.

Previously, all FWFT features were tested together in a single sublist.
This caused issues because:
1. Not all FWFT features are available on all platforms
2. Some features depend on specific ISA extensions (e.g., pointer_masking
requires Smnpm)
3. Tests would fail if any single feature was unavailable

Add the feature-specific SBI FWFT sublists with the following
improvements:
- Add check_fwft_feature() helper to verify FWFT feature availability
  at runtime
- Update filter_reg() to handle per-feature FWFT register filtering

Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>
---
 tools/testing/selftests/kvm/riscv/get-reg-list.c | 60 ++++++++++++++++++++++--
 1 file changed, 57 insertions(+), 3 deletions(-)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index 5033c09201ef..cb86cb6b3635 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -27,6 +27,7 @@ enum {
 };
 
 static bool isa_ext_cant_disable[KVM_RISCV_ISA_EXT_MAX];
+static bool sbi_ext_enabled[KVM_RISCV_SBI_EXT_MAX];
 
 bool filter_reg(__u64 reg)
 {
@@ -149,6 +150,14 @@ bool filter_reg(__u64 reg)
 	case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1h):
 	case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio2h):
 		return isa_ext_cant_disable[KVM_RISCV_ISA_EXT_SSAIA];
+	/*
+	 * FWFT misaligned delegation registers are always visible when the SBI FWFT
+	 * extension is enable and the host supports the misaligned delegation.
+	 */
+	case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable):
+	case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags):
+	case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value):
+		return sbi_ext_enabled[KVM_RISCV_SBI_EXT_FWFT];
 	default:
 		break;
 	}
@@ -193,6 +202,27 @@ static int override_vector_reg_size(struct kvm_vcpu *vcpu, struct vcpu_reg_subli
 	return 0;
 }
 
+void check_fwft_feature(struct kvm_vcpu *vcpu, struct vcpu_reg_sublist *s, u64 feature)
+{
+	unsigned long value;
+	int rc;
+
+	/* Enable SBI FWFT extension so that we can check the supported register */
+	rc = __vcpu_set_reg(vcpu, feature, 1);
+	if (rc)
+		return;
+
+	for (int i = 0; i < s->regs_n; i++) {
+		if ((s->regs[i] & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_SBI_STATE) {
+			rc = __vcpu_get_reg(vcpu, s->regs[i], &value);
+			__TEST_REQUIRE(!rc, "%s not available, skipping tests", s->name);
+		}
+	}
+
+	/* We should assert if disabling failed here while enabling succeeded before */
+	vcpu_set_reg(vcpu, feature, 0);
+}
+
 void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
 {
 	unsigned long isa_ext_state[KVM_RISCV_ISA_EXT_MAX] = { 0 };
@@ -235,6 +265,9 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
 			break;
 		case VCPU_FEATURE_SBI_EXT:
 			feature = RISCV_SBI_EXT_REG(s->feature);
+			if (s->feature == KVM_RISCV_SBI_EXT_FWFT)
+				check_fwft_feature(vcpu, s, feature);
+			sbi_ext_enabled[s->feature] = true;
 			break;
 		default:
 			TEST_FAIL("Unknown feature type");
@@ -897,11 +930,15 @@ static __u64 sbi_sta_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_hi),
 };
 
-static __u64 sbi_fwft_regs[] = {
+static __u64 sbi_fwft_misaligned_deleg_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value),
+};
+
+static __u64 sbi_fwft_pointer_masking_regs[] = {
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value),
@@ -1129,7 +1166,6 @@ KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
 KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
 KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP);
 KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY);
-KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT);
 
 KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA);
 KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F);
@@ -1206,6 +1242,23 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zvksed, ZVKSED);
 KVM_ISA_EXT_SIMPLE_CONFIG(zvksh, ZVKSH);
 KVM_ISA_EXT_SIMPLE_CONFIG(zvkt, ZVKT);
 
+static struct vcpu_reg_list config_sbi_fwft_misaligned_deleg = {
+	.sublists = {
+		SUBLIST_BASE,
+		SUBLIST_SBI(fwft_misaligned_deleg, FWFT),
+		{0},
+	},
+};
+
+static struct vcpu_reg_list config_sbi_fwft_pointer_masking = {
+	.sublists = {
+		SUBLIST_BASE,
+		SUBLIST_ISA(smnpm, SMNPM),
+		SUBLIST_SBI(fwft_pointer_masking, FWFT),
+		{0},
+	},
+};
+
 struct vcpu_reg_list *vcpu_configs[] = {
 	&config_sbi_base,
 	&config_sbi_sta,
@@ -1213,7 +1266,8 @@ struct vcpu_reg_list *vcpu_configs[] = {
 	&config_sbi_dbcn,
 	&config_sbi_susp,
 	&config_sbi_mpxy,
-	&config_sbi_fwft,
+	&config_sbi_fwft_misaligned_deleg,
+	&config_sbi_fwft_pointer_masking,
 	&config_aia,
 	&config_fp_f,
 	&config_fp_d,

-- 
2.43.7



From inochiama at gmail.com  Mon Jun  1 04:16:00 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Mon, 1 Jun 2026 19:16:00 +0800
Subject: [PATCH v2 4/7] RISC-V: KVM: Allow Zicfiss/Zicfilp extensions for
 Guest/VM
In-Reply-To: <20260601084336.2601675-5-inochiama@gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
 <20260601084336.2601675-5-inochiama@gmail.com>
Message-ID: <ah1pgb4S-UoSWhC_@inochi.infowork>

On Mon, Jun 01, 2026 at 04:43:32PM +0800, Inochi Amaoto wrote:
> Extend the KVM ISA extension array to allow KVM userspace to
> detect and enable Zicfiss/Zicfilp extensions for Guest/VM.
> 
> Assisted-by: YuanSheng:claude-4.7-opus
> Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
> Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> ---
>  arch/riscv/include/uapi/asm/kvm.h | 2 ++
>  arch/riscv/kvm/isa.c              | 2 ++
>  2 files changed, 4 insertions(+)
> 

I have forgot to add CSR_SSP to the context, will add in the next
version. But I have a small question for it: could I reuse the 
generic subtype or use a new CSR subtype?

Regards,
Inochi

> diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
> index 501e4fc60dd2..9f9c5ababd1e 100644
> --- a/arch/riscv/include/uapi/asm/kvm.h
> +++ b/arch/riscv/include/uapi/asm/kvm.h
> @@ -199,6 +199,8 @@ enum KVM_RISCV_ISA_EXT_ID {
>  	KVM_RISCV_ISA_EXT_ZCLSD,
>  	KVM_RISCV_ISA_EXT_ZILSD,
>  	KVM_RISCV_ISA_EXT_ZALASR,
> +	KVM_RISCV_ISA_EXT_ZICFILP,
> +	KVM_RISCV_ISA_EXT_ZICFISS,
>  	KVM_RISCV_ISA_EXT_MAX,
>  };
>  
> diff --git a/arch/riscv/kvm/isa.c b/arch/riscv/kvm/isa.c
> index 1132d909cc25..9852a91fdecc 100644
> --- a/arch/riscv/kvm/isa.c
> +++ b/arch/riscv/kvm/isa.c
> @@ -65,6 +65,8 @@ static const unsigned long kvm_isa_ext_arr[] = {
>  	KVM_ISA_EXT_ARR(ZICBOP),
>  	KVM_ISA_EXT_ARR(ZICBOZ),
>  	KVM_ISA_EXT_ARR(ZICCRSE),
> +	KVM_ISA_EXT_ARR(ZICFILP),
> +	KVM_ISA_EXT_ARR(ZICFISS),
>  	KVM_ISA_EXT_ARR(ZICNTR),
>  	KVM_ISA_EXT_ARR(ZICOND),
>  	KVM_ISA_EXT_ARR(ZICSR),
> -- 
> 2.54.0
> 
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv


From david at kernel.org  Mon Jun  1 05:22:52 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Mon, 1 Jun 2026 14:22:52 +0200
Subject: [PATCH v3 1/5] mm/sparse-vmemmap: provide generic
 vmemmap_set_pmd() and vmemmap_check_pmd()
In-Reply-To: <20260601084845.3792171-2-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-2-songmuchun@bytedance.com>
Message-ID: <db8d440d-c8a1-4f77-b5d9-00bab8737f12@kernel.org>

On 6/1/26 10:48, Muchun Song wrote:
> The two weak functions are currently no-ops on every architecture,
> forcing each platform that needs them to duplicate the same handful
> of lines.  Provide a generic implementation:
> 
> - vmemmap_set_pmd() simply sets a huge PMD with PAGE_KERNEL protection.
> 
> - vmemmap_check_pmd() verifies that the PMD is present and leaf,
>   then calls the existing vmemmap_verify() helper.
> 
> Architectures that need special handling can continue to override the
> weak symbols; everyone else gets the standard version for free.
> 
> Signed-off-by: Muchun Song <songmuchun at bytedance.com>
> ---
> v2->v3:
> - Replace BUG_ON() with WARN_ON_ONCE() in vmemmap_set_pmd()
> ---
>  mm/sparse-vmemmap.c | 7 ++++++-
>  1 file changed, 6 insertions(+), 1 deletion(-)
> 
> diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
> index 112ccf9c71ca..99e2be39671b 100644
> --- a/mm/sparse-vmemmap.c
> +++ b/mm/sparse-vmemmap.c
> @@ -386,12 +386,17 @@ int __meminit vmemmap_populate_hvo(unsigned long addr, unsigned long end,
>  void __weak __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,
>  				      unsigned long addr, unsigned long next)
>  {
> +	WARN_ON_ONCE(!pmd_set_huge(pmd, virt_to_phys(p), PAGE_KERNEL));


Not sure if a VM_WARN_ON_ONCE() would be appropriate. (then, we have to move the
pmd_set_huge() out of the statement).

Acked-by: David Hildenbrand (Arm) <david at kernel.org>


-- 
Cheers,

David


From david at kernel.org  Mon Jun  1 05:23:08 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Mon, 1 Jun 2026 14:23:08 +0200
Subject: [PATCH v3 2/5] arm64/mm: drop vmemmap_pmd helpers and use generic
 code
In-Reply-To: <20260601084845.3792171-3-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-3-songmuchun@bytedance.com>
Message-ID: <c9783e61-cbc0-449a-9a0b-db40fb335e99@kernel.org>

On 6/1/26 10:48, Muchun Song wrote:
> The generic implementations now suffice; remove the arm64 copies.
> 
> Signed-off-by: Muchun Song <songmuchun at bytedance.com>
> Acked-by: Will Deacon <will at kernel.org>
> ---

Reviewed-by: David Hildenbrand (Arm) <david at kernel.org>

-- 
Cheers,

David


From david at kernel.org  Mon Jun  1 05:23:26 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Mon, 1 Jun 2026 14:23:26 +0200
Subject: [PATCH v3 3/5] riscv/mm: drop vmemmap_pmd helpers and use generic
 code
In-Reply-To: <20260601084845.3792171-4-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-4-songmuchun@bytedance.com>
Message-ID: <87985f48-2668-4fd0-aae9-3754d2f6bd93@kernel.org>

On 6/1/26 10:48, Muchun Song wrote:
> The generic implementations now suffice; remove the riscv copies.
> 
> Signed-off-by: Muchun Song <songmuchun at bytedance.com>
> ---

Reviewed-by: David Hildenbrand (Arm) <david at kernel.org>

-- 
Cheers,

David


From david at kernel.org  Mon Jun  1 05:24:38 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Mon, 1 Jun 2026 14:24:38 +0200
Subject: [PATCH v3 4/5] loongarch/mm: drop vmemmap_check_pmd helper and
 use generic code
In-Reply-To: <20260601084845.3792171-5-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-5-songmuchun@bytedance.com>
Message-ID: <8c60f9bb-7a4a-4340-b414-9f7fbef4150c@kernel.org>

On 6/1/26 10:48, Muchun Song wrote:
> The generic implementations now suffice; remove the loongarch copies.

You are only removing a single function? So "copy"


Reviewed-by: David Hildenbrand (Arm) <david at kernel.org>

-- 
Cheers,

David


From david at kernel.org  Mon Jun  1 05:25:05 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Mon, 1 Jun 2026 14:25:05 +0200
Subject: [PATCH v3 5/5] sparc/mm: drop vmemmap_check_pmd helper and use
 generic code
In-Reply-To: <20260601084845.3792171-6-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-6-songmuchun@bytedance.com>
Message-ID: <61f0dae7-4e49-4142-8b0d-10c175856277@kernel.org>

On 6/1/26 10:48, Muchun Song wrote:
> The generic implementations now suffice; remove the sparc copies.

"copy"

Reviewed-by: David Hildenbrand (Arm) <david at kernel.org>

-- 
Cheers,

David


From muchun.song at linux.dev  Mon Jun  1 05:26:47 2026
From: muchun.song at linux.dev (Muchun Song)
Date: Mon, 1 Jun 2026 20:26:47 +0800
Subject: [PATCH v3 4/5] loongarch/mm: drop vmemmap_check_pmd helper and
 use generic code
In-Reply-To: <8c60f9bb-7a4a-4340-b414-9f7fbef4150c@kernel.org>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-5-songmuchun@bytedance.com>
 <8c60f9bb-7a4a-4340-b414-9f7fbef4150c@kernel.org>
Message-ID: <0C8C9C2B-2EDA-47DB-AC54-237F2127A6A8@linux.dev>



> On Jun 1, 2026, at 20:24, David Hildenbrand (Arm) <david at kernel.org> wrote:
> 
> On 6/1/26 10:48, Muchun Song wrote:
>> The generic implementations now suffice; remove the loongarch copies.
> 
> You are only removing a single function? So "copy"

Yes. I copied the commit message from other commit and forgot to update
accordingly.

> 
> 
> Reviewed-by: David Hildenbrand (Arm) <david at kernel.org>

Thanks.

> 
> -- 
> Cheers,
> 
> David



From muchun.song at linux.dev  Mon Jun  1 05:37:42 2026
From: muchun.song at linux.dev (Muchun Song)
Date: Mon, 1 Jun 2026 20:37:42 +0800
Subject: [PATCH v3 1/5] mm/sparse-vmemmap: provide generic
 vmemmap_set_pmd() and vmemmap_check_pmd()
In-Reply-To: <db8d440d-c8a1-4f77-b5d9-00bab8737f12@kernel.org>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-2-songmuchun@bytedance.com>
 <db8d440d-c8a1-4f77-b5d9-00bab8737f12@kernel.org>
Message-ID: <0D4AF42F-37C5-4A76-9703-44ACC6374C48@linux.dev>



> On Jun 1, 2026, at 20:22, David Hildenbrand (Arm) <david at kernel.org> wrote:
> 
> On 6/1/26 10:48, Muchun Song wrote:
>> The two weak functions are currently no-ops on every architecture,
>> forcing each platform that needs them to duplicate the same handful
>> of lines.  Provide a generic implementation:
>> 
>> - vmemmap_set_pmd() simply sets a huge PMD with PAGE_KERNEL protection.
>> 
>> - vmemmap_check_pmd() verifies that the PMD is present and leaf,
>>  then calls the existing vmemmap_verify() helper.
>> 
>> Architectures that need special handling can continue to override the
>> weak symbols; everyone else gets the standard version for free.
>> 
>> Signed-off-by: Muchun Song <songmuchun at bytedance.com>
>> ---
>> v2->v3:
>> - Replace BUG_ON() with WARN_ON_ONCE() in vmemmap_set_pmd()
>> ---
>> mm/sparse-vmemmap.c | 7 ++++++-
>> 1 file changed, 6 insertions(+), 1 deletion(-)
>> 
>> diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
>> index 112ccf9c71ca..99e2be39671b 100644
>> --- a/mm/sparse-vmemmap.c
>> +++ b/mm/sparse-vmemmap.c
>> @@ -386,12 +386,17 @@ int __meminit vmemmap_populate_hvo(unsigned long addr, unsigned long end,
>> void __weak __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,
>>       unsigned long addr, unsigned long next)
>> {
>> + 	WARN_ON_ONCE(!pmd_set_huge(pmd, virt_to_phys(p), PAGE_KERNEL));
> 
> 
> Not sure if a VM_WARN_ON_ONCE() would be appropriate. (then, we have to move the
> pmd_set_huge() out of the statement).

I think it might be better to keep WARN_ON_ONCE here. This way, we can still
monitor for warnings in production while keeping the code simple.

> 
> Acked-by: David Hildenbrand (Arm) <david at kernel.org>

Thanks.

> 
> 
> -- 
> Cheers,
> 
> David




From docular.xu at gmail.com  Mon Jun  1 18:35:06 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Mon, 01 Jun 2026 21:35:06 -0400
Subject: [PATCH] MAINTAINERS: add entry for SpacemiT reset controller
 driver
Message-ID: <20260601-b4-spacemit-reset-maintainers-v1-1-1ab3014e9a35@gmail.com>

The SpacemiT reset controller driver under drivers/reset/spacemit/
(common code plus the K1 and K3 SoC instances) and its reset-ID header
have no dedicated MAINTAINERS entry; today they fall only under the
broad drivers/reset/ entry of the reset subsystem and the N:/K:
catch-all of the RISC-V SpacemiT SoC umbrella.

Add a dedicated entry and list myself as maintainer. I introduced the
drivers/reset/spacemit/ subdirectory, moved and refactored the existing
K1 reset support (originally written by Alex Elder) into it, and wrote
the K3 reset driver. The series that created this directory and these
files is archived at [1].

[1] https://lore.kernel.org/spacemit/20260120-k3-reset-v3-0-effe87f4bdbe at riscstar.com/

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
I contributed this driver as Guodong Xu <guodong at riscstar.com>;
docular.xu at gmail.com is my current address. A matching .mailmap update
has been submitted at
https://lore.kernel.org/all/20260601-b4-mailmap-guodong-xu-v1-1-ee9eff1e57ba at gmail.com/
---
 MAINTAINERS | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44a..c9d87244c1715 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25119,6 +25119,13 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/i2c/spacemit,k1-i2c.yaml
 F:	drivers/i2c/busses/i2c-k1.c
 
+SPACEMIT RESET CONTROLLER DRIVER
+M:	Guodong Xu <docular.xu at gmail.com>
+L:	linux-riscv at lists.infradead.org
+S:	Maintained
+F:	drivers/reset/spacemit/
+F:	include/dt-bindings/reset/spacemit,k3-resets.h
+
 SPANISH DOCUMENTATION
 M:	Carlos Bilbao <carlos.bilbao at kernel.org>
 R:	Avadhut Naik <avadhut.naik at amd.com>

---
base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
change-id: 20260601-b4-spacemit-reset-maintainers-4b5a91599585

Best regards,
--  
Guodong Xu <docular.xu at gmail.com>



From baoquan.he at linux.dev  Mon Jun  1 06:40:23 2026
From: baoquan.he at linux.dev (Baoquan He)
Date: Mon, 1 Jun 2026 21:40:23 +0800
Subject: [PATCH v15 00/23] arm64/riscv: Add support for crashkernel CMA
 reservation
In-Reply-To: <20260601094805.2928614-1-ruanjinjie@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
Message-ID: <ah2Lx7KHI60tzd0v@MiWiFi-R3L-srv>

Hi Jinjie,

On 06/01/26 at 05:47pm, Jinjie Ruan wrote:
...snip... 
> Changes in v15:
> - Unify the subject prefix formats as Huacai suggested.
> - Fix powerpc pre-existing NULL pointer dereference [Sashiko [1]]
> - Fix powerpc pre-existing __merge_memory_ranges() memory range
>   truncation [Sashiko [1]].
> - Fix pre-existing arm64 CMA page leaks [Sashiko[2]].
> - Fix pre-existing crash_load_dm_crypt_keys() Use-After-Free and
>   Double Free issue [Sashiko[3]].
> - Fix vfree(headers) and uninitialized variables issue
>   and simplify the fix [Sashiko[2]].
> - As walk_system_ram_res() and for_each_mem_range() use different
>   lock, unify and simplify the fix of TOCTOU buffer overflow via memory
>   region padding [Sashiko[4]].
> - Fix the arm64 crash dump issues in Sashiko[5].
> - Link to v14: https://lore.kernel.org/all/20260525084932.934910-1-ruanjinjie at huawei.com/

Do these Fixes have anything with the main target of this patch series
you mentioned in cover-letter:"arm64/riscv: Add support for crashkernel CMA"?
The patches become more and more in each new version, I am wondering if
it relies on these Fixes patches to implement your adding support for
crashkernel CMA on arm64/risc-v.

If not relying on them, could you split them into different patchset
on different purpose? 

Thanks
Baoquan

> 
> [1]: https://lore.kernel.org/all/20260525092207.96B9D1F000E9 at smtp.kernel.org/
> [2]: https://lore.kernel.org/all/20260525091149.1A1E01F00A3D at smtp.kernel.org/
> [3]: https://lore.kernel.org/all/20260525105227.3C2421F000E9 at smtp.kernel.org/
> [4]: https://lore.kernel.org/all/20260525095447.944E11F000E9 at smtp.kernel.org/
> [5]: https://lore.kernel.org/all/20260525101746.9959D1F000E9 at smtp.kernel.org/
> 
> Changes in v14:
> - Fix image->elf_headers memory leak during retry loop for arm64 as Sashiko
>   AI code review pointed out.
> - Solve the hotplug notifier arch_crash_handle_hotplug_event() AA
>   self-deadlock problem as Sashiko AI code review pointed out.
> - Fix the TOCTOU issue in prepare_elf_headers() by get_online_mems().
> - -ENOMEM -> -EAGAIN as Breno suggested.
> - Add support for arm64 crash hotplug.
> - Link to v13: https://lore.kernel.org/all/20260511030454.1730881-1-ruanjinjie at huawei.com/
> 
> Changes in v13:
> - Rebased on v7.1-rc1.
> - Update the commit message.
> - Add Reviewed-by.
> - Link to v12: https://lore.kernel.org/all/20260402072701.628293-1-ruanjinjie at huawei.com/
> 
> Changes in v12:
> - Remove the unused "nr_mem_ranges" for x86.
> - Add "Fix crashk_low_res not exclude bug" test log.
> - Provide a separate patch for each architecture for using
>   crash_prepare_headers(), which will make the review more convenient.
> - Add Reviewed-by and Tested-by.
> - Link to v11: https://lore.kernel.org/all/20260328074013.3589544-1-ruanjinjie at huawei.com/
> 
> Changes in v11:
> - Avoid silently drop crash memory if the crash kernel is built without
>   CONFIG_CMA.
> - Remove unnecessary "cmem->nr_ranges = 0" for arch_crash_populate_cmem()
>   as we use kvzalloc().
> - Provide a separate patch for each architecture to fix the existing
>   buffer overflow issue.
> - Add Acked-bys for arm64.
> 
> Changes in v10:
> - Fix crashk_low_res not excluded bug in the existing
>   RISC-V code.
> - Fix an existing memory leak issue in the existing PowerPC code.
> - Fix the ordering issue of adding CMA ranges to
>   "linux,usable-memory-range".
> - Fix an existing concurrency issue. A Concurrent memory hotplug may occur
>   between reading memblock and attempting to fill cmem during kexec_load()
>   for almost all existing architectures.
> - Link to v9: https://lore.kernel.org/all/20260323072745.2481719-1-ruanjinjie at huawei.com/
> 
> Changes in v9:
> - Collect Reviewed-by and Acked-by, and prepare for Sashiko AI review.
> - Link to v8: https://lore.kernel.org/all/20260302035315.3892241-1-ruanjinjie at huawei.com/
> 
> Changes in v8:
> - Fix the build issues reported by kernel test robot and Sourabh.
> - Link to v7: https://lore.kernel.org/all/20260226130437.1867658-1-ruanjinjie at huawei.com/
> 
> Changes in v7:
> - Correct the inclusion of CMA-reserved ranges for kdump kernel in of/kexec
>   for arm64 and riscv.
> - Add Acked-by.
> - Link to v6: https://lore.kernel.org/all/20260224085342.387996-1-ruanjinjie at huawei.com/
> 
> Changes in v6:
> - Update the crash core exclude code as Mike suggested.
> - Rebased on v7.0-rc1.
> - Add acked-by.
> - Link to v5: https://lore.kernel.org/all/20260212101001.343158-1-ruanjinjie at huawei.com/
> 
> Jinjie Ruan (22):
>   riscv: kexec_file: Fix crashk_low_res not exclude bug
>   powerpc/crash: Fix possible memory leak in update_crash_elfcorehdr()
>   powerpc/kexec_file: Fix NULL pointer dereference in
>     kexec_extra_fdt_size_ppc64()
>   powerpc/kexec_file: Fix memory range truncation in
>     __merge_memory_ranges()
>   kexec: Extract kexec_free_segment_cma() from kimage_free_cma()
>   arm64: kexec_file: Fix CMA page leaks during segment placement retry
>     loops
>   arm64: kexec_file: Fix image->elf_headers memory leak during retry
>     loop
>   kexec: Fix UAF and Double Free in crash_load_dm_crypt_keys()
>   crash_core: Introduce CRASH_HOTPLUG_SAFETY_PADDING for memory hotplug
>     safety
>   x86: kexec_file: Fix TOCTOU buffer overflow via memory region padding
>   arm64: kexec_file: Fix TOCTOU buffer overflow via memory region
>     padding
>   riscv: kexec_file: Fix TOCTOU buffer overflow via memory region
>     padding
>   LoongArch: kexec_file: Fix TOCTOU buffer overflow via memory region
>     padding
>   crash: Add crash_prepare_headers() to exclude crash kernel memory
>   arm64: kexec_file: Use crash_prepare_headers() helper to simplify code
>   x86: kexec_file: Use crash_prepare_headers() helper to simplify code
>   riscv: kexec_file: Use crash_prepare_headers() helper to simplify code
>   LoongArch: kexec_file: Use crash_prepare_headers() helper to simplify
>     code
>   powerpc/kexec_file: Use crash_exclude_core_ranges() helper
>   arm64: kexec_file: Add support for crashkernel CMA reservation
>   riscv: kexec_file: Add support for crashkernel CMA reservation
>   arm64: crash: Add crash hotplug support
> 
> Sourabh Jain (1):
>   powerpc/crash: sort crash memory ranges before preparing elfcorehdr
> 
>  .../admin-guide/kernel-parameters.txt         |  16 +-
>  arch/arm64/Kconfig                            |   3 +
>  arch/arm64/include/asm/kexec.h                |  13 ++
>  arch/arm64/kernel/Makefile                    |   2 +-
>  arch/arm64/kernel/crash.c                     | 152 ++++++++++++++++++
>  arch/arm64/kernel/kexec_image.c               |  34 ++++
>  arch/arm64/kernel/machine_kexec_file.c        |  78 ++-------
>  arch/arm64/mm/init.c                          |   5 +-
>  arch/loongarch/kernel/machine_kexec_file.c    |  44 ++---
>  arch/powerpc/include/asm/kexec_ranges.h       |   1 -
>  arch/powerpc/kexec/crash.c                    |   7 +-
>  arch/powerpc/kexec/file_load_64.c             |   3 +
>  arch/powerpc/kexec/ranges.c                   | 113 ++-----------
>  arch/riscv/kernel/machine_kexec_file.c        |  43 ++---
>  arch/riscv/mm/init.c                          |   5 +-
>  arch/x86/kernel/crash.c                       |  92 ++---------
>  drivers/of/fdt.c                              |   9 +-
>  drivers/of/kexec.c                            |   9 ++
>  include/linux/crash_core.h                    |  15 ++
>  include/linux/crash_reserve.h                 |   4 +-
>  include/linux/kexec.h                         |   2 +
>  kernel/crash_core.c                           |  89 +++++++++-
>  kernel/crash_dump_dm_crypt.c                  |   4 +-
>  kernel/kexec_core.c                           |  25 +--
>  24 files changed, 430 insertions(+), 338 deletions(-)
>  create mode 100644 arch/arm64/kernel/crash.c
> 
> -- 
> 2.34.1
> 


From elder at riscstar.com  Mon Jun  1 06:48:55 2026
From: elder at riscstar.com (Alex Elder)
Date: Mon, 1 Jun 2026 08:48:55 -0500
Subject: [PATCH] MAINTAINERS: add entry for SpacemiT reset controller
 driver
In-Reply-To: <20260601-b4-spacemit-reset-maintainers-v1-1-1ab3014e9a35@gmail.com>
References: <20260601-b4-spacemit-reset-maintainers-v1-1-1ab3014e9a35@gmail.com>
Message-ID: <ec6b44cc-ae24-4497-aeb5-8465c20e4b74@riscstar.com>

On 6/1/26 8:35 PM, Guodong Xu wrote:
> The SpacemiT reset controller driver under drivers/reset/spacemit/
> (common code plus the K1 and K3 SoC instances) and its reset-ID header
> have no dedicated MAINTAINERS entry; today they fall only under the
> broad drivers/reset/ entry of the reset subsystem and the N:/K:
> catch-all of the RISC-V SpacemiT SoC umbrella.
> 
> Add a dedicated entry and list myself as maintainer. I introduced the
> drivers/reset/spacemit/ subdirectory, moved and refactored the existing
> K1 reset support (originally written by Alex Elder) into it, and wrote
> the K3 reset driver. The series that created this directory and these
> files is archived at [1].
> 
> [1] https://lore.kernel.org/spacemit/20260120-k3-reset-v3-0-effe87f4bdbe at riscstar.com/
> 
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>

Looks good to me Guodong.

Acked-by: Alex Elder <elder at riscstar.com>

> ---
> I contributed this driver as Guodong Xu <guodong at riscstar.com>;
> docular.xu at gmail.com is my current address. A matching .mailmap update
> has been submitted at
> https://lore.kernel.org/all/20260601-b4-mailmap-guodong-xu-v1-1-ee9eff1e57ba at gmail.com/
> ---
>   MAINTAINERS | 7 +++++++
>   1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9ec290e38b44a..c9d87244c1715 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25119,6 +25119,13 @@ S:	Maintained
>   F:	Documentation/devicetree/bindings/i2c/spacemit,k1-i2c.yaml
>   F:	drivers/i2c/busses/i2c-k1.c
>   
> +SPACEMIT RESET CONTROLLER DRIVER
> +M:	Guodong Xu <docular.xu at gmail.com>
> +L:	linux-riscv at lists.infradead.org
> +S:	Maintained
> +F:	drivers/reset/spacemit/
> +F:	include/dt-bindings/reset/spacemit,k3-resets.h
> +
>   SPANISH DOCUMENTATION
>   M:	Carlos Bilbao <carlos.bilbao at kernel.org>
>   R:	Avadhut Naik <avadhut.naik at amd.com>
> 
> ---
> base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
> change-id: 20260601-b4-spacemit-reset-maintainers-4b5a91599585
> 
> Best regards,
> --
> Guodong Xu <docular.xu at gmail.com>
> 



From rostedt at goodmis.org  Mon Jun  1 06:57:46 2026
From: rostedt at goodmis.org (Steven Rostedt)
Date: Mon, 1 Jun 2026 09:57:46 -0400
Subject: [PATCH v2 1/8] scripts/sorttable: Handle RISC-V patchable
 ftrace entries
In-Reply-To: <0a913398-3d0c-472e-89c4-062052eae04d@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
	<20260528082310.1994388-2-wanghan@linux.alibaba.com>
	<0a913398-3d0c-472e-89c4-062052eae04d@linux.alibaba.com>
Message-ID: <20260601095746.70c01d24@fedora>

On Mon, 1 Jun 2026 14:17:08 +0800
Shuai Xue <xueshuai at linux.alibaba.com> wrote:

> > diff --git a/scripts/sorttable.c b/scripts/sorttable.c
> > index e8ed11c680c6..4c10e85bb5af 100644
> > --- a/scripts/sorttable.c
> > +++ b/scripts/sorttable.c
> > @@ -891,17 +891,21 @@ static int do_file(char const *const fname, void *addr)
> >   	table_sort_t custom_sort = NULL;
> >   
> >   	switch (elf_map_machine(ehdr)) {
> > -	case EM_AARCH64:
> >   #ifdef MCOUNT_SORT_ENABLED
> > +	case EM_AARCH64:
> >   		sort_reloc = true;
> >   		rela_type = 0x403;
> > -		/* arm64 uses patchable function entry placing before function */
> > +		/* fallthrough */
> > +	case EM_RISCV:
> > +		/* arm64 and RISC-V place patchable entries before the function */
> >   		before_func = 8;  
> 
> Nit: The shared comment now sits under `case EM_RISCV:` but the two
> lines above it (sort_reloc / rela_type = 0x403) are strictly
> arm64-only ? they configure the RELA-based weak-function fixup that
> RISC-V does not need. On a quick read it is easy to wonder if RISC-V
> is implicitly inheriting that path. Splitting the comments would
> help, e.g.:
> 
>         case EM_AARCH64:
>             /* arm64 needs RELA-based weak-function fixup */
>             sort_reloc = true;
>             rela_type = 0x403;
>             /* fallthrough */
>         case EM_RISCV:
>             /* arm64 and RISC-V place patchable entries before the function */
>             before_func = 8;

Makes sense.

Care to send a v3?

-- Steve


From docular.xu at gmail.com  Mon Jun  1 19:11:50 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Mon,  1 Jun 2026 22:11:50 -0400
Subject: [PATCH v2 03/10] riscv: Standardize extension capitalization
In-Reply-To: <CAAhSdy0pHPAMRRR-Mri735zLu3ymr=ePQ7gA6zZ11BkHEXj+AA@mail.gmail.com>
References: <20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc@riscstar.com> <20260511-rva23u64-hwprobe-v2-v2-3-21c5a544f1dc@riscstar.com> <CAAhSdy0pHPAMRRR-Mri735zLu3ymr=ePQ7gA6zZ11BkHEXj+AA@mail.gmail.com>
Message-ID: <20260602021638.158707-1-docular.xu@gmail.com>

Hi Anup,

> Acked-by: Anup Patel <anup at brainfault.org>
> Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks for the review.

> @Paul, This patch is independent of other changes
> in this series. If you are okay then I can take this single
> patch through KVM RISC-V tree.

There is a dependency ordering I should point out. Patch 08
("riscv: cpufeature: Introduce ISA bases bitmap and rva23u64 detection")
uses the upper-case RISCV_ISA_EXT_I/M/A... macros introduced in this patch,
so it won't build without patch 03. I mean, if patch 03 goes into a
different tree on its own.

But of course, I can rebase them onto your tree if patch 03 lands earlier
than the other patches.

Either way should be fine with me, your call.

Thanks,
Guodong Xu
docular.xu at gmail.com


From debug at rivosinc.com  Mon Jun  1 09:22:17 2026
From: debug at rivosinc.com (Deepak Gupta)
Date: Mon, 1 Jun 2026 09:22:17 -0700
Subject: [PATCH v23 06/28] riscv/mm : ensure PROT_WRITE leads to VM_READ | VM_WRITE
In-Reply-To: <875x44o9hj.fsf@igel.home>
References: <20251112-v5_user_cfi_series-v23-0-b55691eacf4f@rivosinc.com>
 <20251112-v5_user_cfi_series-v23-6-b55691eacf4f@rivosinc.com>
 <87jyslndo4.fsf@igel.home> <CAKC1njS=AHu6uHrH4ae8VxcdEbhgiPXYCAoN3F_mnppBd3SwOA@mail.gmail.com>
 <875x44o9hj.fsf@igel.home>
Message-ID: <CAKC1njSn_rtCj8ii876PNQTk0nsCTfWsb4DzdymufHVthh1Rkg@mail.gmail.com>

On Sat, May 30, 2026 at 2:47?PM Andreas Schwab <schwab at linux-m68k.org> wrote:
>
> On Mai 30 2026, Deepak Gupta wrote:
>
> > I see two ways forward:
> >
> > - It can be done in generic way where incoming PROT_WRITE means
> >   PROT_READ | PROT_WRITE irrespective of RISC-V. Although others
> >   (x86, arm, etc) would have to weigh in.
> >
> > OR
> >
> > - mmap04 LTP test can be updated to expect either of "rw-p" or "-w-p"
> >   whenever only PROT_WRITE was specified.
>
> OR
>
> - Add a new PROT_ flag.

This was settled when x86 introduced shadow stack. Instead of having
new `PROT_`, it was agreed to create a new syscall for mapping shadow
stack memory (syscall: `map_shadow_stack`). Scenarios like `clone3` or
co-routines required manufacturing a shadow stack, thus necessitating a
new mechanism to create shadow stack style memory in demand. Instead
of having a new PROT_ flag,  a new syscall was created.

>
> --
> Andreas Schwab, schwab at linux-m68k.org
> GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
> "And now for something completely different."


From schwab at linux-m68k.org  Mon Jun  1 10:10:36 2026
From: schwab at linux-m68k.org (Andreas Schwab)
Date: Mon, 01 Jun 2026 19:10:36 +0200
Subject: [PATCH v23 06/28] riscv/mm : ensure PROT_WRITE leads to VM_READ
 | VM_WRITE
In-Reply-To: <CAKC1njSn_rtCj8ii876PNQTk0nsCTfWsb4DzdymufHVthh1Rkg@mail.gmail.com>
	(Deepak Gupta's message of "Mon, 1 Jun 2026 09:22:17 -0700")
References: <20251112-v5_user_cfi_series-v23-0-b55691eacf4f@rivosinc.com>
	<20251112-v5_user_cfi_series-v23-6-b55691eacf4f@rivosinc.com>
	<87jyslndo4.fsf@igel.home>
	<CAKC1njS=AHu6uHrH4ae8VxcdEbhgiPXYCAoN3F_mnppBd3SwOA@mail.gmail.com>
	<875x44o9hj.fsf@igel.home>
	<CAKC1njSn_rtCj8ii876PNQTk0nsCTfWsb4DzdymufHVthh1Rkg@mail.gmail.com>
Message-ID: <871peqgp9v.fsf@igel.home>

On Jun 01 2026, Deepak Gupta wrote:

> This was settled when x86 introduced shadow stack. Instead of having
> new `PROT_`, it was agreed to create a new syscall for mapping shadow
> stack memory (syscall: `map_shadow_stack`). Scenarios like `clone3` or
> co-routines required manufacturing a shadow stack, thus necessitating a
> new mechanism to create shadow stack style memory in demand. Instead
> of having a new PROT_ flag,  a new syscall was created.

So what prevents riscv from making use of VM_SHADOW_STACK similar as
x86, without the user visible effects?

-- 
Andreas Schwab, schwab at linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."


From debug at rivosinc.com  Mon Jun  1 10:57:41 2026
From: debug at rivosinc.com (Deepak Gupta)
Date: Mon, 1 Jun 2026 10:57:41 -0700
Subject: [PATCH v23 06/28] riscv/mm : ensure PROT_WRITE leads to VM_READ | VM_WRITE
In-Reply-To: <871peqgp9v.fsf@igel.home>
References: <20251112-v5_user_cfi_series-v23-0-b55691eacf4f@rivosinc.com>
 <20251112-v5_user_cfi_series-v23-6-b55691eacf4f@rivosinc.com>
 <87jyslndo4.fsf@igel.home> <CAKC1njS=AHu6uHrH4ae8VxcdEbhgiPXYCAoN3F_mnppBd3SwOA@mail.gmail.com>
 <875x44o9hj.fsf@igel.home> <CAKC1njSn_rtCj8ii876PNQTk0nsCTfWsb4DzdymufHVthh1Rkg@mail.gmail.com>
 <871peqgp9v.fsf@igel.home>
Message-ID: <CAKC1njR+dTdvp+BmLGPtgd8dufiUwBtkQ9a-qinELT_Fmi13sQ@mail.gmail.com>

On Mon, Jun 1, 2026 at 10:10?AM Andreas Schwab <schwab at linux-m68k.org> wrote:
>
> On Jun 01 2026, Deepak Gupta wrote:
>
> > This was settled when x86 introduced shadow stack. Instead of having
> > new `PROT_`, it was agreed to create a new syscall for mapping shadow
> > stack memory (syscall: `map_shadow_stack`). Scenarios like `clone3` or
> > co-routines required manufacturing a shadow stack, thus necessitating a
> > new mechanism to create shadow stack style memory in demand. Instead
> > of having a new PROT_ flag,  a new syscall was created.
>
> So what prevents riscv from making use of VM_SHADOW_STACK similar as
> x86, without the user visible effects?

riscv uses `VM_SHADOW_STACK`. It's just very simple to use `protection_map`
with just `VM_WRITE`. On RISC-V, `-W-` is a shadow stack mapping. It's not same
on x86 or arm64. So `protection_map[VM_WRITE]` simply picks shadow stack
encoding. We just ensure that PROT_WRITE is converted to
"VM_READ | VM_WRITE" at vma level.

see commit message

"""
Earlier `protection_map[VM_WRITE]` used to pick read-write PTE encodings.
Now `protection_map[VM_WRITE]` will always pick PAGE_SHADOWSTACK PTE
encodings for shadow stack. Above changes ensure that existing apps
continue to work because underneath kernel will be picking
`protection_map[VM_WRITE|VM_READ]` PTE encodings.
"""

As I said other arches have a VMA flag for shadow stack range but PTE encodings
and overlays are complicated.

>
> --
> Andreas Schwab, schwab at linux-m68k.org
> GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
> "And now for something completely different."


From fustini at kernel.org  Mon Jun  1 13:35:55 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:35:55 -0700
Subject: [PATCH RFC v6 01/18] dt-bindings: riscv: Add Ssqosid extension
 description
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-1-baf00f50028a@kernel.org>

Document the ratified Supervisor-mode Quality of Service ID (Ssqosid)
extension v1.0.

Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 Documentation/devicetree/bindings/riscv/extensions.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb21..1c6f091518d4 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -232,6 +232,12 @@ properties:
             ratified at commit d70011dde6c2 ("Update to ratified state")
             of riscv-j-extension.
 
+        - const: ssqosid
+          description: |
+            The standard Ssqosid extension for Quality of Service ID is
+            ratified as v1.0 in commit d9c616497fde ("Merge pull
+            request #7 from ved-rivos/Ratified") of riscv-ssqosid.
+
         - const: ssstateen
           description: |
             The standard Ssstateen extension for supervisor-mode view of the

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:35:54 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:35:54 -0700
Subject: [PATCH RFC v6 00/18] riscv: add Ssqosid and CBQRI resctrl support
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>

This RFC series adds RISC-V QoS support: the Ssqosid extension [1]
(srmcfg CSR), the CBQRI controller interface [2] integrated with
resctrl [3], and ACPI RQSC [4] for controller discovery. DT support
is possible but no platform drivers are included. The series is
also available as a branch [5].

QEMU support for Ssqosid and CBQRI lives in [6], with ACPI RQSC as
a follow-on series [7]. There is also a combined branch [8].

Series organization
-------------------
01      DT binding for Ssqosid extension
02-03   Ssqosid ISA support (detection, srmcfg CSR, switch_to)
04-06   fs/resctrl helpers and resource type additions
07-10   CBQRI device ops (cbqri_devices.c): capacity probe +
        allocation, capacity monitoring, bandwidth probe +
        allocation, bandwidth monitoring
11-15   CBQRI resctrl integration (cbqri_resctrl.c): cache
        allocation, L3 cache occupancy monitoring, MB_MIN
        bandwidth allocation, MB_WGHT bandwidth allocation,
        mbm_total_bytes monitoring
16-17   ACPI RQSC parser and init
18      Enable resctrl filesystem for Ssqosid (Kconfig)

Refer to the v3 cover letter [9] for the test setup including the
reference SoC layout and the corresponding QEMU command line.

[1] https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
[2] https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
[3] https://docs.kernel.org/filesystems/resctrl.html
[4] https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
[5] https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git/log/?h=b4/ssqosid-cbqri-rqsc
[6] https://lore.kernel.org/qemu-devel/20260105-riscv-ssqosid-cbqri-v4-0-9ad7671dde78 at kernel.org/
[7] https://lore.kernel.org/qemu-devel/20260202-riscv-rqsc-v1-0-dcf448a3ed73 at kernel.org/
[8] https://github.com/tt-fustini/qemu/tree/b4/riscv-rqsc
[9] https://lore.kernel.org/r/20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a at kernel.org

Key design decisions
--------------------
 - Create new resource types as RDT_RESOURCE_MBA cannot represent the
   semantics of the CBQRI bandwidth controllers:

   - RDT_RESOURCE_MB_MIN matches CBQRI Rbwb (reserved bandwidth
     blocks). The sum of Rbwb across all control groups must be
     <= MRBWB (maximum number of reserved bandwidth blocks).

   - RDT_RESOURCE_MB_WGHT matches CBQRI Mweight, the weighted share of
     the remaining bandwidth blocks. Values are in [0, 255]: 0 disables
     work-conserving sharing for the group, 1..255 compete for the
     leftover pool.

 - mbm_total_bytes is supported only when the platform exposes exactly
   one mon-capable bandwidth controller and exactly one L3 domain.
   Pairing a single BC across multiple L3 domains would let standard
   userspace tools overcount system bandwidth by summing the same
   counter across domains.

Open issues
-----------
 - RDT_RESOURCE_MB_MIN and RDT_RESOURCE_MB_WGHT are intended to drive
   discussion, not as the final solution. Reinette has recently posted
   a generic schema proof of concept. I will based the next revision on
   that.

 - resctrl monitoring scope limitations:
   - monitor-only L3 capacity controllers are not supported.
   - CBQRI capacity controllers can monitor any cache level, but resctrl
     only supports occupancy on L3.
   - resctrl needs to gain a non-CPU scope level for mbm_total_bytes
     to be supported on platforms with multiple bandwidth controllers
     or multiple L3 domains.

 - When a control group is freed, rbwb_cache[closid] is not reset,
   so the MB_MIN sum check can count the stale reservation against
   MRBWB. Fixing this requires a new resctrl_arch_* callback in
   fs/resctrl invoked on group destroy, which is out of scope for
   this arch-driver series.

 - cc_cunits is not supported. cc_block_mask maps well onto resctrl's
   existing CBM schema, but there is no existing equivalent for
   capacity units.

 - RQSC structs live in drivers/acpi/riscv/rqsc.h until the spec is
   ratified and the ACPICA upstream submission lands. They will then move
   to include/acpi/actbl2.h. The spec is in the final phase
   before ratification.

Changes in v6:
--------------
The changes in this revision are based on the feedback in the Sashiko
review of v5 and Sunil V L's review of the RQSC parser.

riscv_cbqri device: 
 - Widen the remaining CBQRI_CONTROL_REGISTERS_OP/AT/RCID and the RBWB /
   MWEIGHT field masks to GENMASK_ULL, so FIELD_MODIFY and ~mask on a
   u64 register stay correct if RV32 support is ever added.
 - Reject an rcid_count or mcid_count larger than 12-bits can encode.
 - Probe monitoring with CONFIG_EVENT and a probe-safe event id rather
   than READ_COUNTER. Run the AT probe only for allocation registers
 - cbqri_bc_alloc_op() clears AT, matching the capacity path.
 - cbqri_apply_bc_field() waits for BUSY=0 before staging the new value
   so an in-flight op cannot consume a half-updated register.
 - cbqri_read_rbwb() and cbqri_read_mweight() stage a sentinel in the
   unread field, so a silent READ_LIMIT no-op is detected instead of
   returning stale data.

resctrl:
 - cbqri_resctrl_online_cpu() and cbqri_resctrl_offline_cpu() seed the
   per-CPU default RCID/MCID.
 - Partial attach failure detaches the CPU from every domain it reached.
 - resctrl_arch_reset_rmid() no longer re-arms occupancy. Occupancy
   counters are armed once and run free.
 - The BC is paired and initialized only when mbm_total_bytes is enabled,
   so a controller left unpicked on a system with multiple L3 domains
   is not allocated and no longer clamps the occupancy rmid space.
 - num_rmid is reported as the system-wide minimum mcid_count.

ACPI:
 - Skip controllers whose RCID Count and MCID Count are both zero, as
   RQSC requires at least one to be non-zero.
 - Add the Memory-Side Cache, ACPI device and PCI device resource id
   type constants.

Sashiko review:
https://sashiko.dev/#/patchset/20260524-ssqosid-cbqri-rqsc-v7-0-v5-0-78d3a7ba9dbe%40kernel.org

Link to v5:
https://lore.kernel.org/all/20260524-ssqosid-cbqri-rqsc-v7-0-v5-0-78d3a7ba9dbe at kernel.org/

Changes in v5:
--------------
The changes in this revision are based on the feedback in the Sashiko
review of the series.

Ssqosid:
 - Seed cpu_srmcfg to U32_MAX in DEFINE_PER_CPU so early-boot context
   switches always write the CSR rather than matching a zero-initialised
   cache before riscv_srmcfg_init() runs.
 - __switch_to_srmcfg() evaluates RCID and MCID against
   cpu_srmcfg_default independently. A task in the default RCID group
   with a specific MCID previously bypassed the CPU default.
 - Register a CPU PM notifier that invalidates cpu_srmcfg on
   CPU_PM_EXIT / CPU_PM_ENTER_FAILED so resume-from-suspend on the boot
   CPU writes the CSR.
 - Drop the for_each_online_cpu pre-seed loop in riscv_srmcfg_init().
   cpuhp_setup_state() already covers already-online CPUs.

CBQRI:
 - Add mweight_cache. cbqri_apply_bc_field() seeds both fields of
   bc_bw_alloc from the software caches, so that stale data can not leak
   into the unmodified field.
 - Seed mweight_cache to FIELD_MAX(MWEIGHT_MASK) at probe so the first
   MB_MIN domain init does not commit Mweight=0 to every RCID. A weight
   of 0 is a hard cap on opportunistic bandwidth, which would starve
   every RCID until the subsequent MB_WGHT domain init catches up.
 - cbqri_apply_mweight_config() rejects mweight > WEIGHT_MASK at entry
   rather than letting it truncate and trigger a verify mismatch.
 - cbqri_apply_bc_field() updates per-RCID cache only after verifying.
 - cbqri_controller_destroy() now iounmaps and releases the mem region
   from rollback paths, gated on ctrl->base.
 - cbqri_probe_feature() clears OP, AT, RCID and EVT_ID on every write,
   so the probe never writes stale bits into the register.
 - cbqri_apply_cache_config() clears cc_block_mask before the initial
   READ_LIMIT that captures saved_cbm.
 - Drop the ctrl->faulted early return from controller ops.
 - Reject a second bandwidth controller when sharing a proximity domain.
 - Rejects ctrl->rcid_count > SRMCFG_RCID_MASK so the schedule-in
   fast path cannot silently truncate the RCID.
 - Widen CBQRI_MON_CTL_OP/MCID/EVT_ID masks to GENMASK_ULL so
   FIELD_MODIFY on a u64 register stays safe if RV32 support is added.

resctrl:
 - Switch the L3 mon_domain teardown paths from cancel_delayed_work_sync
   to cancel_delayed_work to avoid potential deadlock.
 - Guard the mbm_over cancel on QOS_L3_MBM_TOTAL_EVENT_ID, so a system
   without a paired BC does not cancel a zeroed work struct.
 - cbqri_attach_cpu_to_cap_ctrl() rolls back cpumask_set_cpu and any
   freshly created ctrl_domain when cbqri_attach_cpu_to_l3_mon() fails.
 - Restrict mbm_total_bytes to platforms with exactly one L3 domain.
 - Pair the L3 mon domain with its BC and initialise the BC's
   per-MCID accumulators before resctrl_online_mon_domain() exposes
   the domain, so a concurrent mbm_total_bytes read cannot race with
   paired_bc init.
 - Hold cbqri_domain_list_lock across the MMIO paths in
   resctrl_arch_rmid_read() and resctrl_arch_reset_rmid() so a
   concurrent CPU hotplug detach cannot free hw_dom mid-read.
 - cbqri_resctrl_setup() rolls back exposed_alloc_capable /
   exposed_mon_capable on resctrl_init() failure so
   resctrl_arch_*_capable() does not report stale state to callers.
 - Drop the cacheinfo_ready wait queue in cbqri_resctrl_setup() and
   the RCU annotations on the ctrl_domain list. cacheinfo runs at
   device_initcall_sync, strictly before late_initcall, and the list
   is mutated only from cpuhp callbacks under cbqri_domain_list_lock.

Kconfig:
 - RISCV_ISA_SSQOSID selects RISCV_CBQRI_DRIVER unconditionally. resctrl
   is gated separately by the silent RISCV_CBQRI_RESCTRL_FS option. 

ACPI:
 - acpi_parse_rqsc() rejects tables with the wrong header.revision,
   validates res0->type and res0->id_type, and checks that node->length
   does not overrun the table end.

Sashiko review:
https://sashiko.dev/#/patchset/20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683%40kernel.org

Link to v4:
https://lore.kernel.org/all/20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683 at kernel.org/

Changes in v4:
--------------
resctrl:
 - Add RDT_RESOURCE_MB_MIN and RDT_RESOURCE_MB_WGHT
 - Add default_to_min to resctrl_membw so MB_MIN defaults to min_bw
 - Add L3 cache occupancy monitoring for L3-scoped capacity controllers
 - Add mbm_total_bytes bandwidth monitoring when there is a single
   bandwidth controller
 - Move domain creation into cpuhp callbacks so that cpu_mask reflects
   only online CPUs
 - resctrl_arch_reset_rmid() returns early when called with IRQs
   disabled.

CBQRI:
 - Replace per-controller spinlock with mutex. Each CBQRI op is a
   write-then-poll-busy cycle of up to 1 ms. A sleeping mutex paired
   with readq_poll_timeout() keeps preemption enabled across the
   busy-wait. All resctrl-arch entry points run in process context.
 - Replace struct cbqri_config with direct params in helper functions.
 - max_rmid = min(max_rmid, ctrl->mcid_count) now gated on
   ctrl->mon_capable.
 - Validate that the sum of Rbwb does not exceed MRBWB.
 - Move CDP enable state from file-scope globals to per-resource
   cdp_enabled / cdp_capable.
 - Configure both AT_CODE and AT_DATA limits when CDP is supported but
   not enabled.

Ssqosid:
 - __switch_to_srmcfg() emits RISCV_FENCE(rw, o) before and (o, rw)
   after csrw to drain old-task stores and order new-task loads.
 - Invalidate per-cpu cpu_srmcfg on hart online via CPUHP_AP_ONLINE_DYN.
   Also seed already-online CPUs synchronously at init.

ACPI:
 - Drop the PPTT helper patch and resolve cache_size via cacheinfo at
   cbqri_resctrl_setup() time.
 - ACPI driver now calls riscv_cbqri_register_controller() and the
   cbqri_controller internals stay in cbqri_internal.h.

Refer to v3 for previous change logs:
https://lore.kernel.org/r/20260414-ssqosid-cbqri-rqsc-v7-0-v3-0-b3b2e7e9847a at kernel.org

---
Drew Fustini (18):
      dt-bindings: riscv: Add Ssqosid extension description
      riscv: detect the Ssqosid extension
      riscv: add support for srmcfg CSR from Ssqosid extension
      fs/resctrl: Add resctrl_is_membw() helper
      fs/resctrl: Add RDT_RESOURCE_MB_MIN and RDT_RESOURCE_MB_WGHT
      fs/resctrl: Let bandwidth resources default to min_bw at reset
      riscv_cbqri: Add capacity controller probe and allocation device ops
      riscv_cbqri: Add capacity controller monitoring device ops
      riscv_cbqri: Add bandwidth controller probe and allocation device ops
      riscv_cbqri: Add bandwidth controller monitoring device ops
      riscv_cbqri: resctrl: Add cache allocation via capacity block mask
      riscv_cbqri: resctrl: Add L3 cache occupancy monitoring
      riscv_cbqri: resctrl: Add MB_MIN bandwidth allocation via Rbwb
      riscv_cbqri: resctrl: Add MB_WGHT bandwidth allocation via Mweight
      riscv_cbqri: resctrl: Add mbm_total_bytes bandwidth monitoring
      ACPI: RISC-V: Parse RISC-V Quality of Service Controller (RQSC) table
      ACPI: RISC-V: Add support for RISC-V Quality of Service Controller (RQSC)
      riscv: enable resctrl filesystem for Ssqosid

 .../devicetree/bindings/riscv/extensions.yaml      |    6 +
 MAINTAINERS                                        |   15 +
 arch/riscv/Kconfig                                 |   20 +
 arch/riscv/include/asm/acpi.h                      |   10 +
 arch/riscv/include/asm/csr.h                       |    5 +
 arch/riscv/include/asm/hwcap.h                     |    1 +
 arch/riscv/include/asm/processor.h                 |    3 +
 arch/riscv/include/asm/qos.h                       |   87 ++
 arch/riscv/include/asm/resctrl.h                   |  152 ++
 arch/riscv/include/asm/switch_to.h                 |    3 +
 arch/riscv/kernel/Makefile                         |    2 +
 arch/riscv/kernel/cpufeature.c                     |    1 +
 arch/riscv/kernel/qos.c                            |   98 ++
 drivers/acpi/riscv/Makefile                        |    1 +
 drivers/acpi/riscv/init.c                          |   21 +
 drivers/acpi/riscv/rqsc.c                          |  202 +++
 drivers/acpi/riscv/rqsc.h                          |   66 +
 drivers/resctrl/Kconfig                            |   32 +
 drivers/resctrl/Makefile                           |    6 +
 drivers/resctrl/cbqri_devices.c                    | 1154 +++++++++++++++
 drivers/resctrl/cbqri_internal.h                   |  247 ++++
 drivers/resctrl/cbqri_resctrl.c                    | 1520 ++++++++++++++++++++
 fs/resctrl/ctrlmondata.c                           |    3 +-
 fs/resctrl/internal.h                              |    2 +
 fs/resctrl/rdtgroup.c                              |   16 +-
 include/linux/resctrl.h                            |   13 +-
 include/linux/riscv_cbqri.h                        |   60 +
 27 files changed, 3737 insertions(+), 9 deletions(-)
---
base-commit: 5200f5f493f79f14bbdc349e402a40dfb32f23c8
change-id: 20260329-ssqosid-cbqri-rqsc-v7-0-b0c788bab48a

Best regards,
--  
Drew Fustini <fustini at kernel.org>



From fustini at kernel.org  Mon Jun  1 13:35:57 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:35:57 -0700
Subject: [PATCH RFC v6 03/18] riscv: add support for srmcfg CSR from
 Ssqosid extension
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-3-baf00f50028a@kernel.org>

Add support for the srmcfg CSR defined in the Ssqosid ISA extension.
The CSR contains two fields:

  - Resource Control ID (RCID) for resource allocation
  - Monitoring Counter ID (MCID) for tracking resource usage

Requests from a hart to shared resources are tagged with these IDs,
allowing resource usage to be associated with the running task.

Add a srmcfg field to thread_struct with the same format as the CSR so
the scheduler can set the RCID and MCID for each task on context
switch. A per-cpu cpu_srmcfg variable mirrors the CSR state to avoid
redundant writes. L1D-hot memory access is faster than a CSR read and
avoids traps under virtualization.

A per-cpu cpu_srmcfg_default holds the default srmcfg for each CPU as
set by resctrl CPU group assignment. On context switch, RCID and MCID
inherit from the CPU default independently: a task whose thread RCID
field is zero takes the CPU default's RCID, and likewise for MCID.

Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Kornel Dul?ba <mindal at semihalf.com>
Signed-off-by: Kornel Dul?ba <mindal at semihalf.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 MAINTAINERS                        |  8 ++++
 arch/riscv/Kconfig                 | 18 +++++++
 arch/riscv/include/asm/csr.h       |  5 ++
 arch/riscv/include/asm/processor.h |  3 ++
 arch/riscv/include/asm/qos.h       | 87 +++++++++++++++++++++++++++++++++
 arch/riscv/include/asm/switch_to.h |  3 ++
 arch/riscv/kernel/Makefile         |  2 +
 arch/riscv/kernel/qos.c            | 98 ++++++++++++++++++++++++++++++++++++++
 8 files changed, 224 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c2c6d79275c6..e694fb2a22d2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23017,6 +23017,14 @@ F:	drivers/perf/riscv_pmu.c
 F:	drivers/perf/riscv_pmu_legacy.c
 F:	drivers/perf/riscv_pmu_sbi.c
 
+RISC-V QOS RESCTRL SUPPORT
+M:	Drew Fustini <fustini at kernel.org>
+R:	yunhui cui <cuiyunhui at bytedance.com>
+L:	linux-riscv at lists.infradead.org
+S:	Supported
+F:	arch/riscv/include/asm/qos.h
+F:	arch/riscv/kernel/qos.c
+
 RISC-V RPMI AND MPXY DRIVERS
 M:	Rahul Pathak <rahul at summations.net>
 M:	Anup Patel <anup at brainfault.org>
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index c5754942cf85..6abbb21f3a0d 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -591,6 +591,24 @@ config RISCV_ISA_SVNAPOT
 
 	  If you don't know what to do here, say Y.
 
+config RISCV_ISA_SSQOSID
+	bool "Ssqosid extension support for supervisor mode Quality of Service ID"
+	depends on 64BIT
+	default n
+	help
+	  Adds support for the Ssqosid ISA extension (Supervisor-mode
+	  Quality of Service ID).
+
+	  Ssqosid defines the srmcfg CSR which allows the system to tag the
+	  running process with an RCID (Resource Control ID) and MCID
+	  (Monitoring Counter ID). The RCID is used to determine resource
+	  allocation. The MCID is used to track resource usage in event
+	  counters.
+
+	  For example, a cache controller may use the RCID to apply a
+	  cache partitioning scheme and use the MCID to track how much
+	  cache a process, or a group of processes, is using.
+
 config RISCV_ISA_SVPBMT
 	bool "Svpbmt extension support for supervisor mode page-based memory types"
 	depends on 64BIT && MMU
diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 31b8988f4488..7bce928e5daa 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -84,6 +84,10 @@
 #define SATP_ASID_MASK	_AC(0xFFFF, UL)
 #endif
 
+/* SRMCFG fields */
+#define SRMCFG_RCID_MASK	GENMASK(11, 0)
+#define SRMCFG_MCID_MASK	GENMASK(27, 16)
+
 /* Exception cause high bit - is an interrupt if set */
 #define CAUSE_IRQ_FLAG		(_AC(1, UL) << (__riscv_xlen - 1))
 
@@ -328,6 +332,7 @@
 #define CSR_STVAL		0x143
 #define CSR_SIP			0x144
 #define CSR_SATP		0x180
+#define CSR_SRMCFG		0x181
 
 #define CSR_STIMECMP		0x14D
 #define CSR_STIMECMPH		0x15D
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 812517b2cec1..49a386d74cd3 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -123,6 +123,9 @@ struct thread_struct {
 	/* A forced icache flush is not needed if migrating to the previous cpu. */
 	unsigned int prev_cpu;
 #endif
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+	u32 srmcfg;
+#endif
 };
 
 /* Whitelist the fstate from the task_struct for hardened usercopy */
diff --git a/arch/riscv/include/asm/qos.h b/arch/riscv/include/asm/qos.h
new file mode 100644
index 000000000000..727d438454f3
--- /dev/null
+++ b/arch/riscv/include/asm/qos.h
@@ -0,0 +1,87 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_RISCV_QOS_H
+#define _ASM_RISCV_QOS_H
+
+#include <linux/percpu-defs.h>
+
+#ifdef CONFIG_RISCV_ISA_SSQOSID
+
+#include <linux/bitfield.h>
+#include <linux/cpufeature.h>
+#include <linux/sched.h>
+
+#include <asm/csr.h>
+#include <asm/fence.h>
+#include <asm/hwcap.h>
+
+/* cached value of srmcfg csr for each cpu */
+DECLARE_PER_CPU(u32, cpu_srmcfg);
+
+/* default srmcfg value for each cpu, set via resctrl cpu assignment */
+DECLARE_PER_CPU(u32, cpu_srmcfg_default);
+
+static inline void __switch_to_srmcfg(struct task_struct *next)
+{
+	u32 thread_srmcfg, default_srmcfg;
+
+	thread_srmcfg = READ_ONCE(next->thread.srmcfg);
+	default_srmcfg = __this_cpu_read(cpu_srmcfg_default);
+
+	/*
+	 * RCID and MCID inherit from cpu_srmcfg_default independently.
+	 * RESCTRL_RESERVED_CLOSID and RESCTRL_RESERVED_RMID are both 0,
+	 * so a per-field zero means "no task assignment for this
+	 * dimension" and the CPU default supplies that field. Matches
+	 * x86 RDT's __resctrl_sched_in() per-field logic. The fully
+	 * unassigned (thread.srmcfg == 0) and fully assigned (both
+	 * fields non-zero) cases short-circuit the field math.
+	 */
+	if (thread_srmcfg == 0) {
+		thread_srmcfg = default_srmcfg;
+	} else {
+		u32 rcid = FIELD_GET(SRMCFG_RCID_MASK, thread_srmcfg);
+		u32 mcid = FIELD_GET(SRMCFG_MCID_MASK, thread_srmcfg);
+
+		if (rcid == 0 || mcid == 0) {
+			if (rcid == 0)
+				rcid = FIELD_GET(SRMCFG_RCID_MASK, default_srmcfg);
+			if (mcid == 0)
+				mcid = FIELD_GET(SRMCFG_MCID_MASK, default_srmcfg);
+			thread_srmcfg = FIELD_PREP(SRMCFG_RCID_MASK, rcid) |
+					FIELD_PREP(SRMCFG_MCID_MASK, mcid);
+		}
+	}
+
+	if (thread_srmcfg != __this_cpu_read(cpu_srmcfg)) {
+		/*
+		 * Drain stores from the outgoing task before the CSR write
+		 * so they retain the previous RCID/MCID tag at the cache
+		 * interconnect.
+		 */
+		RISCV_FENCE(rw, o);
+
+		__this_cpu_write(cpu_srmcfg, thread_srmcfg);
+		csr_write(CSR_SRMCFG, thread_srmcfg);
+		/*
+		 * Order the csrw before the new task's loads/stores so they
+		 * pick up the new tag. Zicsr 6.1.1 makes CSR writes weakly
+		 * ordered (device-output) vs memory ops. Ssqosid v1.0 is
+		 * silent so honor the general CSR rule.
+		 */
+		RISCV_FENCE(o, rw);
+	}
+}
+
+static __always_inline bool has_srmcfg(void)
+{
+	return riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID);
+}
+
+#else /* ! CONFIG_RISCV_ISA_SSQOSID  */
+
+struct task_struct;
+static __always_inline bool has_srmcfg(void) { return false; }
+static inline void __switch_to_srmcfg(struct task_struct *next) { }
+
+#endif /* CONFIG_RISCV_ISA_SSQOSID */
+#endif /* _ASM_RISCV_QOS_H */
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 0e71eb82f920..1c7ea53ec012 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -14,6 +14,7 @@
 #include <asm/processor.h>
 #include <asm/ptrace.h>
 #include <asm/csr.h>
+#include <asm/qos.h>
 
 #ifdef CONFIG_FPU
 extern void __fstate_save(struct task_struct *save_to);
@@ -119,6 +120,8 @@ do {							\
 		__switch_to_fpu(__prev, __next);	\
 	if (has_vector() || has_xtheadvector())		\
 		__switch_to_vector(__prev, __next);	\
+	if (has_srmcfg())				\
+		__switch_to_srmcfg(__next);		\
 	if (switch_to_should_flush_icache(__next))	\
 		local_flush_icache_all();		\
 	__switch_to_envcfg(__next);			\
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index cabb99cadfb6..ebe1c3588177 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -128,3 +128,5 @@ obj-$(CONFIG_ACPI_NUMA)	+= acpi_numa.o
 
 obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o
 obj-$(CONFIG_RISCV_USER_CFI) += usercfi.o
+
+obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
diff --git a/arch/riscv/kernel/qos.c b/arch/riscv/kernel/qos.c
new file mode 100644
index 000000000000..d18b99b195e7
--- /dev/null
+++ b/arch/riscv/kernel/qos.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/cpu.h>
+#include <linux/cpu_pm.h>
+#include <linux/cpuhotplug.h>
+#include <linux/notifier.h>
+#include <linux/percpu-defs.h>
+#include <linux/types.h>
+
+#include <asm/cpufeature-macros.h>
+#include <asm/hwcap.h>
+#include <asm/qos.h>
+
+/*
+ * Cached value of srmcfg csr for each cpu. Seeded to U32_MAX so the next
+ * __switch_to_srmcfg() unconditionally writes the CSR; the encoding
+ * MCID << 16 | RCID with both fields well under 16 bits can never
+ * produce this sentinel. This covers early-boot context switches that
+ * happen before riscv_srmcfg_init() runs as an arch_initcall.
+ */
+DEFINE_PER_CPU(u32, cpu_srmcfg) = U32_MAX;
+
+/* default srmcfg value for each cpu, set via resctrl cpu assignment */
+DEFINE_PER_CPU(u32, cpu_srmcfg_default);
+
+/*
+ * Seed the per-CPU srmcfg cache to a sentinel that no real srmcfg encoding
+ * can produce (MCID << 16 | RCID, both fields well under 16 bits) so the
+ * next __switch_to_srmcfg() unconditionally writes the CSR. Ssqosid v1.0
+ * leaves CSR state across hart stop/start implementation-defined, so the
+ * cached value cannot be trusted after online.
+ */
+static int riscv_srmcfg_online(unsigned int cpu)
+{
+	per_cpu(cpu_srmcfg, cpu) = U32_MAX;
+	return 0;
+}
+
+/*
+ * Invalidate the cache on offline too. The sentinel persists across the
+ * offline period, so a CPU brought back online finds the cache already
+ * invalidated before it is schedulable. This closes the window where a
+ * task scheduled before riscv_srmcfg_online() runs could match a stale
+ * cache and skip the CSR write while the hardware CSR was reset across
+ * hart stop/start.
+ */
+static int riscv_srmcfg_offline(unsigned int cpu)
+{
+	per_cpu(cpu_srmcfg, cpu) = U32_MAX;
+	return 0;
+}
+
+/*
+ * CPU PM notifier: invalidate the cached srmcfg on resume from a deep
+ * idle / suspend. Ssqosid v1.0 leaves CSR_SRMCFG state across low-power
+ * transitions implementation-defined, and the boot CPU never goes
+ * through the cpuhp online callback during system suspend, so without
+ * this hook __switch_to_srmcfg() would skip the CSR write when the
+ * outgoing task happens to share its srmcfg with the pre-suspend cache.
+ */
+static int riscv_srmcfg_pm_notify(struct notifier_block *nb,
+				  unsigned long action, void *unused)
+{
+	switch (action) {
+	case CPU_PM_EXIT:
+	case CPU_PM_ENTER_FAILED:
+		__this_cpu_write(cpu_srmcfg, U32_MAX);
+		break;
+	}
+	return NOTIFY_OK;
+}
+
+static struct notifier_block riscv_srmcfg_pm_nb = {
+	.notifier_call = riscv_srmcfg_pm_notify,
+};
+
+static int __init riscv_srmcfg_init(void)
+{
+	int err;
+
+	if (!riscv_has_extension_unlikely(RISCV_ISA_EXT_SSQOSID))
+		return 0;
+
+	/*
+	 * cpuhp_setup_state() invokes the startup callback locally on every
+	 * already-online CPU, so no separate seed loop is needed here.
+	 */
+	err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "riscv/srmcfg:online",
+				riscv_srmcfg_online, riscv_srmcfg_offline);
+	if (err < 0) {
+		pr_warn("srmcfg cpuhp registration failed (%d), cpus brought online after boot will not invalidate the CSR_SRMCFG cache\n",
+			err);
+		return err;
+	}
+
+	cpu_pm_register_notifier(&riscv_srmcfg_pm_nb);
+	return 0;
+}
+arch_initcall(riscv_srmcfg_init);

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:35:56 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:35:56 -0700
Subject: [PATCH RFC v6 02/18] riscv: detect the Ssqosid extension
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-2-baf00f50028a@kernel.org>

Ssqosid is the RISC-V Quality-of-Service (QoS) Identifiers specification
which defines the Supervisor Resource Management Configuration (srmcfg)
register.

Link: https://github.com/riscv/riscv-ssqosid/releases/tag/v1.0
Co-developed-by: Kornel Dul?ba <mindal at semihalf.com>
Signed-off-by: Kornel Dul?ba <mindal at semihalf.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 arch/riscv/include/asm/hwcap.h | 1 +
 arch/riscv/kernel/cpufeature.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 7ef8e5f55c8d..b83dae5cebb9 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -112,6 +112,7 @@
 #define RISCV_ISA_EXT_ZCLSD		103
 #define RISCV_ISA_EXT_ZICFILP		104
 #define RISCV_ISA_EXT_ZICFISS		105
+#define RISCV_ISA_EXT_SSQOSID		106
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index f46aa5602d74..668a7e71ff1c 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -582,6 +582,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
 	__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
 	__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
+	__RISCV_ISA_EXT_DATA(ssqosid, RISCV_ISA_EXT_SSQOSID),
 	__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
 	__RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),
 	__RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate),

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:35:58 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:35:58 -0700
Subject: [PATCH RFC v6 04/18] fs/resctrl: Add resctrl_is_membw() helper
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-4-baf00f50028a@kernel.org>

Four sites in fs/resctrl distinguish bandwidth resources (MBA, SMBA)
from cache resources by explicit rid match:

  fs/resctrl/ctrlmondata.c parse_line()
  fs/resctrl/rdtgroup.c    rdtgroup_mode_test_exclusive()
  fs/resctrl/rdtgroup.c    rdtgroup_size_show()
  fs/resctrl/rdtgroup.c    rdtgroup_init_alloc()

Replace the open-coded MBA/SMBA tests with a single resctrl_is_membw()
helper keyed on schema_fmt (RESCTRL_SCHEMA_RANGE). No functional change:
every existing RESCTRL_SCHEMA_RANGE resource is MBA or SMBA today.

This isolates fs/resctrl from the addition of further bandwidth resource
types so the four call sites do not have to be updated for each new rid.

Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 fs/resctrl/ctrlmondata.c |  3 +--
 fs/resctrl/internal.h    |  2 ++
 fs/resctrl/rdtgroup.c    | 14 +++++++++-----
 3 files changed, 12 insertions(+), 7 deletions(-)

diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index 9a7dfc48cb2e..d9f052700941 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -245,8 +245,7 @@ static int parse_line(char *line, struct resctrl_schema *s,
 	if (WARN_ON_ONCE(!parse_ctrlval))
 		return -EINVAL;
 
-	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP &&
-	    (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)) {
+	if (rdtgrp->mode == RDT_MODE_PSEUDO_LOCKSETUP && resctrl_is_membw(r)) {
 		rdt_last_cmd_puts("Cannot pseudo-lock MBA resource\n");
 		return -EINVAL;
 	}
diff --git a/fs/resctrl/internal.h b/fs/resctrl/internal.h
index 1a9b29119f88..76187987b2ee 100644
--- a/fs/resctrl/internal.h
+++ b/fs/resctrl/internal.h
@@ -397,6 +397,8 @@ void mbm_handle_overflow(struct work_struct *work);
 
 bool is_mba_sc(struct rdt_resource *r);
 
+bool resctrl_is_membw(struct rdt_resource *r);
+
 void cqm_setup_limbo_handler(struct rdt_l3_mon_domain *dom, unsigned long delay_ms,
 			     int exclude_cpu);
 
diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 5dfdaa6f9d8f..0f331bf5ce82 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1412,7 +1412,7 @@ static bool rdtgroup_mode_test_exclusive(struct rdtgroup *rdtgrp)
 
 	list_for_each_entry(s, &resctrl_schema_all, list) {
 		r = s->res;
-		if (r->rid == RDT_RESOURCE_MBA || r->rid == RDT_RESOURCE_SMBA)
+		if (resctrl_is_membw(r))
 			continue;
 		has_cache = true;
 		list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
@@ -1555,6 +1555,12 @@ bool is_mba_sc(struct rdt_resource *r)
 	return r->membw.mba_sc;
 }
 
+/* RANGE schema is bandwidth (MBA/SMBA). BITMAP is cache. */
+bool resctrl_is_membw(struct rdt_resource *r)
+{
+	return r->schema_fmt == RESCTRL_SCHEMA_RANGE;
+}
+
 /*
  * rdtgroup_size_show - Display size in bytes of allocated regions
  *
@@ -1616,8 +1622,7 @@ static int rdtgroup_size_show(struct kernfs_open_file *of,
 					ctrl = resctrl_arch_get_config(r, d,
 								       closid,
 								       type);
-				if (r->rid == RDT_RESOURCE_MBA ||
-				    r->rid == RDT_RESOURCE_SMBA)
+				if (resctrl_is_membw(r))
 					size = ctrl;
 				else
 					size = rdtgroup_cbm_to_size(r, d, ctrl);
@@ -3648,8 +3653,7 @@ static int rdtgroup_init_alloc(struct rdtgroup *rdtgrp)
 
 	list_for_each_entry(s, &resctrl_schema_all, list) {
 		r = s->res;
-		if (r->rid == RDT_RESOURCE_MBA ||
-		    r->rid == RDT_RESOURCE_SMBA) {
+		if (resctrl_is_membw(r)) {
 			rdtgroup_init_mba(r, rdtgrp->closid);
 			if (is_mba_sc(r))
 				continue;

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:35:59 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:35:59 -0700
Subject: [PATCH RFC v6 05/18] fs/resctrl: Add RDT_RESOURCE_MB_MIN and
 RDT_RESOURCE_MB_WGHT
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-5-baf00f50028a@kernel.org>

Introduce bandwidth controls which are semantically different from
the throttle-based MB resource:

 - RDT_RESOURCE_MB_MIN: minimum reserved bandwidth
 - RDT_RESOURCE_MB_WGHT: weighted share of unreserved bandwidth

Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 fs/resctrl/rdtgroup.c   | 4 +++-
 include/linux/resctrl.h | 2 ++
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/fs/resctrl/rdtgroup.c b/fs/resctrl/rdtgroup.c
index 0f331bf5ce82..02733b11e115 100644
--- a/fs/resctrl/rdtgroup.c
+++ b/fs/resctrl/rdtgroup.c
@@ -1555,7 +1555,7 @@ bool is_mba_sc(struct rdt_resource *r)
 	return r->membw.mba_sc;
 }
 
-/* RANGE schema is bandwidth (MBA/SMBA). BITMAP is cache. */
+/* RANGE schema is bandwidth (MBA/SMBA/MB_MIN/MB_WGHT). BITMAP is cache. */
 bool resctrl_is_membw(struct rdt_resource *r)
 {
 	return r->schema_fmt == RESCTRL_SCHEMA_RANGE;
@@ -2402,6 +2402,8 @@ static unsigned long fflags_from_resource(struct rdt_resource *r)
 		return RFTYPE_RES_CACHE;
 	case RDT_RESOURCE_MBA:
 	case RDT_RESOURCE_SMBA:
+	case RDT_RESOURCE_MB_MIN:
+	case RDT_RESOURCE_MB_WGHT:
 		return RFTYPE_RES_MB;
 	case RDT_RESOURCE_PERF_PKG:
 		return RFTYPE_RES_PERF_PKG;
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 006e57fd7ca5..9529ed0d1fdf 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -53,6 +53,8 @@ enum resctrl_res_level {
 	RDT_RESOURCE_L2,
 	RDT_RESOURCE_MBA,
 	RDT_RESOURCE_SMBA,
+	RDT_RESOURCE_MB_MIN,
+	RDT_RESOURCE_MB_WGHT,
 	RDT_RESOURCE_PERF_PKG,
 
 	/* Must be the last */

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:00 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:00 -0700
Subject: [PATCH RFC v6 06/18] fs/resctrl: Let bandwidth resources default
 to min_bw at reset
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-6-baf00f50028a@kernel.org>

Bandwidth resources reset to max_bw on group creation today, which is
the right default for MBA and SMBA. However, it is the wrong default for
hardware whose registers form a sum-constrained reservation: defaulting
every new group to max_bw would immediately violate the sum on the first
mkdir.

When default_to_min is set, resctrl_get_default_ctrl() returns min_bw
for the resource. The existing MBA and SMBA behavior is not changed.

Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 include/linux/resctrl.h | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 9529ed0d1fdf..bcbc166412ef 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -247,7 +247,13 @@ enum membw_throttle_mode {
 /**
  * struct resctrl_membw - Memory bandwidth allocation related data
  * @min_bw:		Minimum memory bandwidth percentage user can request
- * @max_bw:		Maximum memory bandwidth value, used as the reset value
+ * @max_bw:		Maximum memory bandwidth value a group can be
+ *			configured with
+ * @default_to_min:	When true, the default control value for new
+ *			groups and reset is @min_bw instead of @max_bw.
+ *			Drivers whose hardware enforces a sum constraint
+ *			across groups (e.g. CBQRI MB_MIN) set this so
+ *			mkdir does not overflow the sum.
  * @bw_gran:		Granularity at which the memory bandwidth is allocated
  * @delay_linear:	True if memory B/W delay is in linear scale
  * @arch_needs_linear:	True if we can't configure non-linear resources
@@ -259,6 +265,7 @@ enum membw_throttle_mode {
 struct resctrl_membw {
 	u32				min_bw;
 	u32				max_bw;
+	bool				default_to_min;
 	u32				bw_gran;
 	u32				delay_linear;
 	bool				arch_needs_linear;
@@ -405,7 +412,7 @@ static inline u32 resctrl_get_default_ctrl(struct rdt_resource *r)
 	case RESCTRL_SCHEMA_BITMAP:
 		return BIT_MASK(r->cache.cbm_len) - 1;
 	case RESCTRL_SCHEMA_RANGE:
-		return r->membw.max_bw;
+		return r->membw.default_to_min ? r->membw.min_bw : r->membw.max_bw;
 	}
 
 	return WARN_ON_ONCE(1);

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:01 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:01 -0700
Subject: [PATCH RFC v6 07/18] riscv_cbqri: Add capacity controller probe
 and allocation device ops
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-7-baf00f50028a@kernel.org>

Add support for the RISC-V CBQRI capacity controller (CC). The firmware
discovery layer is responsible for passing the cbqri_controller_info
descriptor to riscv_cbqri_register_controller().

The driver resolves the cpumask so callers do not need the cacheinfo
topology. AT-capable controllers with CDP off mirror the cbm into both
DATA and CODE halves.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 MAINTAINERS                      |   3 +
 drivers/resctrl/Kconfig          |  28 ++
 drivers/resctrl/Makefile         |   5 +
 drivers/resctrl/cbqri_devices.c  | 567 +++++++++++++++++++++++++++++++++++++++
 drivers/resctrl/cbqri_internal.h | 141 ++++++++++
 include/linux/riscv_cbqri.h      |  60 +++++
 6 files changed, 804 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index e694fb2a22d2..24bdc04fea7a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23024,6 +23024,9 @@ L:	linux-riscv at lists.infradead.org
 S:	Supported
 F:	arch/riscv/include/asm/qos.h
 F:	arch/riscv/kernel/qos.c
+F:	drivers/resctrl/cbqri_devices.c
+F:	drivers/resctrl/cbqri_internal.h
+F:	include/linux/riscv_cbqri.h
 
 RISC-V RPMI AND MPXY DRIVERS
 M:	Rahul Pathak <rahul at summations.net>
diff --git a/drivers/resctrl/Kconfig b/drivers/resctrl/Kconfig
index 672abea3b03c..d578bc7aed85 100644
--- a/drivers/resctrl/Kconfig
+++ b/drivers/resctrl/Kconfig
@@ -29,3 +29,31 @@ config ARM64_MPAM_RESCTRL_FS
 	default y if ARM64_MPAM_DRIVER && RESCTRL_FS
 	select RESCTRL_RMID_DEPENDS_ON_CLOSID
 	select RESCTRL_ASSIGN_FIXED
+
+menuconfig RISCV_CBQRI_DRIVER
+	bool "RISC-V CBQRI driver"
+	depends on RISCV && RISCV_ISA_SSQOSID
+	help
+	  Capacity and Bandwidth QoS Register Interface (CBQRI) driver
+	  for RISC-V cache and memory-controller QoS resources. CBQRI
+	  exposes capacity allocation, bandwidth reservation, weighted
+	  bandwidth share, and per-MCID monitoring counters through the
+	  resctrl filesystem at /sys/fs/resctrl when RESCTRL_FS is also
+	  enabled.
+
+	  RISCV_ISA_SSQOSID provides the srmcfg CSR that tags each hart's
+	  memory traffic with the RCID and MCID consumed by CBQRI
+	  controllers.
+
+if RISCV_CBQRI_DRIVER
+
+config RISCV_CBQRI_DRIVER_DEBUG
+	bool "Enable debug messages from the CBQRI driver"
+	help
+	  Say yes here to enable debug messages from the CBQRI driver.
+
+	  This adds pr_debug() output covering controller probe and
+	  per-controller registration steps.  Useful when bringing up a
+	  new platform; otherwise leave disabled to avoid log noise.
+
+endif
diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
index 4f6d0e81f9b8..28085036d895 100644
--- a/drivers/resctrl/Makefile
+++ b/drivers/resctrl/Makefile
@@ -3,3 +3,8 @@ mpam-y						+= mpam_devices.o
 mpam-$(CONFIG_ARM64_MPAM_RESCTRL_FS)		+= mpam_resctrl.o
 
 ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)	+= -DDEBUG
+
+obj-$(CONFIG_RISCV_CBQRI_DRIVER)		+= cbqri.o
+cbqri-y						+= cbqri_devices.o
+
+ccflags-$(CONFIG_RISCV_CBQRI_DRIVER_DEBUG)	+= -DDEBUG
diff --git a/drivers/resctrl/cbqri_devices.c b/drivers/resctrl/cbqri_devices.c
new file mode 100644
index 000000000000..65453e614a43
--- /dev/null
+++ b/drivers/resctrl/cbqri_devices.c
@@ -0,0 +1,567 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/acpi.h>
+#include <linux/bitfield.h>
+#include <linux/cacheinfo.h>
+#include <linux/riscv_cbqri.h>
+#include <linux/cpu.h>
+#include <linux/cpumask.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/csr.h>
+
+#include "cbqri_internal.h"
+
+LIST_HEAD(cbqri_controllers);
+
+/* Set capacity block mask (cc_block_mask) */
+static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
+{
+	iowrite64(cbm, ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
+}
+
+static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset,
+				u64 *regp)
+{
+	u64 reg;
+	int ret;
+
+	/*
+	 * Sleeping poll: caller holds ctrl->lock as a sleeping mutex, so
+	 * 10us/1ms is safe under PREEMPT_RT.
+	 */
+	ret = readq_poll_timeout(ctrl->base + reg_offset, reg,
+				 !FIELD_GET(CBQRI_CONTROL_REGISTERS_BUSY_MASK, reg),
+				 10, 1000);
+	if (ret) {
+		ctrl->faulted = true;
+		return ret;
+	}
+	ctrl->faulted = false;
+	if (regp)
+		*regp = reg;
+	return 0;
+}
+
+/*
+ * Perform capacity allocation control operation on capacity controller.
+ * Caller must hold ctrl->lock.
+ */
+static int cbqri_cc_alloc_op(struct cbqri_controller *ctrl, int operation,
+			     int rcid, enum cbqri_at at)
+{
+	int reg_offset = CBQRI_CC_ALLOC_CTL_OFF;
+	int status;
+	u64 reg;
+
+	lockdep_assert_held(&ctrl->lock);
+
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
+		pr_err_ratelimited("BUSY timeout before starting operation\n");
+		return -EIO;
+	}
+	FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_OP_MASK, &reg, operation);
+	FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_RCID_MASK, &reg, rcid);
+
+	/*
+	 * CBQRI Table 1: AT 0=Data, 1=Code. Program AT on controllers
+	 * that report supports_alloc_at_code. On controllers that don't,
+	 * AT is reserved-zero and the op acts on both halves.
+	 */
+	reg &= ~CBQRI_CONTROL_REGISTERS_AT_MASK;
+	if (ctrl->cc.supports_alloc_at_code)
+		reg |= FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK, at);
+
+	iowrite64(reg, ctrl->base + reg_offset);
+
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
+		pr_err_ratelimited("BUSY timeout during operation\n");
+		return -EIO;
+	}
+
+	status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
+	if (status != CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS) {
+		pr_err_ratelimited("operation %d failed: status=%d\n", operation, status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/*
+ * Apply a capacity block mask and verify via CONFIG_LIMIT + READ_LIMIT.
+ *
+ * AT-capable controllers with CDP off need a second CONFIG_LIMIT on the
+ * other AT half (the spec encodes AT only as 0=Data / 1=Code, there is
+ * no "both halves" value). CDP-on issues separate per-type writes from
+ * resctrl, so a single CONFIG_LIMIT per call is correct.
+ */
+int cbqri_apply_cache_config(struct cbqri_controller *ctrl, u32 closid,
+			     const struct cbqri_cc_config *cfg)
+{
+	bool need_at_mirror;
+	u64 saved_cbm = 0;
+	int err = 0;
+	u64 reg;
+
+	mutex_lock(&ctrl->lock);
+
+	need_at_mirror = ctrl->cc.supports_alloc_at_code && !cfg->cdp_enabled;
+
+	/*
+	 * Capture the cfg->at half CBM before any write so a partial
+	 * AT-mirror failure can revert and keep the two halves consistent.
+	 * Pre-clear cc_block_mask so a silent firmware no-op (status
+	 * SUCCESS but staging not updated) shows as a zero readback
+	 * rather than carrying stale data from a prior op. Mirrors the
+	 * defensive pattern in cbqri_read_cache_config().
+	 */
+	if (need_at_mirror) {
+		cbqri_set_cbm(ctrl, 0);
+		err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
+					closid, cfg->at);
+		if (err < 0)
+			goto out;
+		saved_cbm = ioread64(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
+	}
+
+	/* Set capacity block mask (cc_block_mask) */
+	cbqri_set_cbm(ctrl, cfg->cbm);
+
+	/* Capacity config limit operation for the AT half implied by cfg->at */
+	err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT,
+				closid, cfg->at);
+	if (err < 0)
+		goto out;
+
+	/*
+	 * CDP-off mirror: on AT-capable controllers, also program the
+	 * other AT half with the same mask so the two halves stay in sync.
+	 */
+	if (need_at_mirror) {
+		enum cbqri_at other = (cfg->at == CBQRI_AT_CODE) ?
+				      CBQRI_AT_DATA : CBQRI_AT_CODE;
+
+		cbqri_set_cbm(ctrl, cfg->cbm);
+		err = cbqri_cc_alloc_op(ctrl,
+					CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT,
+					closid, other);
+		if (err < 0) {
+			int rerr;
+
+			/*
+			 * Best-effort revert of the cfg->at half so the two
+			 * halves stay in sync. A schemata read sees only one
+			 * half, so silent divergence would otherwise report
+			 * the new value as if the write had succeeded.
+			 */
+			cbqri_set_cbm(ctrl, saved_cbm);
+			rerr = cbqri_cc_alloc_op(ctrl,
+						 CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT,
+						 closid, cfg->at);
+			if (rerr < 0)
+				pr_err_ratelimited("AT-mirror revert failed (err=%d), AT halves diverged\n",
+						   rerr);
+			goto out;
+		}
+	}
+
+	/* Clear cc_block_mask before read limit to verify op works */
+	cbqri_set_cbm(ctrl, 0);
+
+	/* Perform a capacity read limit operation to verify blockmask */
+	err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
+				closid, cfg->at);
+	if (err < 0)
+		goto out;
+
+	/*
+	 * Read capacity blockmask and narrow to u32 to match resctrl's CBM
+	 * width. cbqri_probe_cc() rejects ncblks > 32 so the upper bits are
+	 * reserved zero.
+	 */
+	reg = ioread64(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
+	if (lower_32_bits(reg) != cfg->cbm) {
+		pr_err_ratelimited("CBM verify mismatch (reg=%llx != cbm=%llx)\n",
+				   reg, cfg->cbm);
+		err = -EIO;
+	}
+
+out:
+	mutex_unlock(&ctrl->lock);
+	return err;
+}
+
+/*
+ * Read the configured CBM for closid on the at half via READ_LIMIT.
+ * Pre-clears cc_block_mask before the op so a silent firmware no-op
+ * (status SUCCESS but staging not updated) is detectable in cbm_out.
+ */
+int cbqri_read_cache_config(struct cbqri_controller *ctrl, u32 closid,
+			    enum cbqri_at at, u32 *cbm_out)
+{
+	int err;
+
+	mutex_lock(&ctrl->lock);
+	cbqri_set_cbm(ctrl, 0);
+	err = cbqri_cc_alloc_op(ctrl, CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, closid, at);
+	if (err == 0) {
+		/*
+		 * cc_block_mask is a 64-bit MMIO register. resctrl exposes the
+		 * CBM as a u32. cbqri_probe_cc() rejects ncblks > 32 so the
+		 * upper 32 bits are reserved zero by the spec. Narrow
+		 * explicitly via lower_32_bits() so the assumption is visible
+		 * at the read site.
+		 */
+		*cbm_out = lower_32_bits(ioread64(ctrl->base + CBQRI_CC_BLOCK_MASK_OFF));
+	}
+	mutex_unlock(&ctrl->lock);
+	return err;
+}
+
+static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset,
+			       int operation, int *status, bool *access_type_supported)
+{
+	const u64 active_mask = CBQRI_CONTROL_REGISTERS_OP_MASK |
+				CBQRI_CONTROL_REGISTERS_AT_MASK |
+				CBQRI_CONTROL_REGISTERS_RCID_MASK |
+				CBQRI_MON_CTL_EVT_ID_MASK;
+	u64 reg, saved_reg;
+	int at;
+
+	/*
+	 * Default the output to false so the status==0 (feature not
+	 * implemented) path returns a deterministic value to the caller
+	 * rather than leaving an uninitialized bool.
+	 */
+	*access_type_supported = false;
+
+	/* Keep the initial register value to preserve the WPRI fields */
+	reg = ioread64(ctrl->base + reg_offset);
+	saved_reg = reg;
+
+	/* Drain any in-flight firmware op before issuing our own write. */
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, &saved_reg) < 0) {
+		pr_err("BUSY timeout before probe operation\n");
+		return -EIO;
+	}
+
+	/*
+	 * Execute the requested operation with all active fields
+	 * (OP/AT/RCID/EVT_ID) zeroed except OP itself. The same builder
+	 * works for ALLOC_CTL and MON_CTL because every bit not in
+	 * active_mask is WPRI and gets carried over from saved_reg. The
+	 * AT and EVT_ID positions are reserved for the other register
+	 * type, where writing zero is harmless.
+	 */
+	reg = (saved_reg & ~active_mask) |
+	      FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation);
+	iowrite64(reg, ctrl->base + reg_offset);
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
+		pr_err_ratelimited("BUSY timeout during operation\n");
+		return -EIO;
+	}
+
+	/* Get the operation status */
+	*status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
+
+	/*
+	 * Check for the AT support if the register is implemented
+	 * (if not, the status value will remain 0)
+	 */
+	if (*status != 0) {
+		/*
+		 * Re-issue operation with AT=CODE so the controller
+		 * latches AT=CODE on supported hardware (or resets it to 0
+		 * on hardware that doesn't). OP must be a defined CBQRI op
+		 * here. OP=0 is a no-op and would silently disable CDP.
+		 */
+		reg = (saved_reg & ~active_mask) |
+		      FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation) |
+		      FIELD_PREP(CBQRI_CONTROL_REGISTERS_AT_MASK,
+				 CBQRI_CONTROL_REGISTERS_AT_CODE);
+		iowrite64(reg, ctrl->base + reg_offset);
+		if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
+			pr_err("BUSY timeout setting AT field\n");
+			return -EIO;
+		}
+
+		/*
+		 * If the AT field value has been reset to zero,
+		 * then the AT support is not present
+		 */
+		at = FIELD_GET(CBQRI_CONTROL_REGISTERS_AT_MASK, reg);
+		if (at == CBQRI_CONTROL_REGISTERS_AT_CODE)
+			*access_type_supported = true;
+	}
+
+	/*
+	 * Restore the original register value.
+	 * Clear OP to avoid re-triggering the probe op.
+	 */
+	saved_reg &= ~CBQRI_CONTROL_REGISTERS_OP_MASK;
+	iowrite64(saved_reg, ctrl->base + reg_offset);
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, NULL) < 0) {
+		pr_err("BUSY timeout restoring register value\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int cbqri_probe_cc(struct cbqri_controller *ctrl)
+{
+	int err, status;
+	u64 reg;
+
+	reg = ioread64(ctrl->base + CBQRI_CC_CAPABILITIES_OFF);
+	if (reg == 0)
+		return -ENODEV;
+
+	ctrl->ver_minor = FIELD_GET(CBQRI_CC_CAPABILITIES_VER_MINOR_MASK, reg);
+	ctrl->ver_major = FIELD_GET(CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK, reg);
+	ctrl->cc.ncblks = FIELD_GET(CBQRI_CC_CAPABILITIES_NCBLKS_MASK, reg);
+
+	pr_debug("version=%d.%d ncblks=%d cache_level=%d\n",
+		 ctrl->ver_major, ctrl->ver_minor,
+		 ctrl->cc.ncblks, ctrl->cache.cache_level);
+
+	/*
+	 * NCBLKS == 0 would divide-by-zero in the schemata math while
+	 * ctrl->lock is held.
+	 */
+	if (!ctrl->cc.ncblks) {
+		pr_warn("CC at %pa has 0 capacity blocks, skipping\n",
+			&ctrl->addr);
+		return -ENODEV;
+	}
+
+	if (ctrl->cc.ncblks > 32) {
+		pr_warn("CC at %pa has ncblks=%u > 32 (resctrl CBM is u32), skipping\n",
+			&ctrl->addr, ctrl->cc.ncblks);
+		return -ENODEV;
+	}
+
+	/*
+	 * Resolve cache_size via cacheinfo. cpus_read_lock satisfies
+	 * lockdep_assert_cpus_held() inside get_cpu_cacheinfo_level(). If
+	 * every cpu_mask member is offline, cache_size stays 0 and the
+	 * controller cannot back occupancy monitoring.
+	 */
+	cpus_read_lock();
+	if (!ctrl->cache.cache_size) {
+		int cpu = cpumask_first_and(&ctrl->cache.cpu_mask, cpu_online_mask);
+
+		if (cpu < nr_cpu_ids) {
+			struct cacheinfo *ci;
+
+			ci = get_cpu_cacheinfo_level(cpu, ctrl->cache.cache_level);
+			if (ci)
+				ctrl->cache.cache_size = ci->size;
+		}
+	}
+	cpus_read_unlock();
+
+	/* Probe allocation features */
+	err = cbqri_probe_feature(ctrl, CBQRI_CC_ALLOC_CTL_OFF,
+				  CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
+				  &status, &ctrl->cc.supports_alloc_at_code);
+	if (err)
+		return err;
+
+	if (status == CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS)
+		ctrl->alloc_capable = true;
+
+	return 0;
+}
+
+static int cbqri_probe_controller(struct cbqri_controller *ctrl)
+{
+	int err;
+
+	pr_debug("controller info: type=%d addr=%pa size=%pa max-rcid=%u max-mcid=%u\n",
+		 ctrl->type, &ctrl->addr, &ctrl->size,
+		 ctrl->rcid_count, ctrl->mcid_count);
+
+	if (!ctrl->addr) {
+		pr_warn("controller has invalid addr=0x0, skipping\n");
+		return -EINVAL;
+	}
+
+	if (ctrl->size < CBQRI_CTRL_MIN_REG_SPAN) {
+		pr_warn("controller at %pa: size %pa < minimum 0x%x, skipping\n",
+			&ctrl->addr, &ctrl->size, CBQRI_CTRL_MIN_REG_SPAN);
+		return -EINVAL;
+	}
+
+	if (!request_mem_region(ctrl->addr, ctrl->size, "cbqri_controller")) {
+		pr_err("request_mem_region failed for %pa\n", &ctrl->addr);
+		return -EBUSY;
+	}
+
+	ctrl->base = ioremap(ctrl->addr, ctrl->size);
+	if (!ctrl->base) {
+		pr_err("ioremap failed for %pa\n", &ctrl->addr);
+		err = -ENOMEM;
+		goto err_release;
+	}
+
+	switch (ctrl->type) {
+	case CBQRI_CONTROLLER_TYPE_CAPACITY:
+		err = cbqri_probe_cc(ctrl);
+		break;
+	default:
+		pr_err("unknown controller type %d\n", ctrl->type);
+		err = -ENODEV;
+		break;
+	}
+
+	if (err)
+		goto err_iounmap;
+
+	return 0;
+
+err_iounmap:
+	iounmap(ctrl->base);
+	ctrl->base = NULL;
+err_release:
+	release_mem_region(ctrl->addr, ctrl->size);
+	return err;
+}
+
+void cbqri_controller_destroy(struct cbqri_controller *ctrl)
+{
+	/*
+	 * cbqri_probe_controller() clears ctrl->base on its error paths and
+	 * releases the mem region itself, so reach into both only when
+	 * destroy is rolling back a successful probe.
+	 */
+	if (ctrl->base) {
+		iounmap(ctrl->base);
+		release_mem_region(ctrl->addr, ctrl->size);
+	}
+	kfree(ctrl);
+}
+
+/*
+ * Roll back the most recent n successful riscv_cbqri_register_controller()
+ * calls. Discovery layers use this to undo partial registrations when a
+ * subsequent table entry turns out to be malformed and the whole parse must
+ * abort.
+ *
+ * Caller serialization: this is intended for boot-time discovery (ACPI
+ * acpi_arch_init, future DT) which run single-threaded before late_initcall.
+ * No lock is taken.
+ */
+void riscv_cbqri_unregister_last(unsigned int n)
+{
+	while (n--) {
+		struct cbqri_controller *ctrl;
+
+		if (list_empty(&cbqri_controllers))
+			return;
+		ctrl = list_last_entry(&cbqri_controllers,
+				       struct cbqri_controller, list);
+		list_del(&ctrl->list);
+		cbqri_controller_destroy(ctrl);
+	}
+}
+
+/*
+ * Allocate, populate, and add to cbqri_controllers a fresh controller
+ * descriptor based on info supplied by a discovery layer (ACPI RQSC,
+ * future DT). Resolves the cpumask via PPTT (capacity) so callers do
+ * not need to know about cacheinfo topology.
+ */
+int riscv_cbqri_register_controller(const struct cbqri_controller_info *info)
+{
+	struct cbqri_controller *ctrl;
+	int err;
+
+	if (!info->addr) {
+		pr_warn("skipping controller with invalid addr=0x0\n");
+		return -EINVAL;
+	}
+
+	ctrl = kzalloc(sizeof(*ctrl), GFP_KERNEL);
+	if (!ctrl)
+		return -ENOMEM;
+
+	mutex_init(&ctrl->lock);
+
+	ctrl->addr = info->addr;
+	ctrl->size = info->size;
+	ctrl->type = info->type;
+	ctrl->rcid_count = info->rcid_count;
+	ctrl->mcid_count = info->mcid_count;
+
+	/*
+	 * SRMCFG encodes RCID in 12 bits.  ACPI's acpi_parse_rqsc() already
+	 * caps info->rcid_count at CBQRI_MAX_RCID (1024) so this is unreachable
+	 * today, but a future DT discovery path or a malformed firmware table
+	 * routed through a different validator could bypass that ceiling.
+	 * Catch the violation here rather than silently truncating in every
+	 * FIELD_PREP(SRMCFG_RCID_MASK, closid) on the schedule-in fast path.
+	 */
+	if (WARN_ON_ONCE(ctrl->rcid_count > FIELD_MAX(SRMCFG_RCID_MASK) + 1)) {
+		cbqri_controller_destroy(ctrl);
+		return -EINVAL;
+	}
+
+	switch (info->type) {
+	case CBQRI_CONTROLLER_TYPE_CAPACITY: {
+		int level;
+
+		ctrl->cache.cache_id = info->cache_id;
+
+		level = find_acpi_cache_level_from_id(info->cache_id);
+		if (level < 0) {
+			pr_warn("Failed to resolve cache level for cache id 0x%x (%d), skipping\n",
+				info->cache_id, level);
+			cbqri_controller_destroy(ctrl);
+			return level;
+		}
+		ctrl->cache.cache_level = level;
+
+		/*
+		 * cache_size stays at 0 here. cacheinfo is not populated
+		 * yet at acpi_arch_init time. Filled lazily during probe
+		 * via get_cpu_cacheinfo_level().
+		 */
+
+		err = acpi_pptt_get_cpumask_from_cache_id(info->cache_id,
+							  &ctrl->cache.cpu_mask);
+		if (err) {
+			pr_warn("Failed to get cpumask for cache id 0x%x (%d), skipping\n",
+				info->cache_id, err);
+			cbqri_controller_destroy(ctrl);
+			return err;
+		}
+		break;
+	}
+	default:
+		pr_warn("controller at %pa: unknown type %u, skipping\n",
+			&ctrl->addr, info->type);
+		cbqri_controller_destroy(ctrl);
+		return -EINVAL;
+	}
+
+	err = cbqri_probe_controller(ctrl);
+	if (err) {
+		cbqri_controller_destroy(ctrl);
+		return err;
+	}
+
+	list_add_tail(&ctrl->list, &cbqri_controllers);
+	return 0;
+}
diff --git a/drivers/resctrl/cbqri_internal.h b/drivers/resctrl/cbqri_internal.h
new file mode 100644
index 000000000000..518955963403
--- /dev/null
+++ b/drivers/resctrl/cbqri_internal.h
@@ -0,0 +1,141 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _DRIVERS_RESCTRL_CBQRI_INTERNAL_H
+#define _DRIVERS_RESCTRL_CBQRI_INTERNAL_H
+
+#include <linux/bitfield.h>
+#include <linux/riscv_cbqri.h>
+#include <linux/cpumask.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/types.h>
+
+/* Capacity Controller (CC) MMIO register offsets. */
+#define CBQRI_CC_CAPABILITIES_OFF 0
+#define CBQRI_CC_ALLOC_CTL_OFF   24
+#define CBQRI_CC_BLOCK_MASK_OFF  32
+
+/*
+ * Smallest MMIO span the driver actually accesses: highest defined
+ * register offset (0x20) plus the 8-byte register width. Used by
+ * cbqri_probe_controller() to reject undersized firmware-supplied
+ * mappings before request_mem_region/ioremap, so a u64 access at
+ * BLOCK_MASK does not walk past the end of the mapping.
+ */
+#define CBQRI_CTRL_MIN_REG_SPAN  0x28u
+
+#define CBQRI_CC_CAPABILITIES_VER_MINOR_MASK  GENMASK_ULL(3, 0)
+#define CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK  GENMASK_ULL(7, 4)
+#define CBQRI_CC_CAPABILITIES_NCBLKS_MASK     GENMASK_ULL(23, 8)
+
+/*
+ * CC and BC control and mon registers are 64-bit. Keep every field mask
+ * GENMASK_ULL so FIELD_MODIFY() or ~mask on a u64 register never
+ * zero-extends a 32-bit mask and clobbers STATUS/BUSY/WPRI in bits 63:32
+ * if RV32 support is added in the future.
+ */
+#define CBQRI_CONTROL_REGISTERS_OP_MASK      GENMASK_ULL(4, 0)
+#define CBQRI_CONTROL_REGISTERS_AT_MASK      GENMASK_ULL(7, 5)
+#define CBQRI_CONTROL_REGISTERS_AT_DATA      0
+#define CBQRI_CONTROL_REGISTERS_AT_CODE      1
+#define CBQRI_CONTROL_REGISTERS_RCID_MASK    GENMASK_ULL(19, 8)
+#define CBQRI_CONTROL_REGISTERS_STATUS_MASK  GENMASK_ULL(38, 32)
+#define CBQRI_CONTROL_REGISTERS_BUSY_MASK    GENMASK_ULL(39, 39)
+
+#define CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT 1
+#define CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT   2
+#define CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS  1
+
+/* mon_ctl field masks (CC and BC share an identical OP/MCID/EVT_ID/STATUS layout) */
+#define CBQRI_MON_CTL_OP_MASK        GENMASK_ULL(4, 0)
+#define CBQRI_MON_CTL_MCID_MASK      GENMASK_ULL(19, 8)
+#define CBQRI_MON_CTL_EVT_ID_MASK    GENMASK_ULL(27, 20)
+#define CBQRI_MON_CTL_STATUS_MASK    GENMASK_ULL(38, 32)
+#define CBQRI_MON_CTL_STATUS_SUCCESS 1
+
+/* Capacity Controller hardware capabilities */
+struct riscv_cbqri_capacity_caps {
+	u16 ncblks;
+	bool supports_alloc_at_code;
+};
+
+/**
+ * enum cbqri_at - capacity controller access type for CDP
+ * @CBQRI_AT_DATA: data access (CBQRI Table 1, AT=0)
+ * @CBQRI_AT_CODE: code access (CBQRI Table 1, AT=1)
+ *
+ * Selects between data and code halves on controllers that advertise
+ * supports_alloc_at_code. The resctrl glue maps from CDP_DATA / CDP_CODE
+ * to this enum at the boundary so cbqri_devices.c stays free of fs/resctrl
+ * types.
+ */
+enum cbqri_at {
+	CBQRI_AT_DATA = CBQRI_CONTROL_REGISTERS_AT_DATA,
+	CBQRI_AT_CODE = CBQRI_CONTROL_REGISTERS_AT_CODE,
+};
+
+/**
+ * struct cbqri_cc_config - desired capacity allocation state for one rcid
+ * @cbm:         capacity block mask
+ * @at:          AT half (data or code) the @cbm applies to
+ * @cdp_enabled: when false and the controller supports AT, mirror @cbm
+ *               into the other AT half so both stay in sync
+ */
+struct cbqri_cc_config {
+	u64           cbm;
+	enum cbqri_at at;
+	bool          cdp_enabled;
+};
+
+struct cbqri_controller {
+	void __iomem *base;
+	/*
+	 * Serializes the write-then-poll-busy MMIO sequences on this
+	 * controller. Each CBQRI op may busy-wait up to 1 ms on slow
+	 * firmware, so use a sleeping mutex (paired with the sleeping
+	 * readq_poll_timeout() in cbqri_wait_busy_flag()) to keep
+	 * preemption enabled, which is required for PREEMPT_RT.
+	 * All resctrl-arch entry points run in process context.
+	 */
+	struct mutex lock;
+	/*
+	 * Set by cbqri_wait_busy_flag() on BUSY timeout, cleared on the
+	 * next successful wait. Informational only, used for diagnostics.
+	 */
+	bool faulted;
+
+	int ver_major;
+	int ver_minor;
+
+	struct riscv_cbqri_capacity_caps cc;
+
+	bool alloc_capable;
+	bool mon_capable;
+
+	phys_addr_t addr;
+	phys_addr_t size;
+	enum cbqri_controller_type type;
+	u32 rcid_count;
+	u32 mcid_count;
+
+	struct list_head list;
+
+	struct cache_controller {
+		u32 cache_level;
+		u32 cache_size; /* in bytes */
+		struct cpumask cpu_mask;
+		/* Unique Cache ID from the PPTT table's Cache Type Structure */
+		u32 cache_id;
+	} cache;
+};
+
+extern struct list_head cbqri_controllers;
+
+void cbqri_controller_destroy(struct cbqri_controller *ctrl);
+
+int cbqri_apply_cache_config(struct cbqri_controller *ctrl, u32 closid,
+			     const struct cbqri_cc_config *cfg);
+
+int cbqri_read_cache_config(struct cbqri_controller *ctrl, u32 closid,
+			    enum cbqri_at at, u32 *cbm_out);
+
+#endif /* _DRIVERS_RESCTRL_CBQRI_INTERNAL_H */
diff --git a/include/linux/riscv_cbqri.h b/include/linux/riscv_cbqri.h
new file mode 100644
index 000000000000..5863f0a65f6c
--- /dev/null
+++ b/include/linux/riscv_cbqri.h
@@ -0,0 +1,60 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Public registration API for the RISC-V Capacity and Bandwidth QoS
+ * Register Interface (CBQRI) driver. Discovery layers (ACPI RQSC, future
+ * device tree) call riscv_cbqri_register_controller() to hand a controller
+ * descriptor to the driver, which owns all subsequent state.
+ */
+#ifndef _LINUX_RISCV_CBQRI_H
+#define _LINUX_RISCV_CBQRI_H
+
+#include <linux/types.h>
+
+enum cbqri_controller_type {
+	CBQRI_CONTROLLER_TYPE_CAPACITY,
+	CBQRI_CONTROLLER_TYPE_BANDWIDTH,
+};
+
+/* Sanity caps on per-controller RCID/MCID counts from firmware */
+#define CBQRI_MAX_RCID	1024
+#define CBQRI_MAX_MCID	1024
+
+/**
+ * struct cbqri_controller_info - registration descriptor
+ * @addr:        MMIO base address of the controller's register interface
+ * @size:        size of the MMIO region
+ * @type:        capacity or bandwidth controller
+ * @rcid_count:  number of supported RCIDs (per RQSC table)
+ * @mcid_count:  number of supported MCIDs (per RQSC table)
+ * @cache_id:    PPTT cache id. Only meaningful for CAPACITY controllers
+ * @prox_dom:    SRAT proximity domain. Only meaningful for BANDWIDTH
+ *               controllers
+ *
+ * Discovery layers populate one of @cache_id / @prox_dom according to
+ * @type. The CBQRI driver resolves the matching cpumask internally so
+ * callers do not need to know about cacheinfo/NUMA topology.
+ */
+struct cbqri_controller_info {
+	phys_addr_t			addr;
+	phys_addr_t			size;
+	enum cbqri_controller_type	type;
+	u32				rcid_count;
+	u32				mcid_count;
+	u32				cache_id;
+	u32				prox_dom;
+};
+
+#if IS_ENABLED(CONFIG_RISCV_CBQRI_DRIVER)
+int riscv_cbqri_register_controller(const struct cbqri_controller_info *info);
+void riscv_cbqri_unregister_last(unsigned int n);
+#else
+static inline int
+riscv_cbqri_register_controller(const struct cbqri_controller_info *info)
+{
+	return -ENODEV;
+}
+
+static inline void riscv_cbqri_unregister_last(unsigned int n) { }
+#endif
+
+#endif /* _LINUX_RISCV_CBQRI_H */

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:02 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:02 -0700
Subject: [PATCH RFC v6 08/18] riscv_cbqri: Add capacity controller
 monitoring device ops
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-8-baf00f50028a@kernel.org>

Add capacity monitoring operations. cbqri_init_mon_counters() pre-arms
every MCID with the Occupancy event so a subsequent READ_COUNTER just
snapshots the live counter without re-configuring the slot.

cbqri_probe_cc() leaves ctrl->mon_capable false when cacheinfo has not
given a non-zero cache_size, since the byte conversion would be
meaningless. cbqri_mon_op() takes a reg_offset and serves both capacity
and bandwidth mon_ctl registers as they share an identical layout.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 drivers/resctrl/cbqri_devices.c  | 124 ++++++++++++++++++++++++++++++++++-----
 drivers/resctrl/cbqri_internal.h |  14 +++++
 2 files changed, 124 insertions(+), 14 deletions(-)

diff --git a/drivers/resctrl/cbqri_devices.c b/drivers/resctrl/cbqri_devices.c
index 65453e614a43..c44bc50c31ba 100644
--- a/drivers/resctrl/cbqri_devices.c
+++ b/drivers/resctrl/cbqri_devices.c
@@ -98,6 +98,43 @@ static int cbqri_cc_alloc_op(struct cbqri_controller *ctrl, int operation,
 	return 0;
 }
 
+/*
+ * Issue a monitoring op on a CC or BC controller's mon_ctl register at
+ * reg_offset (CBQRI_CC_MON_CTL_OFF or CBQRI_BC_MON_CTL_OFF). The CC and
+ * BC mon_ctl registers share an identical OP/MCID/EVT_ID/STATUS layout, so
+ * one helper covers both. Caller must hold ctrl->lock.
+ */
+int cbqri_mon_op(struct cbqri_controller *ctrl, int reg_offset,
+		 int operation, int mcid, int evt_id, u64 *out_reg)
+{
+	u64 reg;
+
+	lockdep_assert_held(&ctrl->lock);
+
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
+		pr_err_ratelimited("BUSY timeout before starting operation\n");
+		return -EIO;
+	}
+	FIELD_MODIFY(CBQRI_MON_CTL_OP_MASK, &reg, operation);
+	FIELD_MODIFY(CBQRI_MON_CTL_MCID_MASK, &reg, mcid);
+	FIELD_MODIFY(CBQRI_MON_CTL_EVT_ID_MASK, &reg, evt_id);
+	iowrite64(reg, ctrl->base + reg_offset);
+
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
+		pr_err_ratelimited("BUSY timeout\n");
+		return -EIO;
+	}
+
+	if (FIELD_GET(CBQRI_MON_CTL_STATUS_MASK, reg) !=
+	    CBQRI_MON_CTL_STATUS_SUCCESS)
+		return -EIO;
+
+	if (out_reg)
+		*out_reg = reg;
+
+	return 0;
+}
+
 /*
  * Apply a capacity block mask and verify via CONFIG_LIMIT + READ_LIMIT.
  *
@@ -230,7 +267,8 @@ int cbqri_read_cache_config(struct cbqri_controller *ctrl, u32 closid,
 }
 
 static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset,
-			       int operation, int *status, bool *access_type_supported)
+			       int operation, int evt_id, int *status,
+			       bool *access_type_supported)
 {
 	const u64 active_mask = CBQRI_CONTROL_REGISTERS_OP_MASK |
 				CBQRI_CONTROL_REGISTERS_AT_MASK |
@@ -242,9 +280,11 @@ static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset,
 	/*
 	 * Default the output to false so the status==0 (feature not
 	 * implemented) path returns a deterministic value to the caller
-	 * rather than leaving an uninitialized bool.
+	 * rather than leaving an uninitialized bool. mon_ctl probes pass
+	 * NULL: the register has no AT field, so the AT probe is skipped.
 	 */
-	*access_type_supported = false;
+	if (access_type_supported)
+		*access_type_supported = false;
 
 	/* Keep the initial register value to preserve the WPRI fields */
 	reg = ioread64(ctrl->base + reg_offset);
@@ -257,15 +297,14 @@ static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset,
 	}
 
 	/*
-	 * Execute the requested operation with all active fields
-	 * (OP/AT/RCID/EVT_ID) zeroed except OP itself. The same builder
-	 * works for ALLOC_CTL and MON_CTL because every bit not in
-	 * active_mask is WPRI and gets carried over from saved_reg. The
-	 * AT and EVT_ID positions are reserved for the other register
-	 * type, where writing zero is harmless.
+	 * Execute the requested operation with the active fields
+	 * (OP/AT/RCID/EVT_ID) cleared, then set OP and, for mon_ctl, the
+	 * probe-safe evt_id. WPRI bits outside active_mask carry over from
+	 * saved_reg. alloc_ctl callers pass evt_id 0.
 	 */
 	reg = (saved_reg & ~active_mask) |
-	      FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation);
+	      FIELD_PREP(CBQRI_CONTROL_REGISTERS_OP_MASK, operation) |
+	      FIELD_PREP(CBQRI_MON_CTL_EVT_ID_MASK, evt_id);
 	iowrite64(reg, ctrl->base + reg_offset);
 	if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
 		pr_err_ratelimited("BUSY timeout during operation\n");
@@ -276,10 +315,11 @@ static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset,
 	*status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
 
 	/*
-	 * Check for the AT support if the register is implemented
-	 * (if not, the status value will remain 0)
+	 * Probe AT support only on alloc_ctl registers (mon_ctl has no AT
+	 * field, so access_type_supported is NULL there). Skipped when the
+	 * register is unimplemented (status stays 0).
 	 */
-	if (*status != 0) {
+	if (access_type_supported && *status != 0) {
 		/*
 		 * Re-issue operation with AT=CODE so the controller
 		 * latches AT=CODE on supported hardware (or resets it to 0
@@ -372,9 +412,31 @@ static int cbqri_probe_cc(struct cbqri_controller *ctrl)
 	}
 	cpus_read_unlock();
 
+	/* Probe monitoring features */
+	err = cbqri_probe_feature(ctrl, CBQRI_CC_MON_CTL_OFF,
+				  CBQRI_CC_MON_CTL_OP_CONFIG_EVENT,
+				  CBQRI_CC_EVT_ID_NONE, &status, NULL);
+	if (err)
+		return err;
+
+	if (status == CBQRI_MON_CTL_STATUS_SUCCESS) {
+		/*
+		 * Occupancy is reported to userspace in bytes, computed as
+		 * cache_size * counter / ncblks by the resctrl glue. If
+		 * cacheinfo has no cache_size, leave mon_capable false so
+		 * the file is not exposed at all rather than silently
+		 * returning 0.
+		 */
+		if (!ctrl->cache.cache_size)
+			pr_debug("CC @%pa: cache_size unknown, occupancy monitoring disabled\n",
+				 &ctrl->addr);
+		else
+			ctrl->mon_capable = true;
+	}
+
 	/* Probe allocation features */
 	err = cbqri_probe_feature(ctrl, CBQRI_CC_ALLOC_CTL_OFF,
-				  CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT,
+				  CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT, 0,
 				  &status, &ctrl->cc.supports_alloc_at_code);
 	if (err)
 		return err;
@@ -439,6 +501,28 @@ static int cbqri_probe_controller(struct cbqri_controller *ctrl)
 	return err;
 }
 
+/*
+ * Pre-arm every MCID with the Occupancy event so a subsequent READ_COUNTER
+ * just snapshots the live counter rather than re-configuring the slot.
+ * Called once per CC during resctrl-side cpuhp online for the L3 monitoring
+ * domain.
+ */
+int cbqri_init_mon_counters(struct cbqri_controller *ctrl)
+{
+	int i, err;
+
+	for (i = 0; i < ctrl->mcid_count; i++) {
+		mutex_lock(&ctrl->lock);
+		err = cbqri_mon_op(ctrl, CBQRI_CC_MON_CTL_OFF,
+				   CBQRI_CC_MON_CTL_OP_CONFIG_EVENT,
+				   i, CBQRI_CC_EVT_ID_OCCUPANCY, NULL);
+		mutex_unlock(&ctrl->lock);
+		if (err)
+			return err;
+	}
+	return 0;
+}
+
 void cbqri_controller_destroy(struct cbqri_controller *ctrl)
 {
 	/*
@@ -518,6 +602,18 @@ int riscv_cbqri_register_controller(const struct cbqri_controller_info *info)
 		return -EINVAL;
 	}
 
+	/*
+	 * mon_ctl encodes MCID in 12 bits. acpi_parse_rqsc() caps
+	 * info->mcid_count at CBQRI_MAX_MCID (1024), but a future discovery
+	 * path could bypass that. Reject an out-of-range count so
+	 * cbqri_init_mon_counters() iterates a trusted bound and no MCID
+	 * aliases another slot through FIELD_MODIFY(MON_CTL_MCID_MASK).
+	 */
+	if (WARN_ON_ONCE(ctrl->mcid_count > FIELD_MAX(CBQRI_MON_CTL_MCID_MASK) + 1)) {
+		cbqri_controller_destroy(ctrl);
+		return -EINVAL;
+	}
+
 	switch (info->type) {
 	case CBQRI_CONTROLLER_TYPE_CAPACITY: {
 		int level;
diff --git a/drivers/resctrl/cbqri_internal.h b/drivers/resctrl/cbqri_internal.h
index 518955963403..1d2007a0c15b 100644
--- a/drivers/resctrl/cbqri_internal.h
+++ b/drivers/resctrl/cbqri_internal.h
@@ -11,6 +11,8 @@
 
 /* Capacity Controller (CC) MMIO register offsets. */
 #define CBQRI_CC_CAPABILITIES_OFF 0
+#define CBQRI_CC_MON_CTL_OFF      8
+#define CBQRI_CC_MON_CTL_VAL_OFF 16
 #define CBQRI_CC_ALLOC_CTL_OFF   24
 #define CBQRI_CC_BLOCK_MASK_OFF  32
 
@@ -45,6 +47,9 @@
 #define CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT   2
 #define CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS  1
 
+#define CBQRI_CC_MON_CTL_OP_CONFIG_EVENT 1
+#define CBQRI_CC_MON_CTL_OP_READ_COUNTER 2
+
 /* mon_ctl field masks (CC and BC share an identical OP/MCID/EVT_ID/STATUS layout) */
 #define CBQRI_MON_CTL_OP_MASK        GENMASK_ULL(4, 0)
 #define CBQRI_MON_CTL_MCID_MASK      GENMASK_ULL(19, 8)
@@ -52,6 +57,10 @@
 #define CBQRI_MON_CTL_STATUS_MASK    GENMASK_ULL(38, 32)
 #define CBQRI_MON_CTL_STATUS_SUCCESS 1
 
+/* Capacity usage monitoring event IDs (CBQRI spec Table 4) */
+#define CBQRI_CC_EVT_ID_NONE         0
+#define CBQRI_CC_EVT_ID_OCCUPANCY    1
+
 /* Capacity Controller hardware capabilities */
 struct riscv_cbqri_capacity_caps {
 	u16 ncblks;
@@ -138,4 +147,9 @@ int cbqri_apply_cache_config(struct cbqri_controller *ctrl, u32 closid,
 int cbqri_read_cache_config(struct cbqri_controller *ctrl, u32 closid,
 			    enum cbqri_at at, u32 *cbm_out);
 
+int cbqri_mon_op(struct cbqri_controller *ctrl, int reg_offset,
+		 int operation, int mcid, int evt_id, u64 *out_reg);
+
+int cbqri_init_mon_counters(struct cbqri_controller *ctrl);
+
 #endif /* _DRIVERS_RESCTRL_CBQRI_INTERNAL_H */

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:03 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:03 -0700
Subject: [PATCH RFC v6 09/18] riscv_cbqri: Add bandwidth controller probe
 and allocation device ops
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-9-baf00f50028a@kernel.org>

Add support for CBQRI bandwidth controller (BC) discovery and the two BC
allocation control knobs. Rbwb is the number of reserved bandwidth
blocks per RCID. Mweight is the weighted share per RCID of the remaining
unreserved bandwidth.

Both fields share the bc_bw_alloc register, so cbqri_apply_bc_field()
seeds both halves from per-RCID software caches (rbwb_cache and
mweight_cache) on every CONFIG_LIMIT. The caches are the authoritative
source of the unmodified field, which sidesteps a silent READ_LIMIT
no-op leaking stale data from a prior RCID. After CONFIG_LIMIT, the
caller writes a sentinel to the target field and reads back via
READ_LIMIT to verify hardware accepted the write. The cache is updated
only after verify succeeds.

mweight_cache is seeded to FIELD_MAX at probe so the first MB_MIN
domain init does not commit Mweight=0 (per CBQRI 4.5, a hard cap that
disallows opportunistic bandwidth) before the subsequent MB_WGHT init
catches up.

cbqri_apply_rbwb() enforces the spec-mandated sum(Rbwb) <= MRBWB
invariant from rbwb_cache rather than per-RCID READ_LIMIT round-trips,
which would cost up to 1 ms each while holding the mutex.
cbqri_apply_mweight_config() rejects values that would truncate against
the 8-bit MWEIGHT_MASK at entry.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 drivers/resctrl/cbqri_devices.c  | 416 +++++++++++++++++++++++++++++++++++++++
 drivers/resctrl/cbqri_internal.h |  57 +++++-
 2 files changed, 472 insertions(+), 1 deletion(-)

diff --git a/drivers/resctrl/cbqri_devices.c b/drivers/resctrl/cbqri_devices.c
index c44bc50c31ba..6093706b1ec4 100644
--- a/drivers/resctrl/cbqri_devices.c
+++ b/drivers/resctrl/cbqri_devices.c
@@ -14,6 +14,7 @@
 #include <linux/ioport.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
+#include <linux/numa.h>
 #include <linux/printk.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -30,6 +31,63 @@ static void cbqri_set_cbm(struct cbqri_controller *ctrl, u64 cbm)
 	iowrite64(cbm, ctrl->base + CBQRI_CC_BLOCK_MASK_OFF);
 }
 
+/* Set the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
+static void cbqri_set_rbwb(struct cbqri_controller *ctrl, u64 rbwb)
+{
+	u64 reg;
+
+	reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+	FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_RBWB_MASK, &reg, rbwb);
+	iowrite64(reg, ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+}
+
+/* Get the Rbwb (reserved bandwidth blocks) field in bc_bw_alloc */
+static u64 cbqri_get_rbwb(struct cbqri_controller *ctrl)
+{
+	u64 reg;
+
+	reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+	return FIELD_GET(CBQRI_CONTROL_REGISTERS_RBWB_MASK, reg);
+}
+
+/* Set the Mweight (opportunistic weight) field in bc_bw_alloc */
+static void cbqri_set_mweight(struct cbqri_controller *ctrl, u64 mweight)
+{
+	u64 reg;
+
+	reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+	FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_MWEIGHT_MASK, &reg, mweight);
+	iowrite64(reg, ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+}
+
+/* Get the Mweight (opportunistic weight) field in bc_bw_alloc */
+static u64 cbqri_get_mweight(struct cbqri_controller *ctrl)
+{
+	u64 reg;
+
+	reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+	return FIELD_GET(CBQRI_CONTROL_REGISTERS_MWEIGHT_MASK, reg);
+}
+
+/*
+ * Stage both fields of bc_bw_alloc in one read-modify-write so the staging
+ * register is consistent after a single MMIO write.
+ */
+static void cbqri_set_bc_bw_alloc(struct cbqri_controller *ctrl,
+				  u64 rbwb, u64 mweight)
+{
+	u64 reg = ioread64(ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+
+	FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_RBWB_MASK, &reg, rbwb);
+	FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_MWEIGHT_MASK, &reg, mweight);
+	iowrite64(reg, ctrl->base + CBQRI_BC_BW_ALLOC_OFF);
+}
+
+enum cbqri_bc_field {
+	CBQRI_BC_FIELD_RBWB,
+	CBQRI_BC_FIELD_MWEIGHT,
+};
+
 static int cbqri_wait_busy_flag(struct cbqri_controller *ctrl, int reg_offset,
 				u64 *regp)
 {
@@ -135,6 +193,42 @@ int cbqri_mon_op(struct cbqri_controller *ctrl, int reg_offset,
 	return 0;
 }
 
+/*
+ * Perform bandwidth allocation control operation on bandwidth controller.
+ * Caller must hold ctrl->lock.
+ */
+static int cbqri_bc_alloc_op(struct cbqri_controller *ctrl, int operation, int rcid)
+{
+	int reg_offset = CBQRI_BC_ALLOC_CTL_OFF;
+	int status;
+	u64 reg;
+
+	lockdep_assert_held(&ctrl->lock);
+
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
+		pr_err_ratelimited("BUSY timeout before starting operation\n");
+		return -EIO;
+	}
+	FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_OP_MASK, &reg, operation);
+	FIELD_MODIFY(CBQRI_CONTROL_REGISTERS_RCID_MASK, &reg, rcid);
+	reg &= ~CBQRI_CONTROL_REGISTERS_AT_MASK;
+	iowrite64(reg, ctrl->base + reg_offset);
+
+	if (cbqri_wait_busy_flag(ctrl, reg_offset, &reg) < 0) {
+		pr_err_ratelimited("BUSY timeout during operation\n");
+		return -EIO;
+	}
+
+	status = FIELD_GET(CBQRI_CONTROL_REGISTERS_STATUS_MASK, reg);
+	if (status != CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) {
+		pr_err_ratelimited("BC alloc op %d failed: status=%d\n",
+				   operation, status);
+		return -EIO;
+	}
+
+	return 0;
+}
+
 /*
  * Apply a capacity block mask and verify via CONFIG_LIMIT + READ_LIMIT.
  *
@@ -266,6 +360,189 @@ int cbqri_read_cache_config(struct cbqri_controller *ctrl, u32 closid,
 	return err;
 }
 
+/*
+ * Apply a per-RCID update to one field (Rbwb or Mweight) of bc_bw_alloc.
+ * bc_bw_alloc packs both fields, so both halves are seeded from the
+ * authoritative software caches before CONFIG_LIMIT. This avoids the
+ * silent READ_LIMIT no-op window where stale data from a prior op's
+ * RCID could leak into the unmodified field. The verify step uses an
+ * inverted-value sentinel to confirm hardware accepted the target field.
+ *
+ * Caller must hold ctrl->lock.
+ */
+static int cbqri_apply_bc_field(struct cbqri_controller *ctrl, u32 closid,
+				enum cbqri_bc_field field, u64 val)
+{
+	u64 rbwb = ctrl->rbwb_cache[closid];
+	u64 mweight = ctrl->mweight_cache[closid];
+	u64 readback;
+	int ret;
+
+	lockdep_assert_held(&ctrl->lock);
+
+	if (field == CBQRI_BC_FIELD_RBWB)
+		rbwb = val;
+	else
+		mweight = val;
+
+	/*
+	 * Wait for BUSY=0 before staging. A read-modify-write to the
+	 * bc_bw_alloc staging register while an op is in flight can corrupt
+	 * the unmodified field.
+	 */
+	if (cbqri_wait_busy_flag(ctrl, CBQRI_BC_ALLOC_CTL_OFF, NULL) < 0) {
+		pr_err_ratelimited("BUSY timeout before staging bc_bw_alloc\n");
+		return -EIO;
+	}
+
+	cbqri_set_bc_bw_alloc(ctrl, rbwb, mweight);
+
+	ret = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_CONFIG_LIMIT, closid);
+	if (ret < 0)
+		return ret;
+
+	/*
+	 * Pre-write a sentinel that cannot equal val to the target field
+	 * so a silent READ_LIMIT (status SUCCESS but no staging update)
+	 * is detectable in the readback. ~val truncated to the field
+	 * width cannot equal val.
+	 */
+	if (field == CBQRI_BC_FIELD_RBWB)
+		cbqri_set_rbwb(ctrl, ~val);
+	else
+		cbqri_set_mweight(ctrl, ~val);
+
+	ret = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, closid);
+	if (ret < 0)
+		return ret;
+
+	readback = (field == CBQRI_BC_FIELD_RBWB) ?
+		   cbqri_get_rbwb(ctrl) : cbqri_get_mweight(ctrl);
+	if (readback != val) {
+		pr_err_ratelimited("BC field verify mismatch (reg=0x%llx != val=%llu)\n",
+				   readback, val);
+		return -EIO;
+	}
+
+	/* Hardware confirmed to hold val. Update the authoritative cache. */
+	if (field == CBQRI_BC_FIELD_RBWB)
+		ctrl->rbwb_cache[closid] = rbwb;
+	else
+		ctrl->mweight_cache[closid] = mweight;
+
+	return 0;
+}
+
+/*
+ * Apply an Rbwb update for closid, optionally enforcing CBQRI section 4.5
+ * sum(Rbwb) <= MRBWB. check_sum=false is used by coordinated init/reset
+ * walks where intermediate sums may transiently exceed MRBWB.
+ */
+int cbqri_apply_rbwb(struct cbqri_controller *ctrl, u32 closid,
+		     u64 rbwb, bool check_sum)
+{
+	u32 i;
+	int ret;
+
+	if (rbwb > U16_MAX)
+		return -EINVAL;
+
+	mutex_lock(&ctrl->lock);
+
+	if (check_sum && rbwb > 0) {
+		u64 sum = rbwb;
+
+		for (i = 0; i < ctrl->rcid_count; i++) {
+			if (i == closid)
+				continue;
+			sum += ctrl->rbwb_cache[i];
+		}
+		if (sum > ctrl->bc.mrbwb) {
+			pr_err_ratelimited("RBWB sum %llu exceeds MRBWB %u\n",
+					   sum, ctrl->bc.mrbwb);
+			ret = -EINVAL;
+			goto out;
+		}
+	}
+
+	ret = cbqri_apply_bc_field(ctrl, closid, CBQRI_BC_FIELD_RBWB, rbwb);
+out:
+	mutex_unlock(&ctrl->lock);
+	return ret;
+}
+
+int cbqri_apply_mweight_config(struct cbqri_controller *ctrl, u32 closid,
+			       u64 mweight)
+{
+	int ret;
+
+	if (mweight > FIELD_MAX(CBQRI_CONTROL_REGISTERS_MWEIGHT_MASK))
+		return -EINVAL;
+
+	mutex_lock(&ctrl->lock);
+	ret = cbqri_apply_bc_field(ctrl, closid, CBQRI_BC_FIELD_MWEIGHT, mweight);
+	mutex_unlock(&ctrl->lock);
+	return ret;
+}
+
+/*
+ * Read the Rbwb (reserved bandwidth blocks) for closid via READ_LIMIT.
+ */
+int cbqri_read_rbwb(struct cbqri_controller *ctrl, u32 closid, u64 *rbwb_out)
+{
+	u8 mweight_sentinel = ~ctrl->mweight_cache[closid];
+	int err;
+
+	mutex_lock(&ctrl->lock);
+
+	/*
+	 * Stage a sentinel into the unread Mweight field. A silent
+	 * READ_LIMIT no-op (status SUCCESS but staging not refreshed) leaves
+	 * the sentinel in place, while a real read overwrites Mweight with
+	 * the hardware value, which differs from the inverted cache sentinel.
+	 */
+	cbqri_set_bc_bw_alloc(ctrl, ctrl->rbwb_cache[closid], mweight_sentinel);
+	err = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, closid);
+	if (err == 0) {
+		if (cbqri_get_mweight(ctrl) == mweight_sentinel) {
+			pr_err_ratelimited("Rbwb READ_LIMIT did not update staging\n");
+			err = -EIO;
+		} else {
+			*rbwb_out = cbqri_get_rbwb(ctrl);
+		}
+	}
+	mutex_unlock(&ctrl->lock);
+	return err;
+}
+
+/*
+ * Read the Mweight (opportunistic weight) for closid via READ_LIMIT.
+ */
+int cbqri_read_mweight(struct cbqri_controller *ctrl, u32 closid, u64 *mweight_out)
+{
+	u16 rbwb_sentinel = ~ctrl->rbwb_cache[closid];
+	int err;
+
+	mutex_lock(&ctrl->lock);
+
+	/*
+	 * Stage a sentinel into the unread Rbwb field so a silent READ_LIMIT
+	 * no-op is detectable, mirroring cbqri_read_rbwb().
+	 */
+	cbqri_set_bc_bw_alloc(ctrl, rbwb_sentinel, ctrl->mweight_cache[closid]);
+	err = cbqri_bc_alloc_op(ctrl, CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, closid);
+	if (err == 0) {
+		if (cbqri_get_rbwb(ctrl) == rbwb_sentinel) {
+			pr_err_ratelimited("Mweight READ_LIMIT did not update staging\n");
+			err = -EIO;
+		} else {
+			*mweight_out = cbqri_get_mweight(ctrl);
+		}
+	}
+	mutex_unlock(&ctrl->lock);
+	return err;
+}
+
 static int cbqri_probe_feature(struct cbqri_controller *ctrl, int reg_offset,
 			       int operation, int evt_id, int *status,
 			       bool *access_type_supported)
@@ -447,6 +724,108 @@ static int cbqri_probe_cc(struct cbqri_controller *ctrl)
 	return 0;
 }
 
+static int cbqri_probe_bc(struct cbqri_controller *ctrl)
+{
+	int err, status;
+	u32 i;
+	u64 reg;
+
+	reg = ioread64(ctrl->base + CBQRI_BC_CAPABILITIES_OFF);
+	if (reg == 0)
+		return -ENODEV;
+
+	ctrl->ver_minor = FIELD_GET(CBQRI_BC_CAPABILITIES_VER_MINOR_MASK, reg);
+	ctrl->ver_major = FIELD_GET(CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK, reg);
+	ctrl->bc.nbwblks = FIELD_GET(CBQRI_BC_CAPABILITIES_NBWBLKS_MASK, reg);
+	ctrl->bc.mrbwb = FIELD_GET(CBQRI_BC_CAPABILITIES_MRBWB_MASK, reg);
+
+	if (!ctrl->bc.nbwblks) {
+		pr_err("bandwidth controller has nbwblks=0\n");
+		return -EINVAL;
+	}
+
+	if (!ctrl->rcid_count) {
+		pr_err("bandwidth controller has rcid_count=0\n");
+		return -EINVAL;
+	}
+
+	/*
+	 * Reset seeds RCID 0 with mrbwb - (rcid_count - 1). Reject a
+	 * controller that would underflow that arithmetic.
+	 */
+	if (ctrl->bc.mrbwb < ctrl->rcid_count) {
+		pr_err("bandwidth controller has mrbwb=%u < rcid_count=%u, rejecting\n",
+		       ctrl->bc.mrbwb, ctrl->rcid_count);
+		return -EINVAL;
+	}
+
+	pr_debug("version=%d.%d nbwblks=%d mrbwb=%d\n",
+		 ctrl->ver_major, ctrl->ver_minor,
+		 ctrl->bc.nbwblks, ctrl->bc.mrbwb);
+
+	/* Probe monitoring features */
+	err = cbqri_probe_feature(ctrl, CBQRI_BC_MON_CTL_OFF,
+				  CBQRI_BC_MON_CTL_OP_READ_COUNTER, 0,
+				  &status, NULL);
+	if (err)
+		return err;
+
+	if (status == CBQRI_MON_CTL_STATUS_SUCCESS)
+		ctrl->mon_capable = true;
+
+	/* Probe allocation features */
+	err = cbqri_probe_feature(ctrl, CBQRI_BC_ALLOC_CTL_OFF,
+				  CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT, 0,
+				  &status, &ctrl->bc.supports_alloc_at_code);
+	if (err)
+		return err;
+
+	if (status == CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS) {
+		ctrl->alloc_capable = true;
+
+		/*
+		 * Per-RCID Rbwb and Mweight caches. The caches feed both
+		 * fields of bc_bw_alloc on every apply so the staging
+		 * register reflects authoritative software state, sidestepping
+		 * silent READ_LIMIT no-op corruption of the unmodified field.
+		 * rbwb_cache also lets cbqri_apply_rbwb() validate
+		 * sum(Rbwb) <= MRBWB without re-reading every RCID.
+		 */
+		ctrl->rbwb_cache = kcalloc(ctrl->rcid_count,
+					   sizeof(*ctrl->rbwb_cache),
+					   GFP_KERNEL);
+		if (!ctrl->rbwb_cache)
+			return -ENOMEM;
+
+		ctrl->mweight_cache = kcalloc(ctrl->rcid_count,
+					      sizeof(*ctrl->mweight_cache),
+					      GFP_KERNEL);
+		if (!ctrl->mweight_cache) {
+			kfree(ctrl->rbwb_cache);
+			ctrl->rbwb_cache = NULL;
+			return -ENOMEM;
+		}
+
+		/*
+		 * Seed mweight to the maximum, matching the resctrl-side
+		 * MB_WGHT default. cbqri_apply_bc_field() reads both halves
+		 * of bc_bw_alloc from the caches on every CONFIG_LIMIT, so
+		 * the first MB_MIN domain init (which writes Rbwb) would
+		 * otherwise commit Mweight=0 to every RCID. Per CBQRI 4.5
+		 * a weight of 0 implies the configured limit is a hard
+		 * limit and the use of unused or non-reserved bandwidth
+		 * is not allowed, which starves every RCID of opportunistic
+		 * bandwidth until the subsequent MB_WGHT domain init
+		 * catches up.
+		 */
+		for (i = 0; i < ctrl->rcid_count; i++)
+			ctrl->mweight_cache[i] =
+				FIELD_MAX(CBQRI_CONTROL_REGISTERS_MWEIGHT_MASK);
+	}
+
+	return 0;
+}
+
 static int cbqri_probe_controller(struct cbqri_controller *ctrl)
 {
 	int err;
@@ -482,6 +861,9 @@ static int cbqri_probe_controller(struct cbqri_controller *ctrl)
 	case CBQRI_CONTROLLER_TYPE_CAPACITY:
 		err = cbqri_probe_cc(ctrl);
 		break;
+	case CBQRI_CONTROLLER_TYPE_BANDWIDTH:
+		err = cbqri_probe_bc(ctrl);
+		break;
 	default:
 		pr_err("unknown controller type %d\n", ctrl->type);
 		err = -ENODEV;
@@ -534,6 +916,8 @@ void cbqri_controller_destroy(struct cbqri_controller *ctrl)
 		iounmap(ctrl->base);
 		release_mem_region(ctrl->addr, ctrl->size);
 	}
+	kfree(ctrl->mweight_cache);
+	kfree(ctrl->rbwb_cache);
 	kfree(ctrl);
 }
 
@@ -645,6 +1029,38 @@ int riscv_cbqri_register_controller(const struct cbqri_controller_info *info)
 		}
 		break;
 	}
+	case CBQRI_CONTROLLER_TYPE_BANDWIDTH: {
+		struct cbqri_controller *other;
+		int node_id;
+
+		ctrl->mem.prox_dom = info->prox_dom;
+		node_id = pxm_to_node(info->prox_dom);
+		if (node_id == NUMA_NO_NODE) {
+			pr_warn("controller at %pa: proximity domain %u has no NUMA node, skipping\n",
+				&ctrl->addr, info->prox_dom);
+			cbqri_controller_destroy(ctrl);
+			return -ENODEV;
+		}
+		/*
+		 * cbqri_resctrl_dom tracks a single hw_ctrl per domain, so a
+		 * second BC sharing the same proximity domain would be
+		 * silently dropped when the resctrl glue resolves the cpu to
+		 * an existing domain. Reject the duplicate at register time
+		 * to keep the failure mode visible.
+		 */
+		list_for_each_entry(other, &cbqri_controllers, list) {
+			if (other->type != CBQRI_CONTROLLER_TYPE_BANDWIDTH)
+				continue;
+			if (other->mem.prox_dom != info->prox_dom)
+				continue;
+			pr_warn("controller at %pa: proximity domain %u already claimed by %pa, skipping\n",
+				&ctrl->addr, info->prox_dom, &other->addr);
+			cbqri_controller_destroy(ctrl);
+			return -EEXIST;
+		}
+		cpumask_copy(&ctrl->mem.cpu_mask, cpumask_of_node(node_id));
+		break;
+	}
 	default:
 		pr_warn("controller at %pa: unknown type %u, skipping\n",
 			&ctrl->addr, info->type);
diff --git a/drivers/resctrl/cbqri_internal.h b/drivers/resctrl/cbqri_internal.h
index 1d2007a0c15b..4f806689d503 100644
--- a/drivers/resctrl/cbqri_internal.h
+++ b/drivers/resctrl/cbqri_internal.h
@@ -9,13 +9,21 @@
 #include <linux/mutex.h>
 #include <linux/types.h>
 
-/* Capacity Controller (CC) MMIO register offsets. */
+/*
+ * Capacity Controller (CC) and Bandwidth Controller (BC) MMIO register offsets.
+ */
 #define CBQRI_CC_CAPABILITIES_OFF 0
 #define CBQRI_CC_MON_CTL_OFF      8
 #define CBQRI_CC_MON_CTL_VAL_OFF 16
 #define CBQRI_CC_ALLOC_CTL_OFF   24
 #define CBQRI_CC_BLOCK_MASK_OFF  32
 
+#define CBQRI_BC_CAPABILITIES_OFF 0
+#define CBQRI_BC_MON_CTL_OFF      8
+#define CBQRI_BC_MON_CTR_VAL_OFF 16
+#define CBQRI_BC_ALLOC_CTL_OFF   24
+#define CBQRI_BC_BW_ALLOC_OFF    32
+
 /*
  * Smallest MMIO span the driver actually accesses: highest defined
  * register offset (0x20) plus the 8-byte register width. Used by
@@ -29,6 +37,11 @@
 #define CBQRI_CC_CAPABILITIES_VER_MAJOR_MASK  GENMASK_ULL(7, 4)
 #define CBQRI_CC_CAPABILITIES_NCBLKS_MASK     GENMASK_ULL(23, 8)
 
+#define CBQRI_BC_CAPABILITIES_VER_MINOR_MASK  GENMASK_ULL(3, 0)
+#define CBQRI_BC_CAPABILITIES_VER_MAJOR_MASK  GENMASK_ULL(7, 4)
+#define CBQRI_BC_CAPABILITIES_NBWBLKS_MASK    GENMASK_ULL(23, 8)
+#define CBQRI_BC_CAPABILITIES_MRBWB_MASK      GENMASK_ULL(47, 32)
+
 /*
  * CC and BC control and mon registers are 64-bit. Keep every field mask
  * GENMASK_ULL so FIELD_MODIFY() or ~mask on a u64 register never
@@ -42,14 +55,22 @@
 #define CBQRI_CONTROL_REGISTERS_RCID_MASK    GENMASK_ULL(19, 8)
 #define CBQRI_CONTROL_REGISTERS_STATUS_MASK  GENMASK_ULL(38, 32)
 #define CBQRI_CONTROL_REGISTERS_BUSY_MASK    GENMASK_ULL(39, 39)
+#define CBQRI_CONTROL_REGISTERS_RBWB_MASK    GENMASK_ULL(15, 0)
+#define CBQRI_CONTROL_REGISTERS_MWEIGHT_MASK GENMASK_ULL(27, 20)
 
 #define CBQRI_CC_ALLOC_CTL_OP_CONFIG_LIMIT 1
 #define CBQRI_CC_ALLOC_CTL_OP_READ_LIMIT   2
 #define CBQRI_CC_ALLOC_CTL_STATUS_SUCCESS  1
 
+#define CBQRI_BC_ALLOC_CTL_OP_CONFIG_LIMIT 1
+#define CBQRI_BC_ALLOC_CTL_OP_READ_LIMIT   2
+#define CBQRI_BC_ALLOC_CTL_STATUS_SUCCESS  1
+
 #define CBQRI_CC_MON_CTL_OP_CONFIG_EVENT 1
 #define CBQRI_CC_MON_CTL_OP_READ_COUNTER 2
 
+#define CBQRI_BC_MON_CTL_OP_READ_COUNTER 2
+
 /* mon_ctl field masks (CC and BC share an identical OP/MCID/EVT_ID/STATUS layout) */
 #define CBQRI_MON_CTL_OP_MASK        GENMASK_ULL(4, 0)
 #define CBQRI_MON_CTL_MCID_MASK      GENMASK_ULL(19, 8)
@@ -67,6 +88,14 @@ struct riscv_cbqri_capacity_caps {
 	bool supports_alloc_at_code;
 };
 
+/* Bandwidth Controller hardware capabilities */
+struct riscv_cbqri_bandwidth_caps {
+	u16 nbwblks; /* number of bandwidth blocks */
+	u16 mrbwb;   /* max reserved bw blocks */
+
+	bool supports_alloc_at_code;
+};
+
 /**
  * enum cbqri_at - capacity controller access type for CDP
  * @CBQRI_AT_DATA: data access (CBQRI Table 1, AT=0)
@@ -115,6 +144,7 @@ struct cbqri_controller {
 	int ver_major;
 	int ver_minor;
 
+	struct riscv_cbqri_bandwidth_caps bc;
 	struct riscv_cbqri_capacity_caps cc;
 
 	bool alloc_capable;
@@ -126,6 +156,15 @@ struct cbqri_controller {
 	u32 rcid_count;
 	u32 mcid_count;
 
+	/*
+	 * Per-RCID cache of the most recent Rbwb / Mweight values applied
+	 * via CONFIG_LIMIT. bc_bw_alloc packs both fields into one register,
+	 * so cbqri_apply_bc_field() seeds both halves from the authoritative
+	 * cache before CONFIG_LIMIT.
+	 */
+	u16 *rbwb_cache;
+	u8  *mweight_cache;
+
 	struct list_head list;
 
 	struct cache_controller {
@@ -135,6 +174,12 @@ struct cbqri_controller {
 		/* Unique Cache ID from the PPTT table's Cache Type Structure */
 		u32 cache_id;
 	} cache;
+
+	struct mem_controller {
+		/* Proximity Domain from SRAT table Memory Affinity Controller */
+		u32 prox_dom;
+		struct cpumask cpu_mask;
+	} mem;
 };
 
 extern struct list_head cbqri_controllers;
@@ -152,4 +197,14 @@ int cbqri_mon_op(struct cbqri_controller *ctrl, int reg_offset,
 
 int cbqri_init_mon_counters(struct cbqri_controller *ctrl);
 
+int cbqri_apply_rbwb(struct cbqri_controller *ctrl, u32 closid,
+		     u64 rbwb, bool check_sum);
+
+int cbqri_apply_mweight_config(struct cbqri_controller *ctrl, u32 closid,
+			       u64 mweight);
+
+int cbqri_read_rbwb(struct cbqri_controller *ctrl, u32 closid, u64 *rbwb_out);
+
+int cbqri_read_mweight(struct cbqri_controller *ctrl, u32 closid, u64 *mweight_out);
+
 #endif /* _DRIVERS_RESCTRL_CBQRI_INTERNAL_H */

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:04 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:04 -0700
Subject: [PATCH RFC v6 10/18] riscv_cbqri: Add bandwidth controller
 monitoring device ops
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-10-baf00f50028a@kernel.org>

Add the BC monitoring primitives. cbqri_init_bc_mon_counters() pre-arms
each MCID with the TOTAL_READ_WRITE event and allocates the per-MCID
software accumulator (struct cbqri_bc_mon_state) so subsequent reads can
extend the 62-bit hardware counter to the 64-bit byte total resctrl
expects. cbqri_bc_mon_overflow() recovers a single-wrap delta. The OVF
bit signals multi-wrap and is the caller's concern.

cbqri_find_only_mon_bc() returns NULL when zero or more than one
mon-capable BC is present. A BC's counter can only accurately back L3
mbm_total_bytes when every memory request flows through that BC.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 drivers/resctrl/cbqri_devices.c  | 75 ++++++++++++++++++++++++++++++++++++++++
 drivers/resctrl/cbqri_internal.h | 37 ++++++++++++++++++++
 2 files changed, 112 insertions(+)

diff --git a/drivers/resctrl/cbqri_devices.c b/drivers/resctrl/cbqri_devices.c
index 6093706b1ec4..b1a6ce35042a 100644
--- a/drivers/resctrl/cbqri_devices.c
+++ b/drivers/resctrl/cbqri_devices.c
@@ -905,6 +905,80 @@ int cbqri_init_mon_counters(struct cbqri_controller *ctrl)
 	return 0;
 }
 
+/*
+ * 62-bit BC counter delta. Inputs must be pre-masked to
+ * CBQRI_BC_MON_CTR_VAL_CTR_MASK. The shift promotes the modular
+ * subtraction into 64-bit so a single wrap (cur < prev) yields the
+ * correct delta. Multi-wrap is handled by the caller via the
+ * hardware OVF bit (CBQRI 4.3). This function only needs to recover
+ * from at most one wrap.
+ */
+u64 cbqri_bc_mon_overflow(u64 prev_ctr, u64 cur_ctr)
+{
+	const unsigned int shift = 64 - 62;
+	u64 chunks = (cur_ctr << shift) - (prev_ctr << shift);
+
+	return chunks >> shift;
+}
+
+/*
+ * Allocate the per-MCID software accumulator and pre-arm every MCID
+ * with TOTAL_READ_WRITE so subsequent reads just snapshot the live
+ * counter.
+ *
+ * Caller responsibility: serialize concurrent invocations on the same
+ * single mon-capable BC (cbqri_resctrl uses cbqri_domain_list_lock for
+ * this).
+ */
+int cbqri_init_bc_mon_counters(struct cbqri_controller *bc)
+{
+	int i, err;
+
+	if (bc->mbm_total_states)
+		return 0;
+
+	bc->mbm_total_states = kcalloc(bc->mcid_count,
+				       sizeof(*bc->mbm_total_states),
+				       GFP_KERNEL);
+	if (!bc->mbm_total_states)
+		return -ENOMEM;
+
+	for (i = 0; i < bc->mcid_count; i++) {
+		mutex_lock(&bc->lock);
+		err = cbqri_mon_op(bc, CBQRI_BC_MON_CTL_OFF,
+				   CBQRI_BC_MON_CTL_OP_CONFIG_EVENT,
+				   i, CBQRI_BC_EVT_ID_TOTAL_READ_WRITE, NULL);
+		mutex_unlock(&bc->lock);
+		if (err) {
+			kfree(bc->mbm_total_states);
+			bc->mbm_total_states = NULL;
+			return err;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Return the single mon-capable BC, NULL if zero or more than one. BC
+ * counters can only accurately surface as L3 mbm_total_bytes if every memory
+ * request flows through the same BC.
+ */
+struct cbqri_controller *cbqri_find_only_mon_bc(void)
+{
+	struct cbqri_controller *ctrl, *only_bc = NULL;
+
+	list_for_each_entry(ctrl, &cbqri_controllers, list) {
+		if (ctrl->type != CBQRI_CONTROLLER_TYPE_BANDWIDTH)
+			continue;
+		if (!ctrl->mon_capable)
+			continue;
+		if (only_bc)
+			return NULL;
+		only_bc = ctrl;
+	}
+	return only_bc;
+}
+
 void cbqri_controller_destroy(struct cbqri_controller *ctrl)
 {
 	/*
@@ -916,6 +990,7 @@ void cbqri_controller_destroy(struct cbqri_controller *ctrl)
 		iounmap(ctrl->base);
 		release_mem_region(ctrl->addr, ctrl->size);
 	}
+	kfree(ctrl->mbm_total_states);
 	kfree(ctrl->mweight_cache);
 	kfree(ctrl->rbwb_cache);
 	kfree(ctrl);
diff --git a/drivers/resctrl/cbqri_internal.h b/drivers/resctrl/cbqri_internal.h
index 4f806689d503..68a40f846f40 100644
--- a/drivers/resctrl/cbqri_internal.h
+++ b/drivers/resctrl/cbqri_internal.h
@@ -69,8 +69,17 @@
 #define CBQRI_CC_MON_CTL_OP_CONFIG_EVENT 1
 #define CBQRI_CC_MON_CTL_OP_READ_COUNTER 2
 
+#define CBQRI_BC_MON_CTL_OP_CONFIG_EVENT 1
 #define CBQRI_BC_MON_CTL_OP_READ_COUNTER 2
 
+/* Bandwidth usage monitoring event IDs (CBQRI spec Table 10) */
+#define CBQRI_BC_EVT_ID_TOTAL_READ_WRITE  1
+
+/* bc_mon_ctr_val layout (CBQRI spec section 4.3, Figure 7) */
+#define CBQRI_BC_MON_CTR_VAL_CTR_MASK    GENMASK_ULL(61, 0)
+#define CBQRI_BC_MON_CTR_VAL_INVALID     BIT_ULL(62)
+#define CBQRI_BC_MON_CTR_VAL_OVF         BIT_ULL(63)
+
 /* mon_ctl field masks (CC and BC share an identical OP/MCID/EVT_ID/STATUS layout) */
 #define CBQRI_MON_CTL_OP_MASK        GENMASK_ULL(4, 0)
 #define CBQRI_MON_CTL_MCID_MASK      GENMASK_ULL(19, 8)
@@ -96,6 +105,19 @@ struct riscv_cbqri_bandwidth_caps {
 	bool supports_alloc_at_code;
 };
 
+/**
+ * struct cbqri_bc_mon_state - per-MCID software accumulator for BC bandwidth
+ * @prev_ctr: previous 62-bit hardware snapshot (already masked to CTR field)
+ * @chunks:   accumulated 64-bit byte total across hardware wraparounds
+ *
+ * Updated in resctrl_arch_rmid_read() under cbqri_controller::lock and
+ * zeroed by resctrl_arch_reset_rmid().
+ */
+struct cbqri_bc_mon_state {
+	u64 prev_ctr;
+	u64 chunks;
+};
+
 /**
  * enum cbqri_at - capacity controller access type for CDP
  * @CBQRI_AT_DATA: data access (CBQRI Table 1, AT=0)
@@ -165,6 +187,15 @@ struct cbqri_controller {
 	u16 *rbwb_cache;
 	u8  *mweight_cache;
 
+	/*
+	 * Per-MCID 64-bit software accumulator for the BC's mbm_total_bytes
+	 * event. Allocated by cbqri_init_bc_mon_counters() when this BC is
+	 * paired with an L3 monitoring domain, sized by ->mcid_count. NULL
+	 * on capacity controllers and on BCs that are not mon-paired.
+	 * Protected by ->lock along with the surrounding MMIO sequence.
+	 */
+	struct cbqri_bc_mon_state *mbm_total_states;
+
 	struct list_head list;
 
 	struct cache_controller {
@@ -207,4 +238,10 @@ int cbqri_read_rbwb(struct cbqri_controller *ctrl, u32 closid, u64 *rbwb_out);
 
 int cbqri_read_mweight(struct cbqri_controller *ctrl, u32 closid, u64 *mweight_out);
 
+u64 cbqri_bc_mon_overflow(u64 prev_ctr, u64 cur_ctr);
+
+int cbqri_init_bc_mon_counters(struct cbqri_controller *bc);
+
+struct cbqri_controller *cbqri_find_only_mon_bc(void);
+
 #endif /* _DRIVERS_RESCTRL_CBQRI_INTERNAL_H */

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:07 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:07 -0700
Subject: [PATCH RFC v6 13/18] riscv_cbqri: resctrl: Add MB_MIN bandwidth
 allocation via Rbwb
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-13-baf00f50028a@kernel.org>

Add bandwidth allocation through Rbwb (reserved bandwidth blocks)
exposed as the MB_MIN resource. Rbwb's sum constraint does not fit MBA's
percentage cap, so MB_MIN lands as a new RDT_RESOURCE_* rather than
masquerading as MBA.

The sum(Rbwb) <= MRBWB (max resv bw blocks) invariant from the CBQRI
spec is enforced at schemata-write time using a per-RCID software cache
under ctrl->lock. -EINVAL on overflow, matching the existing
schemata-write rejection convention.

Reset gives RCID 0 the remaining MRBWB budget after reserving 1 block
per other RCID. default_to_min=true on MB_MIN so mkdir cannot overflow
the sum constraint.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 drivers/resctrl/cbqri_resctrl.c | 219 ++++++++++++++++++++++++++++++++++++----
 1 file changed, 197 insertions(+), 22 deletions(-)

diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
index f379058b0114..1d312004b07d 100644
--- a/drivers/resctrl/cbqri_resctrl.c
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -363,6 +363,9 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	case RDT_RESOURCE_L2:
 	case RDT_RESOURCE_L3:
 		return cbqri_apply_cache_config_dom(dom, r, closid, t, cfg_val);
+	case RDT_RESOURCE_MB_MIN:
+		/* sum(Rbwb) <= MRBWB validation runs inside cbqri_apply_rbwb(). */
+		return cbqri_apply_rbwb(dom->hw_ctrl, closid, cfg_val, true);
 	default:
 		return -EINVAL;
 	}
@@ -415,6 +418,14 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 		if (err < 0)
 			val = resctrl_get_default_ctrl(r);
 		break;
+	case RDT_RESOURCE_MB_MIN: {
+		u64 rbwb;
+
+		err = cbqri_read_rbwb(ctrl, closid, &rbwb);
+		if (err == 0)
+			val = (u32)rbwb;
+		break;
+	}
 	default:
 		break;
 	}
@@ -422,9 +433,22 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	return val;
 }
 
+/*
+ * RCID 0 carries the remaining MRBWB after every other RCID is seeded with
+ * the minimum Rbwb of 1. cbqri_probe_bc() rejects a bandwidth controller
+ * with mrbwb < rcid_count, so this subtraction cannot underflow.
+ */
+static u64 cbqri_rcid0_rbwb(struct cbqri_controller *ctrl)
+{
+	if (WARN_ON_ONCE(ctrl->bc.mrbwb < ctrl->rcid_count))
+		return 1;
+	return ctrl->bc.mrbwb - (ctrl->rcid_count - 1);
+}
+
 void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 {
 	struct cbqri_resctrl_res *hw_res;
+	struct cbqri_resctrl_dom *dom;
 	struct rdt_ctrl_domain *d;
 	enum resctrl_conf_type t;
 	u32 default_ctrl;
@@ -439,15 +463,41 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 		return;
 
 	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
-		for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
-			for (t = 0; t < CDP_NUM_TYPES; t++) {
+		dom = container_of(d, struct cbqri_resctrl_dom,
+				   resctrl_ctrl_dom);
+
+		switch (r->rid) {
+		case RDT_RESOURCE_MB_MIN:
+			/*
+			 * CBQRI section 4.5: Rbwb >= 1, sum(Rbwb) <= MRBWB.
+			 * Walk N-1..1 first so RCID 0 lands last with the
+			 * remaining budget.
+			 */
+			for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
+				u32 rcid = (i + 1) % hw_res->ctrl->rcid_count;
+				u64 rbwb = (rcid == 0) ?
+					cbqri_rcid0_rbwb(dom->hw_ctrl) : 1;
 				int rerr;
 
-				rerr = resctrl_arch_update_one(r, d, i, t, default_ctrl);
+				rerr = cbqri_apply_rbwb(dom->hw_ctrl, rcid, rbwb, false);
 				if (rerr)
-					pr_err_ratelimited("rid=%d reset RCID %u type %u failed (%d)\n",
-							   r->rid, i, t, rerr);
+					pr_err_ratelimited("RBWB reset RCID %u failed (%d)\n",
+							   rcid, rerr);
+			}
+			break;
+		default:
+			for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
+				for (t = 0; t < CDP_NUM_TYPES; t++) {
+					int rerr;
+
+					rerr = resctrl_arch_update_one(r, d, i, t,
+								       default_ctrl);
+					if (rerr)
+						pr_err_ratelimited("rid=%d reset RCID %u type %u failed (%d)\n",
+								   r->rid, i, t, rerr);
+				}
 			}
+			break;
 		}
 	}
 }
@@ -472,26 +522,51 @@ static struct rdt_ctrl_domain *cbqri_new_domain(struct cbqri_controller *ctrl)
 static int cbqri_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
 {
 	struct cbqri_resctrl_res *hw_res;
+	struct cbqri_resctrl_dom *dom;
 	enum resctrl_conf_type t;
 	int err = 0;
+	u64 rbwb;
 	int i;
 
 	hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+	dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
 
 	for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
 		/*
-		 * Seed both DATA and CODE staged slots so a later mount
-		 * with -o cdp does not see stale CODE values.
-		 * On non-AT controllers cbqri_cc_alloc_op() masks AT to 0
-		 * so all three iterations land on the same hardware state.
-		 * The redundant writes are harmless.
+		 * For MB_MIN walk, RCIDs 1..N-1 then RCID 0 last so the sum
+		 * doesn't exceed MRBWB during the walk.
 		 */
-		for (t = 0; t < CDP_NUM_TYPES; t++) {
-			err = resctrl_arch_update_one(r, d, i, t,
-						      resctrl_get_default_ctrl(r));
-			if (err)
-				return err;
+		u32 rcid = (r->rid == RDT_RESOURCE_MB_MIN) ?
+				((i + 1) % hw_res->ctrl->rcid_count) : i;
+
+		switch (r->rid) {
+		case RDT_RESOURCE_MB_MIN:
+			/*
+			 * CBQRI section 4.5: Rbwb >= 1, sum(Rbwb) <= MRBWB.
+			 * RCID 0 takes the remaining budget.
+			 */
+			rbwb = (rcid == 0) ? cbqri_rcid0_rbwb(dom->hw_ctrl) : 1;
+
+			err = cbqri_apply_rbwb(dom->hw_ctrl, rcid, rbwb, false);
+			break;
+		default:
+			/*
+			 * Seed both DATA and CODE staged slots so a later
+			 * mount with -o cdp does not see stale CODE values.
+			 * On non-AT controllers cbqri_cc_alloc_op() masks
+			 * AT to 0, so all three iterations land on the same
+			 * hardware state. The redundant writes are harmless.
+			 */
+			for (t = 0; t < CDP_NUM_TYPES; t++) {
+				err = resctrl_arch_update_one(r, d, i, t,
+							      resctrl_get_default_ctrl(r));
+				if (err)
+					break;
+			}
+			break;
 		}
+		if (err)
+			return err;
 	}
 	return 0;
 }
@@ -590,6 +665,31 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 			res->mon_capable = true;
 		}
 		break;
+
+	case RDT_RESOURCE_MB_MIN:
+		res->name = "MB_MIN";
+		res->schema_fmt = RESCTRL_SCHEMA_RANGE;
+		/*
+		 * resctrl requires a cache scope for MBA-style domains.
+		 * Use L3 as a proxy until the resctrl supports non-cache
+		 * scopes for bandwidth resources.
+		 */
+		res->ctrl_scope = RESCTRL_L3_CACHE;
+		/* Rbwb is an integer block count, not a percentage. No MBA delay_linear. */
+		res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+		res->membw.min_bw = 1;
+		res->membw.max_bw = ctrl->bc.mrbwb;
+		res->membw.bw_gran = 1;
+		/*
+		 * CBQRI section 4.5 caps sum(Rbwb) <= MRBWB. Default new
+		 * groups to min_bw so mkdir cannot overflow that sum.
+		 */
+		res->membw.default_to_min = true;
+		res->alloc_capable = ctrl->alloc_capable;
+		INIT_LIST_HEAD(&res->ctrl_domains);
+		INIT_LIST_HEAD(&res->mon_domains);
+		break;
+
 	default:
 		break;
 	}
@@ -597,6 +697,36 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 	return 0;
 }
 
+/*
+ * Pick one BC to back MB_MIN.  Multiple BCs must agree on rcid_count
+ * and mrbwb.  Mismatch is fatal because resctrl exposes a single set
+ * of caps per rid.
+ */
+static int cbqri_resctrl_pick_bw_alloc(void)
+{
+	struct cbqri_resctrl_res *mb_min = &cbqri_resctrl_resources[RDT_RESOURCE_MB_MIN];
+	struct cbqri_controller *ctrl;
+
+	list_for_each_entry(ctrl, &cbqri_controllers, list) {
+		if (ctrl->type != CBQRI_CONTROLLER_TYPE_BANDWIDTH)
+			continue;
+		if (!ctrl->alloc_capable)
+			continue;
+
+		if (mb_min->ctrl) {
+			if (mb_min->ctrl->rcid_count != ctrl->rcid_count ||
+			    mb_min->ctrl->bc.mrbwb != ctrl->bc.mrbwb) {
+				pr_err("BW controllers have mismatched capabilities\n");
+				return -EINVAL;
+			}
+			continue;
+		}
+
+		mb_min->ctrl = ctrl;
+	}
+
+	return 0;
+}
 static void cbqri_resctrl_accumulate_caps(void)
 {
 	struct cbqri_controller *l3_ctrl;
@@ -806,6 +936,37 @@ static int cbqri_attach_cpu_to_cap_ctrl(struct cbqri_controller *ctrl,
 	return err;
 }
 
+static int cbqri_attach_cpu_to_one_bw_res(struct cbqri_controller *ctrl,
+					  enum resctrl_res_level rid,
+					  unsigned int cpu)
+{
+	struct cbqri_resctrl_res *hw_res = &cbqri_resctrl_resources[rid];
+	struct rdt_resource *res = &hw_res->resctrl_res;
+	struct rdt_ctrl_domain *domain;
+	int dom_id = ctrl->mem.prox_dom;
+
+	if (!hw_res->ctrl)
+		return 0;
+
+	domain = cbqri_find_ctrl_domain(&res->ctrl_domains, dom_id);
+	if (domain) {
+		cpumask_set_cpu(cpu, &domain->hdr.cpu_mask);
+		return 0;
+	}
+
+	domain = cbqri_create_ctrl_domain(ctrl, res, cpu, dom_id);
+	if (IS_ERR(domain))
+		return PTR_ERR(domain);
+
+	return 0;
+}
+
+static int cbqri_attach_cpu_to_bw_ctrl(struct cbqri_controller *ctrl,
+				       unsigned int cpu)
+{
+	return cbqri_attach_cpu_to_one_bw_res(ctrl, RDT_RESOURCE_MB_MIN, cpu);
+}
+
 static void cbqri_detach_cpu_from_l3_mon(struct rdt_resource *res,
 					 unsigned int cpu)
 {
@@ -893,14 +1054,24 @@ static int cbqri_attach_cpu_to_all_ctrls(unsigned int cpu)
 	lockdep_assert_held(&cbqri_domain_list_lock);
 
 	list_for_each_entry(ctrl, &cbqri_controllers, list) {
-		if (ctrl->type != CBQRI_CONTROLLER_TYPE_CAPACITY)
-			continue;
-		if (!cpumask_test_cpu(cpu, &ctrl->cache.cpu_mask))
-			continue;
-		if (!ctrl->alloc_capable)
+		switch (ctrl->type) {
+		case CBQRI_CONTROLLER_TYPE_CAPACITY:
+			if (!cpumask_test_cpu(cpu, &ctrl->cache.cpu_mask))
+				continue;
+			if (!ctrl->alloc_capable)
+				continue;
+			err = cbqri_attach_cpu_to_cap_ctrl(ctrl, cpu);
+			break;
+		case CBQRI_CONTROLLER_TYPE_BANDWIDTH:
+			if (!cpumask_test_cpu(cpu, &ctrl->mem.cpu_mask))
+				continue;
+			if (!ctrl->alloc_capable)
+				continue;
+			err = cbqri_attach_cpu_to_bw_ctrl(ctrl, cpu);
+			break;
+		default:
 			continue;
-
-		err = cbqri_attach_cpu_to_cap_ctrl(ctrl, cpu);
+		}
 		if (err) {
 			cbqri_detach_cpu_from_all_ctrls(cpu);
 			break;
@@ -945,6 +1116,10 @@ static int cbqri_resctrl_setup(void)
 	if (err)
 		return err;
 
+	err = cbqri_resctrl_pick_bw_alloc();
+	if (err)
+		return err;
+
 	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
 		err = cbqri_resctrl_control_init(&cbqri_resctrl_resources[rid]);
 		if (err)

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:05 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:05 -0700
Subject: [PATCH RFC v6 11/18] riscv_cbqri: resctrl: Add cache allocation
 via capacity block mask
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-11-baf00f50028a@kernel.org>

Wire CBQRI capacity controllers into resctrl as RDT_RESOURCE_L2 and
RDT_RESOURCE_L3 schemata.

Mismatched CC caps at the same cache level are treated as a fatal
configuration error since fs/resctrl exposes a single per-rid cap
set. Domains are created lazily in the cpuhp online callback so
cpu_mask reflects only currently online CPUs.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 MAINTAINERS                      |   2 +
 arch/riscv/Kconfig               |   1 +
 arch/riscv/include/asm/resctrl.h | 152 ++++++++
 drivers/resctrl/Kconfig          |   4 +
 drivers/resctrl/Makefile         |   1 +
 drivers/resctrl/cbqri_resctrl.c  | 777 +++++++++++++++++++++++++++++++++++++++
 6 files changed, 937 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 24bdc04fea7a..7821dd5159cb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23023,9 +23023,11 @@ R:	yunhui cui <cuiyunhui at bytedance.com>
 L:	linux-riscv at lists.infradead.org
 S:	Supported
 F:	arch/riscv/include/asm/qos.h
+F:	arch/riscv/include/asm/resctrl.h
 F:	arch/riscv/kernel/qos.c
 F:	drivers/resctrl/cbqri_devices.c
 F:	drivers/resctrl/cbqri_internal.h
+F:	drivers/resctrl/cbqri_resctrl.c
 F:	include/linux/riscv_cbqri.h
 
 RISC-V RPMI AND MPXY DRIVERS
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 6abbb21f3a0d..390353a6153a 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -595,6 +595,7 @@ config RISCV_ISA_SSQOSID
 	bool "Ssqosid extension support for supervisor mode Quality of Service ID"
 	depends on 64BIT
 	default n
+	select ARCH_HAS_CPU_RESCTRL
 	help
 	  Adds support for the Ssqosid ISA extension (Supervisor-mode
 	  Quality of Service ID).
diff --git a/arch/riscv/include/asm/resctrl.h b/arch/riscv/include/asm/resctrl.h
new file mode 100644
index 000000000000..282b5b59e3ee
--- /dev/null
+++ b/arch/riscv/include/asm/resctrl.h
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef _ASM_RISCV_RESCTRL_H
+#define _ASM_RISCV_RESCTRL_H
+
+#include <linux/resctrl_types.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+
+#include <asm/qos.h>
+
+struct rdt_resource;
+
+/*
+ * Sentinel "no CLOSID assigned" used by resctrl_arch_rmid_idx_decode().
+ * fs/resctrl treats this opaquely. CBQRI uses MCID directly as the linear
+ * rmid index, so closid is unused on decode.
+ */
+#define RISCV_RESCTRL_EMPTY_CLOSID	((u32)~0)
+
+/*
+ * Terminology mapping between x86 (Intel RDT/AMD QoS) and RISC-V:
+ *
+ *  CLOSID on x86 is RCID on RISC-V
+ *    RMID on x86 is MCID on RISC-V
+ *     CDP on x86 is AT (access type) on RISC-V
+ *
+ * Each fast-path arch entry point below is the RISC-V realization of the
+ * generic contract documented in <linux/resctrl.h>. Comments here describe
+ * only the RISC-V-specific behavior (srmcfg encoding, CBQRI controller
+ * lookup, MCID-as-index policy).
+ */
+
+/**
+ * resctrl_arch_alloc_capable() - any CBQRI controller exposes resctrl alloc
+ *
+ * Returns true once at least one CBQRI controller has successfully probed for
+ * a resctrl-exposed allocation feature (cache capacity or memory bandwidth).
+ * Only meaningful after cbqri_resctrl_setup() runs at late_initcall.
+ */
+bool resctrl_arch_alloc_capable(void);
+
+/**
+ * resctrl_arch_mon_capable() - any CBQRI controller exposes resctrl monitoring
+ *
+ * Returns true once at least one CBQRI controller has successfully probed a
+ * monitoring event wired through resctrl (L3 occupancy or L3 mbm_total_bytes).
+ */
+bool resctrl_arch_mon_capable(void);
+
+/**
+ * resctrl_arch_rmid_idx_encode() - encode (RCID, MCID) into a linear index
+ * @closid: RCID (resource control id)
+ * @rmid:   MCID (monitoring counter id)
+ *
+ * RISC-V uses MCID directly as the linear index into per-RMID arrays
+ * managed by fs/resctrl, since CBQRI controllers admit any MCID for any
+ * RCID. closid is unused here. CDP is encoded via the AT field on each
+ * CBQRI op rather than via the index.
+ */
+u32  resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid);
+
+/**
+ * resctrl_arch_rmid_idx_decode() - inverse of resctrl_arch_rmid_idx_encode()
+ * @idx:    linear index
+ * @closid: out: always RISCV_RESCTRL_EMPTY_CLOSID
+ * @rmid:   out: the MCID that @idx encodes
+ */
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid);
+
+/**
+ * resctrl_arch_set_cpu_default_closid_rmid() - install per-CPU srmcfg default
+ * @cpu:    CPU number
+ * @closid: RCID to use when no task is matched
+ * @rmid:   MCID to use when no task is matched
+ *
+ * Sets the per-CPU cpu_srmcfg_default so __switch_to_srmcfg() can fall back
+ * to the CPU's default RCID/MCID for default-group tasks (those whose
+ * thread.srmcfg encodes to 0, i.e. closid == RESCTRL_RESERVED_CLOSID and
+ * rmid == RESCTRL_RESERVED_RMID). Implements resctrl allocation rule 2
+ * ("CPU default") on RISC-V.
+ */
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid);
+
+/**
+ * resctrl_arch_sched_in() - context-switch hook to install task RCID/MCID
+ * @tsk: the task being scheduled in
+ *
+ * Called from finish_task_switch() to write tsk->thread.srmcfg into the
+ * srmcfg CSR. Tasks tagged with RISCV_RESCTRL_EMPTY_CLOSID inherit the
+ * per-CPU default set via resctrl_arch_set_cpu_default_closid_rmid().
+ */
+void resctrl_arch_sched_in(struct task_struct *tsk);
+
+/**
+ * resctrl_arch_set_closid_rmid() - tag a task with an RCID/MCID
+ * @tsk:    task to tag
+ * @closid: RCID to install
+ * @rmid:   MCID to install
+ *
+ * Updates tsk->thread.srmcfg with the encoded (RCID, MCID) pair. The new
+ * value takes effect on the next resctrl_arch_sched_in() for this task.
+ */
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+
+/**
+ * resctrl_arch_match_closid() - test whether a task carries a given RCID
+ * @tsk:    task
+ * @closid: RCID
+ */
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid);
+
+/**
+ * resctrl_arch_match_rmid() - test whether a task carries a given (RCID, MCID)
+ * @tsk:    task
+ * @closid: RCID
+ * @rmid:   MCID
+ */
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid);
+
+/**
+ * resctrl_arch_mon_ctx_alloc() - allocate per-monitor-event arch context
+ * @r:     resctrl resource being monitored
+ * @evtid: which monitor event needs context
+ *
+ * Returns an opaque pointer that resctrl_arch_rmid_read() can use to find the
+ * CBQRI controller backing this event. CBQRI's BC bandwidth context is
+ * keyed off the resource's L3 monitoring domain rather than per-event state,
+ * so this implementation returns NULL.
+ */
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r, enum resctrl_event_id evtid);
+
+/**
+ * resctrl_arch_mon_ctx_free() - release context returned by mon_ctx_alloc()
+ * @r:            resctrl resource
+ * @evtid:        monitor event id
+ * @arch_mon_ctx: pointer returned by resctrl_arch_mon_ctx_alloc()
+ */
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r, enum resctrl_event_id evtid,
+			       void *arch_mon_ctx);
+
+static inline unsigned int resctrl_arch_round_mon_val(unsigned int val)
+{
+	return val;
+}
+
+/* Not needed for RISC-V */
+static inline void resctrl_arch_enable_mon(void) { }
+static inline void resctrl_arch_disable_mon(void) { }
+static inline void resctrl_arch_enable_alloc(void) { }
+static inline void resctrl_arch_disable_alloc(void) { }
+
+#endif /* _ASM_RISCV_RESCTRL_H */
diff --git a/drivers/resctrl/Kconfig b/drivers/resctrl/Kconfig
index d578bc7aed85..732aae26f8f8 100644
--- a/drivers/resctrl/Kconfig
+++ b/drivers/resctrl/Kconfig
@@ -57,3 +57,7 @@ config RISCV_CBQRI_DRIVER_DEBUG
 	  new platform; otherwise leave disabled to avoid log noise.
 
 endif
+
+config RISCV_CBQRI_RESCTRL_FS
+	bool
+	default y if RISCV_CBQRI_DRIVER && RESCTRL_FS
diff --git a/drivers/resctrl/Makefile b/drivers/resctrl/Makefile
index 28085036d895..ed737b4461b9 100644
--- a/drivers/resctrl/Makefile
+++ b/drivers/resctrl/Makefile
@@ -6,5 +6,6 @@ ccflags-$(CONFIG_ARM64_MPAM_DRIVER_DEBUG)	+= -DDEBUG
 
 obj-$(CONFIG_RISCV_CBQRI_DRIVER)		+= cbqri.o
 cbqri-y						+= cbqri_devices.o
+cbqri-$(CONFIG_RISCV_CBQRI_RESCTRL_FS)		+= cbqri_resctrl.o
 
 ccflags-$(CONFIG_RISCV_CBQRI_DRIVER_DEBUG)	+= -DDEBUG
diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
new file mode 100644
index 000000000000..fb6d82aa3ffc
--- /dev/null
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -0,0 +1,777 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__
+
+#include <linux/bitfield.h>
+#include <linux/cacheinfo.h>
+#include <linux/riscv_cbqri.h>
+#include <linux/cpu.h>
+#include <linux/cpufeature.h>
+#include <linux/cpuhotplug.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/resctrl.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <asm/csr.h>
+#include <asm/qos.h>
+
+#include "cbqri_internal.h"
+
+struct cbqri_resctrl_res {
+	struct cbqri_controller *ctrl;
+	struct rdt_resource     resctrl_res;
+	bool                    cdp_enabled;
+};
+
+struct cbqri_resctrl_dom {
+	struct rdt_ctrl_domain  resctrl_ctrl_dom;
+	struct cbqri_controller *hw_ctrl;
+};
+
+static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
+
+static bool exposed_alloc_capable;
+
+/* Protects ctrl_domain list mutations across CPU hotplug. */
+static DEFINE_MUTEX(cbqri_domain_list_lock);
+
+static struct rdt_ctrl_domain *
+cbqri_find_ctrl_domain(struct list_head *h, int id)
+{
+	struct rdt_domain_hdr *hdr = resctrl_find_domain(h, id, NULL);
+
+	return hdr ? container_of(hdr, struct rdt_ctrl_domain, hdr) : NULL;
+}
+
+static int cbqri_apply_cache_config_dom(struct cbqri_resctrl_dom *hw_dom,
+					struct rdt_resource *r,
+					u32 closid, enum resctrl_conf_type t,
+					u64 cbm)
+{
+	struct cbqri_resctrl_res *hw_res =
+		container_of(r, struct cbqri_resctrl_res, resctrl_res);
+	struct cbqri_cc_config cfg = {
+		.cbm = cbm,
+		.at = (t == CDP_CODE) ? CBQRI_AT_CODE : CBQRI_AT_DATA,
+		.cdp_enabled = hw_res->cdp_enabled,
+	};
+
+	return cbqri_apply_cache_config(hw_dom->hw_ctrl, closid, &cfg);
+}
+
+bool resctrl_arch_alloc_capable(void)
+{
+	return exposed_alloc_capable;
+}
+
+bool resctrl_arch_mon_capable(void)
+{
+	return false;
+}
+
+bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
+{
+	if (rid != RDT_RESOURCE_L2 && rid != RDT_RESOURCE_L3)
+		return false;
+	return cbqri_resctrl_resources[rid].cdp_enabled;
+}
+
+int resctrl_arch_set_cdp_enabled(enum resctrl_res_level rid, bool enable)
+{
+	struct cbqri_resctrl_res *cbqri_res;
+
+	if (rid != RDT_RESOURCE_L2 && rid != RDT_RESOURCE_L3)
+		return -ENODEV;
+
+	cbqri_res = &cbqri_resctrl_resources[rid];
+	if (!cbqri_res->resctrl_res.cdp_capable)
+		return -ENODEV;
+
+	cbqri_res->cdp_enabled = enable;
+	return 0;
+}
+
+struct rdt_resource *resctrl_arch_get_resource(enum resctrl_res_level l)
+{
+	if (l >= RDT_NUM_RESOURCES)
+		return NULL;
+
+	return &cbqri_resctrl_resources[l].resctrl_res;
+}
+
+/*
+ * fs/resctrl unconditionally references the symbols below before checking
+ * mon_capable. They are stubs for features CBQRI does not yet support.
+ */
+bool resctrl_arch_is_evt_configurable(enum resctrl_event_id evt)
+{
+	return false;
+}
+
+void *resctrl_arch_mon_ctx_alloc(struct rdt_resource *r,
+				 enum resctrl_event_id evtid)
+{
+	return NULL;
+}
+
+void resctrl_arch_mon_ctx_free(struct rdt_resource *r,
+			       enum resctrl_event_id evtid, void *arch_mon_ctx)
+{
+}
+
+void resctrl_arch_config_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+			      enum resctrl_event_id evtid, u32 rmid, u32 closid,
+			      u32 cntr_id, bool assign)
+{
+}
+
+int resctrl_arch_cntr_read(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+			   u32 unused, u32 rmid, int cntr_id,
+			   enum resctrl_event_id eventid, u64 *val)
+{
+	return -EOPNOTSUPP;
+}
+
+bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r)
+{
+	return false;
+}
+
+int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable)
+{
+	return -EOPNOTSUPP;
+}
+
+void resctrl_arch_reset_cntr(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+			     u32 unused, u32 rmid, int cntr_id,
+			     enum resctrl_event_id eventid)
+{
+}
+
+bool resctrl_arch_get_io_alloc_enabled(struct rdt_resource *r)
+{
+	return false;
+}
+
+int resctrl_arch_io_alloc_enable(struct rdt_resource *r, bool enable)
+{
+	return -EOPNOTSUPP;
+}
+
+void resctrl_arch_mon_event_config_read(void *info)
+{
+}
+
+void resctrl_arch_mon_event_config_write(void *info)
+{
+}
+
+void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
+{
+}
+
+void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+			     u32 unused, u32 rmid, enum resctrl_event_id eventid)
+{
+}
+
+int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
+			   u32 closid, u32 rmid, enum resctrl_event_id eventid,
+			   void *arch_priv, u64 *val, void *arch_mon_ctx)
+{
+	return -ENODATA;
+}
+
+/*
+ * Note about terminology between x86 (Intel RDT/AMD QoS) and RISC-V:
+ *   CLOSID on x86 is RCID on RISC-V
+ *     RMID on x86 is MCID on RISC-V
+ */
+u32 resctrl_arch_get_num_closid(struct rdt_resource *res)
+{
+	struct cbqri_resctrl_res *hw_res;
+
+	hw_res = container_of(res, struct cbqri_resctrl_res, resctrl_res);
+
+	if (!hw_res->ctrl)
+		return 0;
+
+	return hw_res->ctrl->rcid_count;
+}
+
+u32 resctrl_arch_system_num_rmid_idx(void)
+{
+	return 1;
+}
+
+u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
+{
+	return rmid;
+}
+
+void resctrl_arch_rmid_idx_decode(u32 idx, u32 *closid, u32 *rmid)
+{
+	*closid = RISCV_RESCTRL_EMPTY_CLOSID;
+	*rmid = idx;
+}
+
+void resctrl_arch_set_cpu_default_closid_rmid(int cpu, u32 closid, u32 rmid)
+{
+	u32 srmcfg = FIELD_PREP(SRMCFG_RCID_MASK, closid) |
+		     FIELD_PREP(SRMCFG_MCID_MASK, rmid);
+
+	WRITE_ONCE(per_cpu(cpu_srmcfg_default, cpu), srmcfg);
+}
+
+void resctrl_arch_sched_in(struct task_struct *tsk)
+{
+	__switch_to_srmcfg(tsk);
+}
+
+void resctrl_arch_set_closid_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+	u32 srmcfg = FIELD_PREP(SRMCFG_RCID_MASK, closid) |
+		     FIELD_PREP(SRMCFG_MCID_MASK, rmid);
+
+	WRITE_ONCE(tsk->thread.srmcfg, srmcfg);
+}
+
+void resctrl_arch_sync_cpu_closid_rmid(void *info)
+{
+	struct resctrl_cpu_defaults *r = info;
+
+	lockdep_assert_preemption_disabled();
+
+	if (r) {
+		resctrl_arch_set_cpu_default_closid_rmid(smp_processor_id(),
+							 r->closid, r->rmid);
+	}
+
+	resctrl_arch_sched_in(current);
+}
+
+bool resctrl_arch_match_closid(struct task_struct *tsk, u32 closid)
+{
+	return FIELD_GET(SRMCFG_RCID_MASK, READ_ONCE(tsk->thread.srmcfg)) == closid;
+}
+
+bool resctrl_arch_match_rmid(struct task_struct *tsk, u32 closid, u32 rmid)
+{
+	return FIELD_GET(SRMCFG_MCID_MASK, READ_ONCE(tsk->thread.srmcfg)) == rmid;
+}
+
+void resctrl_arch_pre_mount(void)
+{
+	/* All controllers discovered at boot via late_initcall. Nothing to do. */
+}
+
+int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+			    u32 closid, enum resctrl_conf_type t, u32 cfg_val)
+{
+	struct cbqri_resctrl_dom *dom;
+
+	dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+
+	if (!r->alloc_capable)
+		return -EINVAL;
+
+	switch (r->rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		return cbqri_apply_cache_config_dom(dom, r, closid, t, cfg_val);
+	default:
+		return -EINVAL;
+	}
+}
+
+int resctrl_arch_update_domains(struct rdt_resource *r, u32 closid)
+{
+	struct resctrl_staged_config *cfg;
+	enum resctrl_conf_type t;
+	struct rdt_ctrl_domain *d;
+	int err = 0;
+
+	/* Walking r->ctrl_domains, ensure it can't race with cpuhp */
+	lockdep_assert_cpus_held();
+
+	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
+		for (t = 0; t < CDP_NUM_TYPES; t++) {
+			cfg = &d->staged_config[t];
+			if (!cfg->have_new_ctrl)
+				continue;
+			err = resctrl_arch_update_one(r, d, closid, t, cfg->new_ctrl);
+			if (err)
+				return err;
+		}
+	}
+	return err;
+}
+
+u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
+			    u32 closid, enum resctrl_conf_type type)
+{
+	struct cbqri_resctrl_dom *hw_dom;
+	struct cbqri_controller *ctrl;
+	enum cbqri_at at;
+	u32 val;
+	int err;
+
+	hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+	ctrl = hw_dom->hw_ctrl;
+	val = resctrl_get_default_ctrl(r);
+
+	if (!r->alloc_capable)
+		return val;
+
+	switch (r->rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		at = (type == CDP_CODE) ? CBQRI_AT_CODE : CBQRI_AT_DATA;
+		err = cbqri_read_cache_config(ctrl, closid, at, &val);
+		if (err < 0)
+			val = resctrl_get_default_ctrl(r);
+		break;
+	default:
+		break;
+	}
+
+	return val;
+}
+
+void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
+{
+	struct cbqri_resctrl_res *hw_res;
+	struct rdt_ctrl_domain *d;
+	enum resctrl_conf_type t;
+	u32 default_ctrl;
+	int i;
+
+	lockdep_assert_cpus_held();
+
+	hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+	default_ctrl = resctrl_get_default_ctrl(r);
+
+	if (!hw_res->ctrl)
+		return;
+
+	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
+		for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
+			for (t = 0; t < CDP_NUM_TYPES; t++) {
+				int rerr;
+
+				rerr = resctrl_arch_update_one(r, d, i, t, default_ctrl);
+				if (rerr)
+					pr_err_ratelimited("rid=%d reset RCID %u type %u failed (%d)\n",
+							   r->rid, i, t, rerr);
+			}
+		}
+	}
+}
+
+static struct rdt_ctrl_domain *cbqri_new_domain(struct cbqri_controller *ctrl)
+{
+	struct cbqri_resctrl_dom *hw_dom;
+	struct rdt_ctrl_domain *domain;
+
+	hw_dom = kzalloc_obj(*hw_dom, GFP_KERNEL);
+	if (!hw_dom)
+		return NULL;
+
+	hw_dom->hw_ctrl = ctrl;
+	domain = &hw_dom->resctrl_ctrl_dom;
+
+	INIT_LIST_HEAD(&domain->hdr.list);
+
+	return domain;
+}
+
+static int cbqri_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
+{
+	struct cbqri_resctrl_res *hw_res;
+	enum resctrl_conf_type t;
+	int err = 0;
+	int i;
+
+	hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+
+	for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
+		/*
+		 * Seed both DATA and CODE staged slots so a later mount
+		 * with -o cdp does not see stale CODE values.
+		 * On non-AT controllers cbqri_cc_alloc_op() masks AT to 0
+		 * so all three iterations land on the same hardware state.
+		 * The redundant writes are harmless.
+		 */
+		for (t = 0; t < CDP_NUM_TYPES; t++) {
+			err = resctrl_arch_update_one(r, d, i, t,
+						      resctrl_get_default_ctrl(r));
+			if (err)
+				return err;
+		}
+	}
+	return 0;
+}
+
+/*
+ * Walk cbqri_controllers and pick one capacity controller (CC) per cache
+ * level (L2/L3) to back the corresponding RDT_RESOURCE_L*. When more than
+ * one CC sits at the same level (e.g. one per socket), they must agree on
+ * rcid_count / ncblks / alloc_capable. A mismatch is fatal because resctrl
+ * exposes a single set of caps per rid. The first matching controller wins.
+ */
+static int cbqri_resctrl_pick_caches(void)
+{
+	struct cbqri_controller *ctrl;
+
+	list_for_each_entry(ctrl, &cbqri_controllers, list) {
+		struct cbqri_resctrl_res *cbqri_res;
+		enum resctrl_res_level rid;
+
+		if (ctrl->type != CBQRI_CONTROLLER_TYPE_CAPACITY)
+			continue;
+		if (!ctrl->alloc_capable) {
+			if (ctrl->mon_capable)
+				pr_warn_once("CC @%pa: monitor-only controllers aren't supported\n",
+					     &ctrl->addr);
+			continue;
+		}
+
+		if (ctrl->cache.cache_level == 2) {
+			rid = RDT_RESOURCE_L2;
+		} else if (ctrl->cache.cache_level == 3) {
+			rid = RDT_RESOURCE_L3;
+		} else {
+			pr_err("unknown cache level %d\n",
+			       ctrl->cache.cache_level);
+			return -ENODEV;
+		}
+
+		cbqri_res = &cbqri_resctrl_resources[rid];
+		if (cbqri_res->ctrl) {
+			/*
+			 * CCs at the same cache level must agree on every cap
+			 * resctrl exposes globally. Reject mismatches at pick
+			 * time so the inconsistency is visible at boot.
+			 */
+			if (cbqri_res->ctrl->rcid_count != ctrl->rcid_count ||
+			    cbqri_res->ctrl->cc.ncblks != ctrl->cc.ncblks ||
+			    cbqri_res->ctrl->cc.supports_alloc_at_code !=
+				    ctrl->cc.supports_alloc_at_code ||
+			    cbqri_res->ctrl->alloc_capable != ctrl->alloc_capable) {
+				pr_err("L%d controllers have mismatched capabilities\n",
+				       ctrl->cache.cache_level);
+				return -EINVAL;
+			}
+			continue;
+		}
+
+		cbqri_res->ctrl = ctrl;
+	}
+
+	return 0;
+}
+
+/*
+ * Fill the rdt_resource fields for one picked rid. An rid with no picked
+ * controller is left untouched so it stays out of resctrl_arch_get_resource().
+ */
+static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
+{
+	struct cbqri_controller *ctrl = cbqri_res->ctrl;
+	struct rdt_resource *res = &cbqri_res->resctrl_res;
+
+	if (!ctrl)
+		return 0;
+
+	switch (res->rid) {
+	case RDT_RESOURCE_L2:
+	case RDT_RESOURCE_L3:
+		res->name = (res->rid == RDT_RESOURCE_L2) ? "L2" : "L3";
+		res->schema_fmt = RESCTRL_SCHEMA_BITMAP;
+		res->ctrl_scope = (res->rid == RDT_RESOURCE_L2) ?
+				    RESCTRL_L2_CACHE : RESCTRL_L3_CACHE;
+		res->cache.cbm_len = ctrl->cc.ncblks;
+		res->cache.shareable_bits = 0;
+		res->cache.min_cbm_bits = 1;
+		res->cache.arch_has_sparse_bitmasks = false;
+		res->cdp_capable = ctrl->cc.supports_alloc_at_code;
+		res->alloc_capable = ctrl->alloc_capable;
+		INIT_LIST_HEAD(&res->ctrl_domains);
+		INIT_LIST_HEAD(&res->mon_domains);
+		break;
+	default:
+		break;
+	}
+
+	return 0;
+}
+
+static void cbqri_resctrl_accumulate_caps(void)
+{
+	int rid;
+
+	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
+		struct cbqri_resctrl_res *hw_res = &cbqri_resctrl_resources[rid];
+
+		if (!hw_res->ctrl)
+			continue;
+		if (hw_res->ctrl->alloc_capable)
+			exposed_alloc_capable = true;
+	}
+}
+
+/*
+ * Create, list-insert, and online a fresh ctrl_domain backing ctrl on
+ * resource res, seeded with cpu and identified by dom_id. Caller must
+ * hold cbqri_domain_list_lock and must have already verified that no
+ * existing ctrl_domain on res carries this id.
+ */
+static struct rdt_ctrl_domain *cbqri_create_ctrl_domain(struct cbqri_controller *ctrl,
+							struct rdt_resource *res,
+							unsigned int cpu, int dom_id)
+{
+	struct rdt_ctrl_domain *domain;
+	struct list_head *pos = NULL;
+	int err;
+
+	domain = cbqri_new_domain(ctrl);
+	if (!domain)
+		return ERR_PTR(-ENOMEM);
+
+	cpumask_set_cpu(cpu, &domain->hdr.cpu_mask);
+	domain->hdr.id = dom_id;
+	domain->hdr.type = RESCTRL_CTRL_DOMAIN;
+
+	err = cbqri_init_domain_ctrlval(res, domain);
+	if (err) {
+		kfree(container_of(domain, struct cbqri_resctrl_dom,
+				   resctrl_ctrl_dom));
+		return ERR_PTR(err);
+	}
+
+	/* Insert sorted by id so user-visible ordering is deterministic. */
+	resctrl_find_domain(&res->ctrl_domains, dom_id, &pos);
+	list_add_tail(&domain->hdr.list, pos);
+
+	resctrl_online_ctrl_domain(res, domain);
+
+	return domain;
+}
+
+static int cbqri_attach_cpu_to_cap_ctrl(struct cbqri_controller *ctrl,
+					unsigned int cpu)
+{
+	struct cbqri_resctrl_res *hw_res;
+	struct rdt_ctrl_domain *domain;
+	struct rdt_resource *res;
+	int dom_id;
+
+	if (ctrl->cache.cache_level == 2)
+		hw_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
+	else if (ctrl->cache.cache_level == 3)
+		hw_res = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
+	else
+		return 0;
+
+	if (!hw_res->ctrl)
+		return 0;
+
+	res = &hw_res->resctrl_res;
+	dom_id = ctrl->cache.cache_id;
+
+	domain = cbqri_find_ctrl_domain(&res->ctrl_domains, dom_id);
+	if (domain) {
+		cpumask_set_cpu(cpu, &domain->hdr.cpu_mask);
+		return 0;
+	}
+
+	domain = cbqri_create_ctrl_domain(ctrl, res, cpu, dom_id);
+	if (IS_ERR(domain))
+		return PTR_ERR(domain);
+
+	return 0;
+}
+
+static void cbqri_detach_cpu_from_ctrl_domains(struct rdt_resource *res,
+					       unsigned int cpu)
+{
+	struct rdt_ctrl_domain *domain, *tmp;
+
+	list_for_each_entry_safe(domain, tmp, &res->ctrl_domains, hdr.list) {
+		if (!cpumask_test_cpu(cpu, &domain->hdr.cpu_mask))
+			continue;
+		cpumask_clear_cpu(cpu, &domain->hdr.cpu_mask);
+		if (cpumask_empty(&domain->hdr.cpu_mask)) {
+			resctrl_offline_ctrl_domain(res, domain);
+			list_del(&domain->hdr.list);
+			kfree(container_of(domain, struct cbqri_resctrl_dom,
+					   resctrl_ctrl_dom));
+		}
+	}
+}
+
+/*
+ * Remove a CPU from every domain it was attached to. The per-resource
+ * detach helpers act only when the CPU is set in a domain's mask, so this
+ * is idempotent and undoes a partial online attach as well as a full
+ * offline. Caller holds cbqri_domain_list_lock.
+ */
+static void cbqri_detach_cpu_from_all_ctrls(unsigned int cpu)
+{
+	int rid;
+
+	lockdep_assert_held(&cbqri_domain_list_lock);
+
+	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
+		struct cbqri_resctrl_res *hw_res = &cbqri_resctrl_resources[rid];
+
+		if (!hw_res->ctrl)
+			continue;
+		cbqri_detach_cpu_from_ctrl_domains(&hw_res->resctrl_res, cpu);
+	}
+}
+
+/*
+ * Attach a CPU to every controller that claims it. On failure, detach the
+ * CPU from everything attached so far: the cpuhp core does not run this
+ * state's offline teardown when its startup fails, so a partial attach
+ * would otherwise leak into the domain cpu_masks. Caller holds
+ * cbqri_domain_list_lock.
+ */
+static int cbqri_attach_cpu_to_all_ctrls(unsigned int cpu)
+{
+	struct cbqri_controller *ctrl;
+	int err = 0;
+
+	lockdep_assert_held(&cbqri_domain_list_lock);
+
+	list_for_each_entry(ctrl, &cbqri_controllers, list) {
+		if (ctrl->type != CBQRI_CONTROLLER_TYPE_CAPACITY)
+			continue;
+		if (!cpumask_test_cpu(cpu, &ctrl->cache.cpu_mask))
+			continue;
+		if (!ctrl->alloc_capable)
+			continue;
+
+		err = cbqri_attach_cpu_to_cap_ctrl(ctrl, cpu);
+		if (err) {
+			cbqri_detach_cpu_from_all_ctrls(cpu);
+			break;
+		}
+	}
+
+	return err;
+}
+
+static bool cbqri_resctrl_inited;
+
+static void cbqri_resctrl_teardown(void)
+{
+	int rid;
+
+	if (!cbqri_resctrl_inited)
+		return;
+
+	resctrl_exit();
+
+	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
+		struct cbqri_resctrl_res *hw_res = &cbqri_resctrl_resources[rid];
+
+		hw_res->ctrl = NULL;
+		hw_res->cdp_enabled = false;
+	}
+	exposed_alloc_capable = false;
+	cbqri_resctrl_inited = false;
+}
+
+static int cbqri_resctrl_setup(void)
+{
+	int rid;
+	int err;
+
+	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++)
+		cbqri_resctrl_resources[rid].resctrl_res.rid = rid;
+
+	err = cbqri_resctrl_pick_caches();
+	if (err)
+		return err;
+
+	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
+		err = cbqri_resctrl_control_init(&cbqri_resctrl_resources[rid]);
+		if (err)
+			return err;
+	}
+
+	cbqri_resctrl_accumulate_caps();
+
+	if (!exposed_alloc_capable) {
+		pr_debug("no resctrl-capable CBQRI controllers found\n");
+		return -ENODEV;
+	}
+
+	err = resctrl_init();
+	if (err)
+		return err;
+
+	cbqri_resctrl_inited = true;
+	return 0;
+}
+
+static int cbqri_resctrl_online_cpu(unsigned int cpu)
+{
+	int err;
+
+	mutex_lock(&cbqri_domain_list_lock);
+	err = cbqri_attach_cpu_to_all_ctrls(cpu);
+	mutex_unlock(&cbqri_domain_list_lock);
+	if (err)
+		return err;
+
+	/*
+	 * Seed the per-CPU default RCID/MCID to the reserved (0, 0) pair and
+	 * notify the resctrl core so it tracks this CPU in the default group.
+	 * Mirrors x86 resctrl_arch_online_cpu().
+	 */
+	resctrl_arch_set_cpu_default_closid_rmid(cpu, 0, 0);
+	resctrl_online_cpu(cpu);
+	return 0;
+}
+
+static int cbqri_resctrl_offline_cpu(unsigned int cpu)
+{
+	resctrl_offline_cpu(cpu);
+
+	mutex_lock(&cbqri_domain_list_lock);
+	cbqri_detach_cpu_from_all_ctrls(cpu);
+	mutex_unlock(&cbqri_domain_list_lock);
+	return 0;
+}
+
+/* Saved cpuhp slot from cpuhp_setup_state() for symmetric removal. */
+static enum cpuhp_state cbqri_cpuhp_state;
+
+static int __init cbqri_arch_late_init(void)
+{
+	int err;
+
+	if (!riscv_isa_extension_available(NULL, SSQOSID))
+		return -ENODEV;
+
+	err = cbqri_resctrl_setup();
+	if (err)
+		return err;
+
+	err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cbqri:online",
+				cbqri_resctrl_online_cpu,
+				cbqri_resctrl_offline_cpu);
+	if (err < 0) {
+		cbqri_resctrl_teardown();
+		return err;
+	}
+	cbqri_cpuhp_state = err;
+
+	return 0;
+}
+late_initcall(cbqri_arch_late_init);

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:08 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:08 -0700
Subject: [PATCH RFC v6 14/18] riscv_cbqri: resctrl: Add MB_WGHT bandwidth
 allocation via Mweight
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-14-baf00f50028a@kernel.org>

Add bandwidth allocation through Mweight (shared weight for unreserved
bandwidth) exposed as the MB_WGHT resource. Mweight has no MBA
equivalent, so it lands as a new RDT_RESOURCE_*.

Mweight is an integer in [0, 255]. A value of 0 disables work-
conserving sharing for the group, capping its bandwidth at the
MB_MIN reservation. Values 1..255 compete for the leftover pool in
proportion to the weight.

The same BC backs both MB_MIN and MB_WGHT and bc_bw_alloc packs Rbwb and
Mweight in one register. cbqri_attach_cpu_to_bw_ctrl() attaches both
rids to the picked BC.

Reset gives every RCID the new-group default (max_bw = 255) for
equal opportunistic shares.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 drivers/resctrl/cbqri_resctrl.c | 90 +++++++++++++++++++++++++++++++++++++++--
 1 file changed, 86 insertions(+), 4 deletions(-)

diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
index 1d312004b07d..14b955eb7949 100644
--- a/drivers/resctrl/cbqri_resctrl.c
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -366,6 +366,8 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	case RDT_RESOURCE_MB_MIN:
 		/* sum(Rbwb) <= MRBWB validation runs inside cbqri_apply_rbwb(). */
 		return cbqri_apply_rbwb(dom->hw_ctrl, closid, cfg_val, true);
+	case RDT_RESOURCE_MB_WGHT:
+		return cbqri_apply_mweight_config(dom->hw_ctrl, closid, cfg_val);
 	default:
 		return -EINVAL;
 	}
@@ -426,6 +428,14 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 			val = (u32)rbwb;
 		break;
 	}
+	case RDT_RESOURCE_MB_WGHT: {
+		u64 mweight;
+
+		err = cbqri_read_mweight(ctrl, closid, &mweight);
+		if (err == 0)
+			val = (u32)mweight;
+		break;
+	}
 	default:
 		break;
 	}
@@ -485,6 +495,18 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 							   rcid, rerr);
 			}
 			break;
+		case RDT_RESOURCE_MB_WGHT:
+			/* All RCIDs start at max weight (the new-group default). */
+			for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
+				int rerr;
+
+				rerr = cbqri_apply_mweight_config(dom->hw_ctrl, i,
+								  default_ctrl);
+				if (rerr)
+					pr_err_ratelimited("Mweight reset RCID %u failed (%d)\n",
+							   i, rerr);
+			}
+			break;
 		default:
 			for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
 				for (t = 0; t < CDP_NUM_TYPES; t++) {
@@ -549,6 +571,11 @@ static int cbqri_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_dom
 
 			err = cbqri_apply_rbwb(dom->hw_ctrl, rcid, rbwb, false);
 			break;
+		case RDT_RESOURCE_MB_WGHT:
+			/* Match the new-group default: equal weights across RCIDs. */
+			err = cbqri_apply_mweight_config(dom->hw_ctrl, i,
+							 resctrl_get_default_ctrl(r));
+			break;
 		default:
 			/*
 			 * Seed both DATA and CODE staged slots so a later
@@ -690,6 +717,25 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 		INIT_LIST_HEAD(&res->mon_domains);
 		break;
 
+	case RDT_RESOURCE_MB_WGHT:
+		res->name = "MB_WGHT";
+		res->schema_fmt = RESCTRL_SCHEMA_RANGE;
+		res->ctrl_scope = RESCTRL_L3_CACHE;
+		/* Mweight is a dimensionless ratio. No delay/linear concept. */
+		res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+		/*
+		 * CBQRI section 4.5: Mweight is 0-255 (0 disables
+		 * work-conserving). No sum constraint, so leave
+		 * default_to_min false. Groups default to max_bw.
+		 */
+		res->membw.min_bw = 0;
+		res->membw.max_bw = 255;
+		res->membw.bw_gran = 1;
+		res->alloc_capable = ctrl->alloc_capable;
+		INIT_LIST_HEAD(&res->ctrl_domains);
+		INIT_LIST_HEAD(&res->mon_domains);
+		break;
+
 	default:
 		break;
 	}
@@ -698,13 +744,12 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 }
 
 /*
- * Pick one BC to back MB_MIN.  Multiple BCs must agree on rcid_count
- * and mrbwb.  Mismatch is fatal because resctrl exposes a single set
- * of caps per rid.
+ * Pick one BC to back both MB_MIN and MB_WGHT.
  */
 static int cbqri_resctrl_pick_bw_alloc(void)
 {
 	struct cbqri_resctrl_res *mb_min = &cbqri_resctrl_resources[RDT_RESOURCE_MB_MIN];
+	struct cbqri_resctrl_res *mb_wght = &cbqri_resctrl_resources[RDT_RESOURCE_MB_WGHT];
 	struct cbqri_controller *ctrl;
 
 	list_for_each_entry(ctrl, &cbqri_controllers, list) {
@@ -723,6 +768,7 @@ static int cbqri_resctrl_pick_bw_alloc(void)
 		}
 
 		mb_min->ctrl = ctrl;
+		mb_wght->ctrl = ctrl;
 	}
 
 	return 0;
@@ -961,10 +1007,46 @@ static int cbqri_attach_cpu_to_one_bw_res(struct cbqri_controller *ctrl,
 	return 0;
 }
 
+static void cbqri_detach_cpu_from_one_bw_res(struct cbqri_controller *ctrl,
+					     enum resctrl_res_level rid,
+					     unsigned int cpu)
+{
+	struct cbqri_resctrl_res *hw_res = &cbqri_resctrl_resources[rid];
+	struct rdt_resource *res = &hw_res->resctrl_res;
+	struct rdt_ctrl_domain *domain;
+	int dom_id = ctrl->mem.prox_dom;
+
+	lockdep_assert_held(&cbqri_domain_list_lock);
+
+	if (!hw_res->ctrl)
+		return;
+
+	domain = cbqri_find_ctrl_domain(&res->ctrl_domains, dom_id);
+	if (!domain || !cpumask_test_cpu(cpu, &domain->hdr.cpu_mask))
+		return;
+
+	cpumask_clear_cpu(cpu, &domain->hdr.cpu_mask);
+	if (cpumask_empty(&domain->hdr.cpu_mask)) {
+		resctrl_offline_ctrl_domain(res, domain);
+		list_del(&domain->hdr.list);
+		kfree(container_of(domain, struct cbqri_resctrl_dom,
+				   resctrl_ctrl_dom));
+	}
+}
+
 static int cbqri_attach_cpu_to_bw_ctrl(struct cbqri_controller *ctrl,
 				       unsigned int cpu)
 {
-	return cbqri_attach_cpu_to_one_bw_res(ctrl, RDT_RESOURCE_MB_MIN, cpu);
+	int err;
+
+	err = cbqri_attach_cpu_to_one_bw_res(ctrl, RDT_RESOURCE_MB_MIN, cpu);
+	if (err)
+		return err;
+
+	err = cbqri_attach_cpu_to_one_bw_res(ctrl, RDT_RESOURCE_MB_WGHT, cpu);
+	if (err)
+		cbqri_detach_cpu_from_one_bw_res(ctrl, RDT_RESOURCE_MB_MIN, cpu);
+	return err;
 }
 
 static void cbqri_detach_cpu_from_l3_mon(struct rdt_resource *res,

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:06 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:06 -0700
Subject: [PATCH RFC v6 12/18] riscv_cbqri: resctrl: Add L3 cache occupancy
 monitoring
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-12-baf00f50028a@kernel.org>

Expose QOS_L3_OCCUP_EVENT_ID so userspace can read per-MCID
llc_occupancy. The result is converted from capacity blocks to bytes
using cache_size and ncblks.

Each MCID is armed once with the Occupancy event by
cbqri_init_mon_counters() and free runs thereafter. The resctrl core
only reads occupancy on the limbo recycle path and never resets it, so
resctrl_arch_reset_rmid() and resctrl_arch_reset_rmid_all() have no
per-rmid software state to clear.

The L3 mon_domain is created lazily on the first CPU of a cache_id and
linked to the paired ctrl_domain.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 drivers/resctrl/cbqri_resctrl.c | 286 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 274 insertions(+), 12 deletions(-)

diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
index fb6d82aa3ffc..f379058b0114 100644
--- a/drivers/resctrl/cbqri_resctrl.c
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -10,6 +10,7 @@
 #include <linux/cpuhotplug.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/resctrl.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -33,6 +34,10 @@ struct cbqri_resctrl_dom {
 static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
 
 static bool exposed_alloc_capable;
+static bool exposed_mon_capable;
+
+/* Used by resctrl_arch_system_num_rmid_idx(). Narrowed by accumulate_caps. */
+static u32 max_rmid = U32_MAX;
 
 /* Protects ctrl_domain list mutations across CPU hotplug. */
 static DEFINE_MUTEX(cbqri_domain_list_lock);
@@ -45,6 +50,14 @@ cbqri_find_ctrl_domain(struct list_head *h, int id)
 	return hdr ? container_of(hdr, struct rdt_ctrl_domain, hdr) : NULL;
 }
 
+static struct rdt_l3_mon_domain *
+cbqri_find_l3_mon_domain(struct list_head *h, int id)
+{
+	struct rdt_domain_hdr *hdr = resctrl_find_domain(h, id, NULL);
+
+	return hdr ? container_of(hdr, struct rdt_l3_mon_domain, hdr) : NULL;
+}
+
 static int cbqri_apply_cache_config_dom(struct cbqri_resctrl_dom *hw_dom,
 					struct rdt_resource *r,
 					u32 closid, enum resctrl_conf_type t,
@@ -68,7 +81,7 @@ bool resctrl_arch_alloc_capable(void)
 
 bool resctrl_arch_mon_capable(void)
 {
-	return false;
+	return exposed_mon_capable;
 }
 
 bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
@@ -168,20 +181,89 @@ void resctrl_arch_mon_event_config_write(void *info)
 {
 }
 
-void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
+void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+			     u32 unused, u32 rmid, enum resctrl_event_id eventid)
 {
+	/*
+	 * Occupancy MCIDs are armed once by cbqri_init_mon_counters() and
+	 * free run thereafter. The core only reads occupancy on the limbo
+	 * recycle path, never resets it, so there is no per-rmid software
+	 * state to clear here.
+	 */
 }
 
-void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
-			     u32 unused, u32 rmid, enum resctrl_event_id eventid)
+void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
 {
+	/* Occupancy counters free run, so there is no state to reset. */
 }
 
 int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
 			   u32 closid, u32 rmid, enum resctrl_event_id eventid,
 			   void *arch_priv, u64 *val, void *arch_mon_ctx)
 {
-	return -ENODATA;
+	struct cbqri_resctrl_dom *hw_dom;
+	struct cbqri_controller *ctrl;
+	struct rdt_ctrl_domain *d;
+	u64 ctr_val;
+	int err = 0;
+
+	resctrl_arch_rmid_read_context_check();
+
+	/*
+	 * cbqri_mon_op() takes ctrl->lock sleeping mutex and polls
+	 * BUSY for up to 1 ms, neither of which is safe under
+	 * irqs_disabled().
+	 */
+	if (irqs_disabled())
+		return -EIO;
+
+	/*
+	 * cbqri_domain_list_lock serialises the list walk against
+	 * cbqri_detach_cpu_from_ctrl_domains().
+	 */
+	mutex_lock(&cbqri_domain_list_lock);
+
+	switch (eventid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+		d = cbqri_find_ctrl_domain(&r->ctrl_domains, hdr->id);
+		if (!d) {
+			err = -ENOENT;
+			break;
+		}
+
+		hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+		ctrl = hw_dom->hw_ctrl;
+
+		mutex_lock(&ctrl->lock);
+
+		/*
+		 * MCIDs are armed with Occupancy once at init and free run.
+		 * Pass EVT_ID explicitly as the CBQRI spec does not guarantee
+		 * sticky-last-configured-event for READ_COUNTER.
+		 */
+		err = cbqri_mon_op(ctrl, CBQRI_CC_MON_CTL_OFF,
+				   CBQRI_CC_MON_CTL_OP_READ_COUNTER,
+				   rmid, CBQRI_CC_EVT_ID_OCCUPANCY, NULL);
+		if (!err) {
+			ctr_val = ioread64(ctrl->base + CBQRI_CC_MON_CTL_VAL_OFF);
+
+			/*
+			 * Capacity blocks to bytes. Multiply before divide
+			 * so a non-power-of-2 ncblks doesn't truncate.
+			 */
+			*val = (u64)ctrl->cache.cache_size * ctr_val /
+			       ctrl->cc.ncblks;
+		}
+		mutex_unlock(&ctrl->lock);
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	mutex_unlock(&cbqri_domain_list_lock);
+	return err;
 }
 
 /*
@@ -203,7 +285,7 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *res)
 
 u32 resctrl_arch_system_num_rmid_idx(void)
 {
-	return 1;
+	return max_rmid;
 }
 
 u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
@@ -500,6 +582,13 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 		res->alloc_capable = ctrl->alloc_capable;
 		INIT_LIST_HEAD(&res->ctrl_domains);
 		INIT_LIST_HEAD(&res->mon_domains);
+
+		if (ctrl->mon_capable && res->rid == RDT_RESOURCE_L3) {
+			res->mon_scope = RESCTRL_L3_CACHE;
+			resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID,
+						 false, 0, NULL);
+			res->mon_capable = true;
+		}
 		break;
 	default:
 		break;
@@ -510,6 +599,7 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 
 static void cbqri_resctrl_accumulate_caps(void)
 {
+	struct cbqri_controller *l3_ctrl;
 	int rid;
 
 	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
@@ -519,7 +609,30 @@ static void cbqri_resctrl_accumulate_caps(void)
 			continue;
 		if (hw_res->ctrl->alloc_capable)
 			exposed_alloc_capable = true;
+		if (hw_res->ctrl->mon_capable)
+			exposed_mon_capable = true;
+	}
+
+	/*
+	 * Narrow max_rmid against the picked occupancy source (the L3 CC)
+	 * only. A mon-capable controller that is not exposed as a counter
+	 * source must not clamp the rmid space.
+	 */
+	l3_ctrl = cbqri_resctrl_resources[RDT_RESOURCE_L3].ctrl;
+	if (l3_ctrl && l3_ctrl->mon_capable)
+		max_rmid = min(max_rmid, l3_ctrl->mcid_count);
+
+	if (!exposed_mon_capable) {
+		max_rmid = 1;
+		return;
 	}
+
+	/*
+	 * num_rmid is the user-visible bound for the L3 monitoring rmid
+	 * space. Track max_rmid (the picked-source minimum) so userspace is
+	 * not told more RMIDs than can be allocated.
+	 */
+	cbqri_resctrl_resources[RDT_RESOURCE_L3].resctrl_res.mon.num_rmid = max_rmid;
 }
 
 /*
@@ -560,13 +673,89 @@ static struct rdt_ctrl_domain *cbqri_create_ctrl_domain(struct cbqri_controller
 	return domain;
 }
 
+static int cbqri_attach_cpu_to_l3_mon(struct cbqri_controller *ctrl,
+				      struct rdt_resource *res, unsigned int cpu)
+{
+	struct rdt_l3_mon_domain *mon_dom;
+	struct rdt_ctrl_domain *ctrl_dom;
+	struct list_head *mon_pos = NULL;
+	int dom_id = ctrl->cache.cache_id;
+	int err;
+
+	lockdep_assert_held(&cbqri_domain_list_lock);
+
+	mon_dom = cbqri_find_l3_mon_domain(&res->mon_domains, dom_id);
+	if (mon_dom) {
+		cpumask_set_cpu(cpu, &mon_dom->hdr.cpu_mask);
+		return 0;
+	}
+
+	ctrl_dom = cbqri_find_ctrl_domain(&res->ctrl_domains, dom_id);
+	if (!ctrl_dom) {
+		pr_err("L3 mon attach for cpu %u: no ctrl_domain id %d\n",
+		       cpu, dom_id);
+		return -EINVAL;
+	}
+
+	mon_dom = kzalloc_obj(*mon_dom, GFP_KERNEL);
+	if (!mon_dom)
+		return -ENOMEM;
+
+	mon_dom->hdr.id = dom_id;
+	mon_dom->hdr.type = RESCTRL_MON_DOMAIN;
+	mon_dom->hdr.rid = RDT_RESOURCE_L3;
+	cpumask_set_cpu(cpu, &mon_dom->hdr.cpu_mask);
+	INIT_LIST_HEAD(&mon_dom->hdr.list);
+
+	if (resctrl_find_domain(&res->mon_domains, dom_id, &mon_pos)) {
+		pr_err("duplicate L3 mon_domain id %d\n", dom_id);
+		err = -EEXIST;
+		goto err_free;
+	}
+	if (mon_pos)
+		list_add_tail(&mon_dom->hdr.list, mon_pos);
+	else
+		list_add_tail(&mon_dom->hdr.list, &res->mon_domains);
+
+	err = resctrl_online_mon_domain(res, &mon_dom->hdr);
+	if (err)
+		goto err_listdel;
+
+	err = cbqri_init_mon_counters(ctrl);
+	if (err)
+		goto err_offline;
+
+	return 0;
+
+err_offline:
+	/*
+	 * cancel_delayed_work avoids deadlocking against the cqm_limbo
+	 * worker which takes cpus_read_lock while this hotplug callback
+	 * already holds cpus_write_lock. mbm_over is only
+	 * INIT_DELAYED_WORK'd when MBM_TOTAL was enabled, so gate the
+	 * cancel on the same condition to avoid touching a zeroed work
+	 * struct.
+	 */
+	cancel_delayed_work(&mon_dom->cqm_limbo);
+	if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
+		cancel_delayed_work(&mon_dom->mbm_over);
+	resctrl_offline_mon_domain(res, &mon_dom->hdr);
+err_listdel:
+	list_del(&mon_dom->hdr.list);
+err_free:
+	kfree(mon_dom);
+	return err;
+}
+
 static int cbqri_attach_cpu_to_cap_ctrl(struct cbqri_controller *ctrl,
 					unsigned int cpu)
 {
 	struct cbqri_resctrl_res *hw_res;
 	struct rdt_ctrl_domain *domain;
 	struct rdt_resource *res;
+	bool new_domain = false;
 	int dom_id;
+	int err;
 
 	if (ctrl->cache.cache_level == 2)
 		hw_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
@@ -584,14 +773,68 @@ static int cbqri_attach_cpu_to_cap_ctrl(struct cbqri_controller *ctrl,
 	domain = cbqri_find_ctrl_domain(&res->ctrl_domains, dom_id);
 	if (domain) {
 		cpumask_set_cpu(cpu, &domain->hdr.cpu_mask);
-		return 0;
+	} else {
+		domain = cbqri_create_ctrl_domain(ctrl, res, cpu, dom_id);
+		if (IS_ERR(domain))
+			return PTR_ERR(domain);
+		new_domain = true;
 	}
 
-	domain = cbqri_create_ctrl_domain(ctrl, res, cpu, dom_id);
-	if (IS_ERR(domain))
-		return PTR_ERR(domain);
+	if (ctrl->mon_capable && ctrl->cache.cache_level == 3) {
+		err = cbqri_attach_cpu_to_l3_mon(ctrl, res, cpu);
+		if (err)
+			goto err_undo_ctrl_dom;
+	}
 
 	return 0;
+
+err_undo_ctrl_dom:
+	/*
+	 * The cpuhp core only rolls back states that successfully ran their
+	 * startup. The L3 mon attach failure happens inside this state's
+	 * startup, so its own offline callback is not invoked. Undo the
+	 * cpumask_set and, if this attach created the ctrl_domain, tear it
+	 * down so a retry sees a clean slate.
+	 */
+	cpumask_clear_cpu(cpu, &domain->hdr.cpu_mask);
+	if (new_domain) {
+		resctrl_offline_ctrl_domain(res, domain);
+		list_del(&domain->hdr.list);
+		kfree(container_of(domain, struct cbqri_resctrl_dom,
+				   resctrl_ctrl_dom));
+	}
+	return err;
+}
+
+static void cbqri_detach_cpu_from_l3_mon(struct rdt_resource *res,
+					 unsigned int cpu)
+{
+	struct rdt_l3_mon_domain *mon_dom, *tmp;
+
+	lockdep_assert_held(&cbqri_domain_list_lock);
+
+	list_for_each_entry_safe(mon_dom, tmp, &res->mon_domains, hdr.list) {
+		if (!cpumask_test_cpu(cpu, &mon_dom->hdr.cpu_mask))
+			continue;
+		cpumask_clear_cpu(cpu, &mon_dom->hdr.cpu_mask);
+		if (cpumask_empty(&mon_dom->hdr.cpu_mask)) {
+			/*
+			 * This runs as a cpuhp offline callback under
+			 * cpus_write_lock. The cqm_limbo and mbm_over workers
+			 * take cpus_read_lock before touching a domain, so
+			 * neither can run or re-queue here. A non-sync cancel
+			 * thus reliably dequeues any pending work before kfree,
+			 * and cancel_delayed_work_sync() would instead deadlock
+			 * against that cpus_read_lock.
+			 */
+			cancel_delayed_work(&mon_dom->cqm_limbo);
+			if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
+				cancel_delayed_work(&mon_dom->mbm_over);
+			resctrl_offline_mon_domain(res, &mon_dom->hdr);
+			list_del(&mon_dom->hdr.list);
+			kfree(mon_dom);
+		}
+	}
 }
 
 static void cbqri_detach_cpu_from_ctrl_domains(struct rdt_resource *res,
@@ -630,6 +873,8 @@ static void cbqri_detach_cpu_from_all_ctrls(unsigned int cpu)
 		if (!hw_res->ctrl)
 			continue;
 		cbqri_detach_cpu_from_ctrl_domains(&hw_res->resctrl_res, cpu);
+		if (rid == RDT_RESOURCE_L3 && hw_res->ctrl->mon_capable)
+			cbqri_detach_cpu_from_l3_mon(&hw_res->resctrl_res, cpu);
 	}
 }
 
@@ -683,6 +928,8 @@ static void cbqri_resctrl_teardown(void)
 		hw_res->cdp_enabled = false;
 	}
 	exposed_alloc_capable = false;
+	exposed_mon_capable = false;
+	max_rmid = U32_MAX;
 	cbqri_resctrl_inited = false;
 }
 
@@ -706,14 +953,29 @@ static int cbqri_resctrl_setup(void)
 
 	cbqri_resctrl_accumulate_caps();
 
-	if (!exposed_alloc_capable) {
+	if (!exposed_alloc_capable && !exposed_mon_capable) {
 		pr_debug("no resctrl-capable CBQRI controllers found\n");
 		return -ENODEV;
 	}
 
 	err = resctrl_init();
-	if (err)
+	if (err) {
+		/*
+		 * resctrl_init() failed before we set cbqri_resctrl_inited,
+		 * so cbqri_resctrl_teardown() would no-op. Roll back the
+		 * exposed_*_capable flags and the resource picks directly
+		 * so resctrl_arch_alloc_capable() / _mon_capable() do not
+		 * lie to callers after this returns.
+		 */
+		for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
+			cbqri_resctrl_resources[rid].ctrl = NULL;
+			cbqri_resctrl_resources[rid].cdp_enabled = false;
+		}
+		exposed_alloc_capable = false;
+		exposed_mon_capable = false;
+		max_rmid = U32_MAX;
 		return err;
+	}
 
 	cbqri_resctrl_inited = true;
 	return 0;

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:09 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:09 -0700
Subject: [PATCH RFC v6 15/18] riscv_cbqri: resctrl: Add mbm_total_bytes
 bandwidth monitoring
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-15-baf00f50028a@kernel.org>

Expose CBQRI bandwidth controller's combined read+write counter as
the L3 mbm_total_bytes event. A software accumulator keeps the
64-bit byte total monotonic across the 62-bit hardware counter wrap.

mbm_local_bytes is not supported because the CBQRI spec has no way
to distinguish total versus local. mbm_total_bytes is enabled only
when the platform exposes exactly one mon-capable bandwidth
controller and exactly one L3 domain. Pairing a single BC with
multiple L3 domains would let standard userspace tools overcount
system bandwidth by summing the same counter across domains.

Assisted-by: Claude:claude-opus-4-7
Co-developed-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Adrien Ricciardi <aricciardi at baylibre.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 drivers/resctrl/cbqri_resctrl.c | 232 +++++++++++++++++++++++++++++++++++++++-
 1 file changed, 228 insertions(+), 4 deletions(-)

diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
index 14b955eb7949..efd75d241122 100644
--- a/drivers/resctrl/cbqri_resctrl.c
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -29,6 +29,13 @@ struct cbqri_resctrl_res {
 struct cbqri_resctrl_dom {
 	struct rdt_ctrl_domain  resctrl_ctrl_dom;
 	struct cbqri_controller *hw_ctrl;
+	/*
+	 * For an L3 capacity controller paired with a bandwidth controller
+	 * of matching topology, paired_bc caches that BC so mbm_total_bytes
+	 * reads / resets don't have to walk cbqri_controllers on every hit.
+	 * NULL for non-L3 domains and L3s without a paired BC.
+	 */
+	struct cbqri_controller *paired_bc;
 };
 
 static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
@@ -184,17 +191,67 @@ void resctrl_arch_mon_event_config_write(void *info)
 void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
 			     u32 unused, u32 rmid, enum resctrl_event_id eventid)
 {
+	struct cbqri_resctrl_dom *hw_dom;
+	struct rdt_ctrl_domain *cd;
+
+	if (irqs_disabled())
+		return;
+
+	mutex_lock(&cbqri_domain_list_lock);
+
 	/*
 	 * Occupancy MCIDs are armed once by cbqri_init_mon_counters() and
-	 * free run thereafter. The core only reads occupancy on the limbo
-	 * recycle path, never resets it, so there is no per-rmid software
-	 * state to clear here.
+	 * free run thereafter, so only mbm_total_bytes needs a per-rmid reset.
 	 */
+	switch (eventid) {
+	case QOS_L3_MBM_TOTAL_EVENT_ID: {
+		struct cbqri_controller *bc;
+
+		cd = cbqri_find_ctrl_domain(&r->ctrl_domains, d->hdr.id);
+		if (!cd)
+			break;
+		hw_dom = container_of(cd, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+		bc = hw_dom->paired_bc;
+		if (!bc)
+			break;
+		if (WARN_ON_ONCE(!bc->mbm_total_states))
+			break;
+		if (rmid >= bc->mcid_count)
+			break;
+
+		mutex_lock(&bc->lock);
+		/*
+		 * CONFIG_EVENT both resets and re-arms. Skip the accumulator
+		 * memset on failure. A stale hardware counter X with
+		 * prev_ctr=0 would inject overflow(0, X) on the next read.
+		 */
+		if (!cbqri_mon_op(bc, CBQRI_BC_MON_CTL_OFF,
+				  CBQRI_BC_MON_CTL_OP_CONFIG_EVENT, rmid,
+				  CBQRI_BC_EVT_ID_TOTAL_READ_WRITE, NULL))
+			memset(&bc->mbm_total_states[rmid], 0,
+			       sizeof(*bc->mbm_total_states));
+		mutex_unlock(&bc->lock);
+		break;
+	}
+
+	default:
+		break;
+	}
+
+	mutex_unlock(&cbqri_domain_list_lock);
 }
 
 void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
 {
-	/* Occupancy counters free run, so there is no state to reset. */
+	int i;
+
+	/*
+	 * Occupancy counters free run and need no reset; only the
+	 * mbm_total_bytes accumulators are cleared. Bound by max_rmid
+	 * (system-wide minimum mcid_count).
+	 */
+	for (i = 0; i < max_rmid; i++)
+		resctrl_arch_reset_rmid(r, d, 0, i, QOS_L3_MBM_TOTAL_EVENT_ID);
 }
 
 int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
@@ -257,6 +314,82 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
 		mutex_unlock(&ctrl->lock);
 		break;
 
+	case QOS_L3_MBM_TOTAL_EVENT_ID: {
+		struct cbqri_controller *bc;
+
+		/*
+		 * The L3 monitoring domain's id is the L3 cache id. The
+		 * matching ctrl domain's hw_dom->paired_bc was cached at
+		 * add time to avoid walking cbqri_controllers on every read.
+		 */
+		d = cbqri_find_ctrl_domain(&r->ctrl_domains, hdr->id);
+		if (!d) {
+			err = -ENOENT;
+			break;
+		}
+		hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+		bc = hw_dom->paired_bc;
+		if (!bc) {
+			err = -ENOENT;
+			break;
+		}
+		if (WARN_ON_ONCE(!bc->mbm_total_states)) {
+			err = -EIO;
+			break;
+		}
+		if (rmid >= bc->mcid_count) {
+			err = -ERANGE;
+			break;
+		}
+
+		mutex_lock(&bc->lock);
+		/* Pass EVT_ID explicitly. Same reason as the CC path above. */
+		err = cbqri_mon_op(bc, CBQRI_BC_MON_CTL_OFF,
+				   CBQRI_BC_MON_CTL_OP_READ_COUNTER, rmid,
+				   CBQRI_BC_EVT_ID_TOTAL_READ_WRITE, NULL);
+		if (err)
+			goto out_bc;
+
+		ctr_val = ioread64(bc->base + CBQRI_BC_MON_CTR_VAL_OFF);
+
+		if (ctr_val & CBQRI_BC_MON_CTR_VAL_INVALID) {
+			/*
+			 * Return the last good total and leave prev_ctr so
+			 * the next valid sample resumes from there.
+			 */
+			*val = bc->mbm_total_states[rmid].chunks;
+		} else if (ctr_val & CBQRI_BC_MON_CTR_VAL_OVF) {
+			/*
+			 * OVF is sticky until next CONFIG_EVENT.
+			 * cbqri_bc_mon_overflow() can recover at most
+			 * one wrap. With OVF set, the count is unknown,
+			 * so re-arm and re-anchor prev_ctr=0.
+			 */
+			struct cbqri_bc_mon_state *s = &bc->mbm_total_states[rmid];
+
+			pr_warn_ratelimited("BC@%pa MCID %u: bandwidth counter overflow\n",
+					    &bc->addr, rmid);
+			err = cbqri_mon_op(bc, CBQRI_BC_MON_CTL_OFF,
+					   CBQRI_BC_MON_CTL_OP_CONFIG_EVENT, rmid,
+					   CBQRI_BC_EVT_ID_TOTAL_READ_WRITE, NULL);
+			if (err)
+				goto out_bc;
+
+			s->prev_ctr = 0;
+			*val = s->chunks;
+		} else {
+			struct cbqri_bc_mon_state *s = &bc->mbm_total_states[rmid];
+			u64 cur = ctr_val & CBQRI_BC_MON_CTR_VAL_CTR_MASK;
+
+			s->chunks  += cbqri_bc_mon_overflow(s->prev_ctr, cur);
+			s->prev_ctr = cur;
+			*val        = s->chunks;
+		}
+out_bc:
+		mutex_unlock(&bc->lock);
+		break;
+	}
+
 	default:
 		err = -EINVAL;
 		break;
@@ -773,6 +906,61 @@ static int cbqri_resctrl_pick_bw_alloc(void)
 
 	return 0;
 }
+
+/*
+ * Enable mbm_total_bytes when the system exposes exactly one mon-capable
+ * bandwidth controller and exactly one L3 cache. Pairing a single BC with
+ * multiple L3 domains would let userspace overcount system bandwidth by a
+ * factor equal to the L3 domain count. resctrl_is_mon_event_enabled() then
+ * gates the BC pairing and rmid-space accounting. L3 occupancy is enabled
+ * by cbqri_resctrl_control_init().
+ */
+static void cbqri_resctrl_pick_counters(void)
+{
+	struct cbqri_resctrl_res *l3 = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
+	struct cbqri_controller *ctrl, *prev;
+	unsigned int l3_count = 0;
+
+	/* Count distinct L3 cache_ids */
+	list_for_each_entry(ctrl, &cbqri_controllers, list) {
+		bool seen = false;
+
+		if (ctrl->type != CBQRI_CONTROLLER_TYPE_CAPACITY)
+			continue;
+		if (ctrl->cache.cache_level != 3)
+			continue;
+
+		list_for_each_entry(prev, &cbqri_controllers, list) {
+			if (prev == ctrl)
+				break;
+			if (prev->type != CBQRI_CONTROLLER_TYPE_CAPACITY)
+				continue;
+			if (prev->cache.cache_level != 3)
+				continue;
+			if (prev->cache.cache_id == ctrl->cache.cache_id) {
+				seen = true;
+				break;
+			}
+		}
+		if (!seen)
+			l3_count++;
+	}
+
+	if (l3_count > 1) {
+		pr_warn_once("multiple L3 domains (%u) detected. mbm_total_bytes disabled\n",
+			     l3_count);
+		return;
+	}
+
+	/*
+	 * mbm_total_bytes is surfaced on the L3 monitoring domain, so it
+	 * needs a mon-capable L3 cache controller as well as a single
+	 * mon-capable bandwidth controller.
+	 */
+	if (l3->ctrl && l3->ctrl->mon_capable && cbqri_find_only_mon_bc())
+		resctrl_enable_mon_event(QOS_L3_MBM_TOTAL_EVENT_ID, false, 0, NULL);
+}
+
 static void cbqri_resctrl_accumulate_caps(void)
 {
 	struct cbqri_controller *l3_ctrl;
@@ -798,6 +986,18 @@ static void cbqri_resctrl_accumulate_caps(void)
 	if (l3_ctrl && l3_ctrl->mon_capable)
 		max_rmid = min(max_rmid, l3_ctrl->mcid_count);
 
+	/*
+	 * When mbm_total_bytes is enabled, the paired BC is a second counter
+	 * source, so clamp against its mcid_count too. A BC left unpicked
+	 * because mbm_total_bytes is disabled must not clamp it.
+	 */
+	if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID)) {
+		struct cbqri_controller *bc = cbqri_find_only_mon_bc();
+
+		if (bc)
+			max_rmid = min(max_rmid, bc->mcid_count);
+	}
+
 	if (!exposed_mon_capable) {
 		max_rmid = 1;
 		return;
@@ -854,6 +1054,7 @@ static int cbqri_attach_cpu_to_l3_mon(struct cbqri_controller *ctrl,
 {
 	struct rdt_l3_mon_domain *mon_dom;
 	struct rdt_ctrl_domain *ctrl_dom;
+	struct cbqri_resctrl_dom *hw_dom;
 	struct list_head *mon_pos = NULL;
 	int dom_id = ctrl->cache.cache_id;
 	int err;
@@ -893,6 +1094,27 @@ static int cbqri_attach_cpu_to_l3_mon(struct cbqri_controller *ctrl,
 	else
 		list_add_tail(&mon_dom->hdr.list, &res->mon_domains);
 
+	/*
+	 * Pair this L3 domain with the system's mon-capable BC and
+	 * initialise the BC's per-MCID software accumulators before
+	 * resctrl_online_mon_domain() exposes the domain to userspace.
+	 * A concurrent sysfs read of mbm_total_bytes between online and
+	 * BC init would otherwise pass the !bc->mbm_total_states check
+	 * with a half-initialised pointer.
+	 */
+	hw_dom = container_of(ctrl_dom, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+
+	if (resctrl_is_mon_event_enabled(QOS_L3_MBM_TOTAL_EVENT_ID))
+		hw_dom->paired_bc = cbqri_find_only_mon_bc();
+	if (hw_dom->paired_bc) {
+		err = cbqri_init_bc_mon_counters(hw_dom->paired_bc);
+		if (err) {
+			pr_err("BC @%pa: mon init failed (%d)\n", &hw_dom->paired_bc->addr, err);
+			hw_dom->paired_bc = NULL;
+			goto err_listdel;
+		}
+	}
+
 	err = resctrl_online_mon_domain(res, &mon_dom->hdr);
 	if (err)
 		goto err_listdel;
@@ -1202,6 +1424,8 @@ static int cbqri_resctrl_setup(void)
 	if (err)
 		return err;
 
+	cbqri_resctrl_pick_counters();
+
 	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
 		err = cbqri_resctrl_control_init(&cbqri_resctrl_resources[rid]);
 		if (err)

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:11 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:11 -0700
Subject: [PATCH RFC v6 17/18] ACPI: RISC-V: Add support for RISC-V Quality
 of Service Controller (RQSC)
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-17-baf00f50028a@kernel.org>

Call acpi_parse_rqsc() from acpi_arch_init() to discover CBQRI
controllers when an RQSC table is present.

Gate on CONFIG_RISCV_CBQRI_DRIVER rather than CONFIG_RISCV_ISA_SSQOSID
so a kernel built with the ISA extension but without the driver (e.g.
RESCTRL_FS=n) does not walk the table and print a misleading "found 0
CBQRI controllers" line on every boot.

Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 drivers/acpi/riscv/init.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/acpi/riscv/init.c b/drivers/acpi/riscv/init.c
index 7c00f7995e86..129ebfae28be 100644
--- a/drivers/acpi/riscv/init.c
+++ b/drivers/acpi/riscv/init.c
@@ -5,11 +5,32 @@
  */
 
 #include <linux/acpi.h>
+#include <linux/cleanup.h>
 #include "init.h"
+#include "rqsc.h"
 
 void __init acpi_arch_init(void)
 {
 	riscv_acpi_init_gsi_mapping();
+
 	if (IS_ENABLED(CONFIG_ACPI_RIMT))
 		riscv_acpi_rimt_init();
+
+	if (IS_ENABLED(CONFIG_RISCV_CBQRI_DRIVER)) {
+		struct acpi_table_header *rqsc __free(acpi_put_table) = NULL;
+		acpi_status status = acpi_get_table(ACPI_SIG_RQSC, 0, &rqsc);
+
+		if (status == AE_NOT_FOUND) {
+			/* RQSC is optional. Silence on systems without it. */
+		} else if (ACPI_FAILURE(status)) {
+			pr_err("RQSC: failed to get table: %s\n",
+			       acpi_format_exception(status));
+		} else {
+			int rc = acpi_parse_rqsc(rqsc);
+
+			if (rc < 0)
+				pr_err("RQSC: failed to parse table: %d\n",
+				       rc);
+		}
+	}
 }

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:10 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:10 -0700
Subject: [PATCH RFC v6 16/18] ACPI: RISC-V: Parse RISC-V Quality of Service
 Controller (RQSC) table
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-16-baf00f50028a@kernel.org>

Add a parser for the ACPI RQSC table, which describes the CBQRI
controllers in a system. For each table entry, populate a
cbqri_controller_info descriptor and hand it to the CBQRI driver via
riscv_cbqri_register_controller(). The driver owns all subsequent state,
including cpumask resolution at cbqri_resctrl_setup() time.

Link: https://github.com/riscv-non-isa/riscv-rqsc/blob/main/src/
Link: https://github.com/riscv-non-isa/riscv-cbqri/releases/tag/v1.0
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 MAINTAINERS                   |   2 +
 arch/riscv/include/asm/acpi.h |  10 +++
 drivers/acpi/riscv/Makefile   |   1 +
 drivers/acpi/riscv/rqsc.c     | 202 ++++++++++++++++++++++++++++++++++++++++++
 drivers/acpi/riscv/rqsc.h     |  66 ++++++++++++++
 5 files changed, 281 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 7821dd5159cb..eab31c7b5e91 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23025,6 +23025,8 @@ S:	Supported
 F:	arch/riscv/include/asm/qos.h
 F:	arch/riscv/include/asm/resctrl.h
 F:	arch/riscv/kernel/qos.c
+F:	drivers/acpi/riscv/rqsc.c
+F:	drivers/acpi/riscv/rqsc.h
 F:	drivers/resctrl/cbqri_devices.c
 F:	drivers/resctrl/cbqri_internal.h
 F:	drivers/resctrl/cbqri_resctrl.c
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index 26ab37c171bc..3cfd0102085e 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -67,6 +67,16 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
 
 void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
 			     u32 *cboz_size, u32 *cbop_size);
+
+#ifdef CONFIG_RISCV_CBQRI_DRIVER
+int __init acpi_parse_rqsc(struct acpi_table_header *table);
+#else
+static inline int acpi_parse_rqsc(struct acpi_table_header *table)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_RISCV_CBQRI_DRIVER */
+
 #else
 static inline void acpi_init_rintc_map(void) { }
 static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
index 1284a076fa88..77f8f0101b7e 100644
--- a/drivers/acpi/riscv/Makefile
+++ b/drivers/acpi/riscv/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y					+= rhct.o init.o irq.o
+obj-$(CONFIG_RISCV_CBQRI_DRIVER)	+= rqsc.o
 obj-$(CONFIG_ACPI_PROCESSOR_IDLE)	+= cpuidle.o
 obj-$(CONFIG_ACPI_CPPC_LIB)		+= cppc.o
 obj-$(CONFIG_ACPI_RIMT)			+= rimt.o
diff --git a/drivers/acpi/riscv/rqsc.c b/drivers/acpi/riscv/rqsc.c
new file mode 100644
index 000000000000..1b1ae2e353a5
--- /dev/null
+++ b/drivers/acpi/riscv/rqsc.c
@@ -0,0 +1,202 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "ACPI: RQSC: " fmt
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/riscv_cbqri.h>
+
+#include "rqsc.h"
+
+#define CBQRI_CTRL_SIZE 0x1000
+
+int __init acpi_parse_rqsc(struct acpi_table_header *table)
+{
+	struct acpi_table_rqsc *rqsc = (struct acpi_table_rqsc *)table;
+	struct acpi_rqsc_node *end, *node;
+	int num_controllers = 0;
+
+	/*
+	 * Reject revisions newer than this parser was written against. A
+	 * future revision could extend the fixed RQSC header before the
+	 * first node, which would shift the resource subtables and cause the
+	 * sizeof(*node)-based offset below to point into the wrong place.
+	 */
+	if (rqsc->header.revision != ACPI_RQSC_REVISION) {
+		pr_err("RQSC table revision %u, expected %u, aborting\n",
+		       rqsc->header.revision, ACPI_RQSC_REVISION);
+		return -EINVAL;
+	}
+
+	/* Reject tables shorter than the fixed RQSC header. */
+	if (rqsc->header.length < sizeof(struct acpi_table_rqsc)) {
+		pr_err("RQSC table truncated: length %u < %zu, aborting\n",
+		       rqsc->header.length, sizeof(struct acpi_table_rqsc));
+		return -EINVAL;
+	}
+
+	end = ACPI_ADD_PTR(struct acpi_rqsc_node, rqsc, rqsc->header.length);
+
+	for (node = ACPI_ADD_PTR(struct acpi_rqsc_node, rqsc,
+				 sizeof(struct acpi_table_rqsc));
+	     node < end;
+	     node = ACPI_ADD_PTR(struct acpi_rqsc_node, node, node->length)
+	) {
+		const struct acpi_rqsc_resource *res0;
+		struct cbqri_controller_info info = {};
+		int ret;
+
+		if ((void *)node + sizeof(*node) > (void *)end) {
+			pr_err("truncated entry at end of table, aborting\n");
+			riscv_cbqri_unregister_last(num_controllers);
+			return -EINVAL;
+		}
+
+		if (node->length < sizeof(*node)) {
+			pr_err("malformed RQSC entry: length %u < %zu, aborting\n",
+			       node->length, sizeof(*node));
+			riscv_cbqri_unregister_last(num_controllers);
+			return -EINVAL;
+		}
+
+		/*
+		 * Without this check, a node whose length claims to extend
+		 * past the end of the table would advance the loop cursor
+		 * past 'end' and silently terminate. Flag the corruption
+		 * explicitly so a malformed firmware table cannot truncate
+		 * the controller list without noise.
+		 */
+		if ((void *)node + node->length > (void *)end) {
+			pr_err("RQSC entry length %u overruns table end, aborting\n",
+			       node->length);
+			riscv_cbqri_unregister_last(num_controllers);
+			return -EINVAL;
+		}
+
+		/* GAS must describe system memory. ioremap() consumes it later. */
+		if (node->reg.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+			pr_warn("controller has unsupported address space_id=%u, skipping\n",
+				node->reg.space_id);
+			continue;
+		}
+
+		if (!node->reg.address) {
+			pr_warn("controller has zero address, skipping\n");
+			continue;
+		}
+
+		info.type = node->type;
+		/* RQSC section 2 Table 2: 12-byte GAS-format register interface address */
+		info.addr = node->reg.address;
+		info.size = CBQRI_CTRL_SIZE;
+		info.rcid_count = node->rcid;
+		info.mcid_count = node->mcid;
+
+		/* See CBQRI_MAX_RCID/MCID in <linux/riscv_cbqri.h> for the rationale. */
+		if (info.rcid_count > CBQRI_MAX_RCID) {
+			pr_warn("controller at %pa: rcid_count %u exceeds CBQRI_MAX_RCID %u, skipping\n",
+				&info.addr, info.rcid_count, CBQRI_MAX_RCID);
+			continue;
+		}
+
+		if (info.mcid_count > CBQRI_MAX_MCID) {
+			pr_warn("controller at %pa: mcid_count %u exceeds CBQRI_MAX_MCID %u, skipping\n",
+				&info.addr, info.mcid_count, CBQRI_MAX_MCID);
+			continue;
+		}
+
+		/*
+		 * RQSC Table 2: at least one of RCID Count or MCID Count must be non-zero.
+		 */
+		if (!info.rcid_count && !info.mcid_count) {
+			pr_warn("controller at %pa: both rcid_count and mcid_count are zero, skipping\n",
+				&info.addr);
+			continue;
+		}
+
+		if (node->nres == 0) {
+			pr_warn("controller at %pa has no resource descriptors, skipping\n",
+				&info.addr);
+			continue;
+		}
+
+		/*
+		 * Resources follow the node header in-line. Only res[0] is
+		 * consumed. Bound it against end before reading its prefix so
+		 * a table that ends partway through a resource subtable is
+		 * rejected rather than read past the mapping.
+		 */
+		res0 = (const struct acpi_rqsc_resource *)
+		       ((const u8 *)node + sizeof(*node));
+		if ((void *)res0 + sizeof(*res0) > (void *)end ||
+		    node->length < sizeof(*node) + sizeof(*res0) ||
+		    res0->length < sizeof(*res0)) {
+			pr_warn("controller at %pa: node too short for resource descriptor, skipping\n",
+				&info.addr);
+			continue;
+		}
+
+		if (node->nres > 1)
+			pr_warn("controller at %pa has %u resource descriptors, using first\n",
+				&info.addr, node->nres);
+
+		/*
+		 * id1 is u64 but it is used for cache_id and prox_dom
+		 * which are only u32. Reject rather than truncate, so a
+		 * too large id is not silently mapped to the wrong PPTT
+		 * entry or NUMA node.
+		 */
+		if (res0->id1 > U32_MAX) {
+			pr_warn("controller at %pa: id1 0x%llx exceeds u32, skipping\n",
+				&info.addr, res0->id1);
+			continue;
+		}
+
+		/*
+		 * Pair the QoS controller type with the resource descriptor
+		 * fields that index id1. RQSC Table 4 defines the mapping:
+		 * Capacity controller indexes a Processor Cache via PPTT
+		 * cache_id, a Bandwidth controller indexes a Memory Range
+		 * via SRAT proximity domain. Mismatched pairings  (e.g. a
+		 * CC whose first resource is Memory) would otherwise route
+		 * id1 into the wrong downstream lookup.
+		 */
+		switch (info.type) {
+		case CBQRI_CONTROLLER_TYPE_CAPACITY:
+			if (res0->type != ACPI_RQSC_RESOURCE_TYPE_CACHE ||
+			    res0->id_type != ACPI_RQSC_RESOURCE_ID_TYPE_PROCESSOR_CACHE) {
+				pr_warn("CC at %pa: resource type=%u id_type=%u not (cache, processor cache), skipping\n",
+					&info.addr, res0->type, res0->id_type);
+				continue;
+			}
+			info.cache_id = (u32)res0->id1;
+			break;
+		case CBQRI_CONTROLLER_TYPE_BANDWIDTH:
+			if (res0->type != ACPI_RQSC_RESOURCE_TYPE_MEMORY ||
+			    res0->id_type != ACPI_RQSC_RESOURCE_ID_TYPE_MEMORY_RANGE) {
+				pr_warn("BC at %pa: resource type=%u id_type=%u not (memory, memory range), skipping\n",
+					&info.addr, res0->type, res0->id_type);
+				continue;
+			}
+			info.prox_dom = (u32)res0->id1;
+			break;
+		default:
+			pr_warn("controller at %pa: unknown type %u, skipping\n",
+				&info.addr, info.type);
+			continue;
+		}
+
+		pr_debug("registering controller type=%u addr=%pa rcid=%u mcid=%u\n",
+			 info.type, &info.addr, info.rcid_count, info.mcid_count);
+
+		ret = riscv_cbqri_register_controller(&info);
+		if (ret == 0)
+			num_controllers++;
+		else
+			pr_warn("controller at %pa: registration failed (%d), skipping\n",
+				&info.addr, ret);
+	}
+
+	pr_info("found %d CBQRI controllers\n", num_controllers);
+	return 0;
+}
diff --git a/drivers/acpi/riscv/rqsc.h b/drivers/acpi/riscv/rqsc.h
new file mode 100644
index 000000000000..fa0d96e267e1
--- /dev/null
+++ b/drivers/acpi/riscv/rqsc.h
@@ -0,0 +1,66 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Local definitions for the RISC-V Quality of Service Controller (RQSC)
+ * ACPI table. Will move to ACPICA's include/acpi/actbl2.h once the spec
+ * is ratified.
+ */
+#ifndef _DRIVERS_ACPI_RISCV_RQSC_H
+#define _DRIVERS_ACPI_RISCV_RQSC_H
+
+#include <linux/types.h>
+#include <acpi/actbl.h>
+
+#define ACPI_SIG_RQSC	"RQSC"	/* RISC-V Quality of Service Controller */
+
+/* RQSC Table 1: current revision number. */
+#define ACPI_RQSC_REVISION	1
+
+/* RQSC Table 4: Resource Type values for acpi_rqsc_resource.type. */
+#define ACPI_RQSC_RESOURCE_TYPE_CACHE	0
+#define ACPI_RQSC_RESOURCE_TYPE_MEMORY	1
+
+/* RQSC Table 4: Resource ID Type values for .id_type. */
+#define ACPI_RQSC_RESOURCE_ID_TYPE_PROCESSOR_CACHE	0
+#define ACPI_RQSC_RESOURCE_ID_TYPE_MEMORY_RANGE		1
+#define ACPI_RQSC_RESOURCE_ID_TYPE_MEMORY_SIDE_CACHE	2
+#define ACPI_RQSC_RESOURCE_ID_TYPE_ACPI_DEVICE		3
+#define ACPI_RQSC_RESOURCE_ID_TYPE_PCI_DEVICE		4
+
+/*
+ * Byte-packed: u64 id1 would otherwise pad to 8-byte alignment and inflate
+ * sizeof(*res) from the spec's 20 bytes to 24, mis-sizing resource subtables.
+ */
+struct acpi_rqsc_resource {
+	u8 type;
+	u8 resv;
+	u16 length;
+	u16 flags;
+	u8 resv2;
+	u8 id_type;
+	u64 id1;
+	u32 id2;
+} __packed;
+
+struct acpi_rqsc_node {
+	u8 type;
+	u8 resv;
+	u16 length;
+	/* RQSC section 2 Table 2: 12-byte GAS-format register interface address */
+	struct acpi_generic_address reg;
+	u16 rcid;
+	u16 mcid;
+	u16 flags;
+	u16 nres;
+	/*
+	 * Followed by nres acpi_rqsc_resource subtables. Walk them via
+	 * each resource's own length field so a future RQSC revision that
+	 * extends the resource layout cannot misalign older parsers.
+	 */
+} __packed;
+
+struct acpi_table_rqsc {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 num;
+} __packed;
+
+#endif /* _DRIVERS_ACPI_RISCV_RQSC_H */

-- 
2.43.0



From fustini at kernel.org  Mon Jun  1 13:36:12 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 01 Jun 2026 13:36:12 -0700
Subject: [PATCH RFC v6 18/18] riscv: enable resctrl filesystem for Ssqosid
In-Reply-To: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
References: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-0-baf00f50028a@kernel.org>
Message-ID: <20260601-ssqosid-cbqri-rqsc-v7-0-v6-18-baf00f50028a@kernel.org>

RISCV_ISA_SSQOSID selects RISCV_CBQRI_DRIVER unconditionally.

The resctrl filesystem integration is gated separately by
RISCV_CBQRI_RESCTRL_FS, a silent option that defaults to y when both
RISCV_CBQRI_DRIVER and RESCTRL_FS are enabled. Enabling the resctrl
filesystem itself stays a user choice via the standard fs/Kconfig
MISC_FILESYSTEMS menu.

Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 arch/riscv/Kconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 390353a6153a..dd65248df117 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -596,6 +596,7 @@ config RISCV_ISA_SSQOSID
 	depends on 64BIT
 	default n
 	select ARCH_HAS_CPU_RESCTRL
+	select RISCV_CBQRI_DRIVER
 	help
 	  Adds support for the Ssqosid ISA extension (Supervisor-mode
 	  Quality of Service ID).

-- 
2.43.0



From schwab at linux-m68k.org  Mon Jun  1 13:58:52 2026
From: schwab at linux-m68k.org (Andreas Schwab)
Date: Mon, 01 Jun 2026 22:58:52 +0200
Subject: [PATCH v23 06/28] riscv/mm : ensure PROT_WRITE leads to VM_READ
 | VM_WRITE
In-Reply-To: <CAKC1njR+dTdvp+BmLGPtgd8dufiUwBtkQ9a-qinELT_Fmi13sQ@mail.gmail.com>
	(Deepak Gupta's message of "Mon, 1 Jun 2026 10:57:41 -0700")
References: <20251112-v5_user_cfi_series-v23-0-b55691eacf4f@rivosinc.com>
	<20251112-v5_user_cfi_series-v23-6-b55691eacf4f@rivosinc.com>
	<87jyslndo4.fsf@igel.home>
	<CAKC1njS=AHu6uHrH4ae8VxcdEbhgiPXYCAoN3F_mnppBd3SwOA@mail.gmail.com>
	<875x44o9hj.fsf@igel.home>
	<CAKC1njSn_rtCj8ii876PNQTk0nsCTfWsb4DzdymufHVthh1Rkg@mail.gmail.com>
	<871peqgp9v.fsf@igel.home>
	<CAKC1njR+dTdvp+BmLGPtgd8dufiUwBtkQ9a-qinELT_Fmi13sQ@mail.gmail.com>
Message-ID: <87wlwif04z.fsf@igel.home>

On Jun 01 2026, Deepak Gupta wrote:

> riscv uses `VM_SHADOW_STACK`. It's just very simple to use `protection_map`
> with just `VM_WRITE`. On RISC-V, `-W-` is a shadow stack mapping. It's not same
> on x86 or arm64. So `protection_map[VM_WRITE]` simply picks shadow stack
> encoding. We just ensure that PROT_WRITE is converted to
> "VM_READ | VM_WRITE" at vma level.

That does not explain _why_ you need to make that user visible change,
when others can get away without it.

-- 
Andreas Schwab, schwab at linux-m68k.org
GPG Key fingerprint = 7578 EB47 D4E5 4D69 2510  2552 DF73 E780 A9DA AEC1
"And now for something completely different."


From fustini at kernel.org  Mon Jun  1 16:06:38 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 1 Jun 2026 16:06:38 -0700
Subject: [GIT PULL] RISC-V Tenstorrent devicetree changes for v7.2
Message-ID: <ah4Qfro/wUyhByF8@x1>

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git tags/tenstorrent-dt-for-v7.2

for you to fetch changes up to 33583baeb1ba7d328e6a9775d889036900b74cdb:

  dt-bindings: iommu: riscv: Add bindings for Tenstorrent RISC-V IOMMU (2026-05-23 17:14:35 -0700)

----------------------------------------------------------------
Tenstorrent device tree for v7.2

Add a riscv,pmu node to the Tenstorrent Blackhole SoC device tree. This
enables OpenSBI to expose the SBI PMU extension, allowing Linux perf to
use the 4 programmable counters (mhpmcounter3-6) across 3 event classes:
instruction commit, microarchitectural, and memory system events.

Extend the RISC-V IOMMU device tree bindings to document the Tenstorrent
IOMMU used in the Tenstorrent Atlantis SoC. A second register range is
added which contains M-mode only registers like PMAs and PMPs. The
binding will be used by OpenSBI and potentially other M-mode software.

----------------------------------------------------------------
Michael Neuling (1):
      riscv: dts: tenstorrent: Add PMU node to blackhole for Linux perf support

Nicholas Piggin (1):
      dt-bindings: iommu: riscv: Add bindings for Tenstorrent RISC-V IOMMU

 .../devicetree/bindings/iommu/riscv,iommu.yaml     | 59 +++++++++++++++++++---
 arch/riscv/boot/dts/tenstorrent/blackhole.dtsi     | 48 ++++++++++++++++++
 2 files changed, 99 insertions(+), 8 deletions(-)


From fustini at kernel.org  Mon Jun  1 17:36:33 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 1 Jun 2026 17:36:33 -0700
Subject: [GIT PULL] RISC-V T-HEAD devicetree changes for v7.2
Message-ID: <ah4lkWh2eD6l7W7n@x1>

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git tags/thead-dt-for-v7.2

for you to fetch changes up to 3a5791956edbfa84d7256224167941931cbc46e7:

  riscv: dts: thead: Enable wifi on the BeagleV-Ahead (2026-05-25 01:36:56 -0700)

----------------------------------------------------------------
T-HEAD Devicetrees for 7.2

Enable wifi on two TH1520 boards: BeagleV Ahead and Lichee Pi 4a.

The BeagleV Ahead board uses an AP6203BM WiFi module connected to SDIO1.
The Lichee Pi 4A has an RTL8723DS WiFi module also connected to SDIO1.
The module reset line is driven through a PCA9557 GPIO expander on the
I2C1 bus.

----------------------------------------------------------------
MoeLeak (2):
      riscv: dts: thead: Add TH1520 I2C1 controller
      riscv: dts: thead: Enable WiFi on Lichee Pi 4A

Thomas Gerner (1):
      riscv: dts: thead: Enable wifi on the BeagleV-Ahead

 arch/riscv/boot/dts/thead/th1520-beaglev-ahead.dts | 48 ++++++++++++++++++++++
 arch/riscv/boot/dts/thead/th1520-lichee-pi-4a.dts  | 47 +++++++++++++++++++++
 arch/riscv/boot/dts/thead/th1520.dtsi              | 11 +++++
 3 files changed, 106 insertions(+)


From ruanjinjie at huawei.com  Mon Jun  1 18:43:26 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Tue, 2 Jun 2026 09:43:26 +0800
Subject: [PATCH v15 00/23] arm64/riscv: Add support for crashkernel CMA
 reservation
In-Reply-To: <ah2Lx7KHI60tzd0v@MiWiFi-R3L-srv>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
 <ah2Lx7KHI60tzd0v@MiWiFi-R3L-srv>
Message-ID: <1a459706-80db-43d8-b163-76fc09da338d@huawei.com>



On 6/1/2026 9:40 PM, Baoquan He wrote:
> Hi Jinjie,
> 
> On 06/01/26 at 05:47pm, Jinjie Ruan wrote:
> ...snip... 
>> Changes in v15:
>> - Unify the subject prefix formats as Huacai suggested.
>> - Fix powerpc pre-existing NULL pointer dereference [Sashiko [1]]
>> - Fix powerpc pre-existing __merge_memory_ranges() memory range
>>   truncation [Sashiko [1]].
>> - Fix pre-existing arm64 CMA page leaks [Sashiko[2]].
>> - Fix pre-existing crash_load_dm_crypt_keys() Use-After-Free and
>>   Double Free issue [Sashiko[3]].
>> - Fix vfree(headers) and uninitialized variables issue
>>   and simplify the fix [Sashiko[2]].
>> - As walk_system_ram_res() and for_each_mem_range() use different
>>   lock, unify and simplify the fix of TOCTOU buffer overflow via memory
>>   region padding [Sashiko[4]].
>> - Fix the arm64 crash dump issues in Sashiko[5].
>> - Link to v14: https://lore.kernel.org/all/20260525084932.934910-1-ruanjinjie at huawei.com/
> 
> Do these Fixes have anything with the main target of this patch series
> you mentioned in cover-letter:"arm64/riscv: Add support for crashkernel CMA"?
> The patches become more and more in each new version, I am wondering if
> it relies on these Fixes patches to implement your adding support for
> crashkernel CMA on arm64/risc-v.
> 
> If not relying on them, could you split them into different patchset
> on different purpose? 

Hi Baoquan,

Thank you for your valuable guidance.

You are absolutely right. Most of these fix patches are indeed not
strictly related to the core implementation of the crashkernel CMA
support. They are pre-existing bugs in the surrounding kexec/crash code
that were flagged during our review.

Previously, Andrew suggested taking a look at the code review comments
from the Sashiko AI system, which is why these fixes kept expanding. I
completely agree with your advice that there is no need to keep them
together. I will split them into two completely different patchsets
based on their purpose:

1. A cleaner version of this series, strictly focused on adding the core
crashkernel CMA support for arm64/riscv.

2. One standalone bugfix patchset dedicated entirely to fixing these
pre-existing issues.

By the way, I would also appreciate some advice on how to handle further
AI reviews. It seems that the more code we touch or refactor to fix
these pre-existing issues, the more tangential bugs the AI flags in the
newly exposed areas, making the series extremely difficult to converge.

Should I continue to address all AI-reported bugs associated with the
surrounding code in this series, or should we draw a strict line
and only focus on the core CMA logic moving forward?

I will prepare the split patchsets shortly. Thanks again for
straightening this out!

Best regards,
Jinjie Ruan


> 
> Thanks
> Baoquan
> 
>>
>> [1]: https://lore.kernel.org/all/20260525092207.96B9D1F000E9 at smtp.kernel.org/
>> [2]: https://lore.kernel.org/all/20260525091149.1A1E01F00A3D at smtp.kernel.org/
>> [3]: https://lore.kernel.org/all/20260525105227.3C2421F000E9 at smtp.kernel.org/
>> [4]: https://lore.kernel.org/all/20260525095447.944E11F000E9 at smtp.kernel.org/
>> [5]: https://lore.kernel.org/all/20260525101746.9959D1F000E9 at smtp.kernel.org/
>>
>> Changes in v14:
>> - Fix image->elf_headers memory leak during retry loop for arm64 as Sashiko
>>   AI code review pointed out.
>> - Solve the hotplug notifier arch_crash_handle_hotplug_event() AA
>>   self-deadlock problem as Sashiko AI code review pointed out.
>> - Fix the TOCTOU issue in prepare_elf_headers() by get_online_mems().
>> - -ENOMEM -> -EAGAIN as Breno suggested.
>> - Add support for arm64 crash hotplug.
>> - Link to v13: https://lore.kernel.org/all/20260511030454.1730881-1-ruanjinjie at huawei.com/
>>

[...]
>>  24 files changed, 430 insertions(+), 338 deletions(-)
>>  create mode 100644 arch/arm64/kernel/crash.c
>>
>> -- 
>> 2.34.1
>>



From baoquan.he at linux.dev  Mon Jun  1 20:06:11 2026
From: baoquan.he at linux.dev (Baoquan He)
Date: Tue, 2 Jun 2026 11:06:11 +0800
Subject: [PATCH v15 00/23] arm64/riscv: Add support for crashkernel CMA
 reservation
In-Reply-To: <1a459706-80db-43d8-b163-76fc09da338d@huawei.com>
References: <20260601094805.2928614-1-ruanjinjie@huawei.com>
 <ah2Lx7KHI60tzd0v@MiWiFi-R3L-srv>
 <1a459706-80db-43d8-b163-76fc09da338d@huawei.com>
Message-ID: <ah5Ioxs9aLxKIKWg@MiWiFi-R3L-srv>

On 06/02/26 at 09:43am, Jinjie Ruan wrote:
> 
> 
> On 6/1/2026 9:40 PM, Baoquan He wrote:
> > Hi Jinjie,
> > 
> > On 06/01/26 at 05:47pm, Jinjie Ruan wrote:
> > ...snip... 
> >> Changes in v15:
> >> - Unify the subject prefix formats as Huacai suggested.
> >> - Fix powerpc pre-existing NULL pointer dereference [Sashiko [1]]
> >> - Fix powerpc pre-existing __merge_memory_ranges() memory range
> >>   truncation [Sashiko [1]].
> >> - Fix pre-existing arm64 CMA page leaks [Sashiko[2]].
> >> - Fix pre-existing crash_load_dm_crypt_keys() Use-After-Free and
> >>   Double Free issue [Sashiko[3]].
> >> - Fix vfree(headers) and uninitialized variables issue
> >>   and simplify the fix [Sashiko[2]].
> >> - As walk_system_ram_res() and for_each_mem_range() use different
> >>   lock, unify and simplify the fix of TOCTOU buffer overflow via memory
> >>   region padding [Sashiko[4]].
> >> - Fix the arm64 crash dump issues in Sashiko[5].
> >> - Link to v14: https://lore.kernel.org/all/20260525084932.934910-1-ruanjinjie at huawei.com/
> > 
> > Do these Fixes have anything with the main target of this patch series
> > you mentioned in cover-letter:"arm64/riscv: Add support for crashkernel CMA"?
> > The patches become more and more in each new version, I am wondering if
> > it relies on these Fixes patches to implement your adding support for
> > crashkernel CMA on arm64/risc-v.
> > 
> > If not relying on them, could you split them into different patchset
> > on different purpose? 
> 
> Hi Baoquan,
> 
> Thank you for your valuable guidance.
> 
> You are absolutely right. Most of these fix patches are indeed not
> strictly related to the core implementation of the crashkernel CMA
> support. They are pre-existing bugs in the surrounding kexec/crash code
> that were flagged during our review.
> 
> Previously, Andrew suggested taking a look at the code review comments
> from the Sashiko AI system, which is why these fixes kept expanding. I
> completely agree with your advice that there is no need to keep them
> together. I will split them into two completely different patchsets
> based on their purpose:
> 
> 1. A cleaner version of this series, strictly focused on adding the core
> crashkernel CMA support for arm64/riscv.
> 
> 2. One standalone bugfix patchset dedicated entirely to fixing these
> pre-existing issues.
> 
> By the way, I would also appreciate some advice on how to handle further
> AI reviews. It seems that the more code we touch or refactor to fix
> these pre-existing issues, the more tangential bugs the AI flags in the
> newly exposed areas, making the series extremely difficult to converge.
> 
> Should I continue to address all AI-reported bugs associated with the
> surrounding code in this series, or should we draw a strict line
> and only focus on the core CMA logic moving forward?

Then please post patches to focus on the core implementation of the
crashkernel CMA support. If any AI reported bugs are raised but not
relatd to it, you can add note in cover-letter or explain somewhere
to tell whehter it's caused by the core code and how you want
to deal with it. Otherwise, you could go round and round of new posting
and still can't see when it ends up.



From osalvador at kernel.org  Mon Jun  1 21:40:24 2026
From: osalvador at kernel.org (Oscar Salvador (SUSE))
Date: Tue, 2 Jun 2026 06:40:24 +0200
Subject: [PATCH v3 1/5] mm/sparse-vmemmap: provide generic
 vmemmap_set_pmd() and vmemmap_check_pmd()
In-Reply-To: <0D4AF42F-37C5-4A76-9703-44ACC6374C48@linux.dev>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-2-songmuchun@bytedance.com>
 <db8d440d-c8a1-4f77-b5d9-00bab8737f12@kernel.org>
 <0D4AF42F-37C5-4A76-9703-44ACC6374C48@linux.dev>
Message-ID: <ah5euKU9l3pP_8Ty@localhost.localdomain>

On Mon, Jun 01, 2026 at 08:37:42PM +0800, Muchun Song wrote:
> 
> 
> > On Jun 1, 2026, at 20:22, David Hildenbrand (Arm) <david at kernel.org> wrote:
> > 
> > On 6/1/26 10:48, Muchun Song wrote:
> >> The two weak functions are currently no-ops on every architecture,
> >> forcing each platform that needs them to duplicate the same handful
> >> of lines.  Provide a generic implementation:
> >> 
> >> - vmemmap_set_pmd() simply sets a huge PMD with PAGE_KERNEL protection.
> >> 
> >> - vmemmap_check_pmd() verifies that the PMD is present and leaf,
> >>  then calls the existing vmemmap_verify() helper.
> >> 
> >> Architectures that need special handling can continue to override the
> >> weak symbols; everyone else gets the standard version for free.
> >> 
> >> Signed-off-by: Muchun Song <songmuchun at bytedance.com>
> >> ---
> >> v2->v3:
> >> - Replace BUG_ON() with WARN_ON_ONCE() in vmemmap_set_pmd()
> >> ---
> >> mm/sparse-vmemmap.c | 7 ++++++-
> >> 1 file changed, 6 insertions(+), 1 deletion(-)
> >> 
> >> diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
> >> index 112ccf9c71ca..99e2be39671b 100644
> >> --- a/mm/sparse-vmemmap.c
> >> +++ b/mm/sparse-vmemmap.c
> >> @@ -386,12 +386,17 @@ int __meminit vmemmap_populate_hvo(unsigned long addr, unsigned long end,
> >> void __weak __meminit vmemmap_set_pmd(pmd_t *pmd, void *p, int node,
> >>       unsigned long addr, unsigned long next)
> >> {
> >> + 	WARN_ON_ONCE(!pmd_set_huge(pmd, virt_to_phys(p), PAGE_KERNEL));
> > 
> > 
> > Not sure if a VM_WARN_ON_ONCE() would be appropriate. (then, we have to move the
> > pmd_set_huge() out of the statement).
> 
> I think it might be better to keep WARN_ON_ONCE here. This way, we can still
> monitor for warnings in production while keeping the code simple.

IIRC there was a discussion about this some time ago, given the fact that quite
some people out there tend to have 'panic_on_warn', but then again, if we fail to
set a PMD here it means something pretty nasty happened, so I am ok with that.

 

-- 
Oscar Salvador
SUSE Labs


From osalvador at kernel.org  Mon Jun  1 21:41:14 2026
From: osalvador at kernel.org (Oscar Salvador (SUSE))
Date: Tue, 2 Jun 2026 06:41:14 +0200
Subject: [PATCH v3 1/5] mm/sparse-vmemmap: provide generic
 vmemmap_set_pmd() and vmemmap_check_pmd()
In-Reply-To: <20260601084845.3792171-2-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-2-songmuchun@bytedance.com>
Message-ID: <ah5e6i8EfoLUnyn2@localhost.localdomain>

On Mon, Jun 01, 2026 at 04:48:40PM +0800, Muchun Song wrote:
> The two weak functions are currently no-ops on every architecture,
> forcing each platform that needs them to duplicate the same handful
> of lines.  Provide a generic implementation:
> 
> - vmemmap_set_pmd() simply sets a huge PMD with PAGE_KERNEL protection.
> 
> - vmemmap_check_pmd() verifies that the PMD is present and leaf,
>   then calls the existing vmemmap_verify() helper.
> 
> Architectures that need special handling can continue to override the
> weak symbols; everyone else gets the standard version for free.
> 
> Signed-off-by: Muchun Song <songmuchun at bytedance.com>

Acked-by: Oscar Salvador (SUSE) <osalvador at kernel.org>

 

-- 
Oscar Salvador
SUSE Labs


From osalvador at kernel.org  Mon Jun  1 21:42:45 2026
From: osalvador at kernel.org (Oscar Salvador (SUSE))
Date: Tue, 2 Jun 2026 06:42:45 +0200
Subject: [PATCH v3 2/5] arm64/mm: drop vmemmap_pmd helpers and use
 generic code
In-Reply-To: <20260601084845.3792171-3-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-3-songmuchun@bytedance.com>
Message-ID: <ah5fRXPvpOSmKoxl@localhost.localdomain>

On Mon, Jun 01, 2026 at 04:48:41PM +0800, Muchun Song wrote:
> The generic implementations now suffice; remove the arm64 copies.
> 
> Signed-off-by: Muchun Song <songmuchun at bytedance.com>
> Acked-by: Will Deacon <will at kernel.org>

Reviewed-by: Oscar Salvador (SUSE) <osalvador at kernel.org>

> ---
> v2->v3:
> - Collect Acked-by from Will Deacon
> ---
>  arch/arm64/mm/mmu.c | 14 --------------
>  1 file changed, 14 deletions(-)
> 
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 24388e5c727d..ea10b0ebecd7 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -1776,20 +1776,6 @@ static void free_empty_tables(unsigned long addr, unsigned long end,
>  }
>  #endif
>  
> -void __meminit vmemmap_set_pmd(pmd_t *pmdp, void *p, int node,
> -			       unsigned long addr, unsigned long next)
> -{
> -	pmd_set_huge(pmdp, __pa(p), __pgprot(PROT_SECT_NORMAL));
> -}
> -
> -int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node,
> -				unsigned long addr, unsigned long next)
> -{
> -	vmemmap_verify((pte_t *)pmdp, node, addr, next);
> -
> -	return pmd_leaf(READ_ONCE(*pmdp));
> -}
> -
>  int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
>  		struct vmem_altmap *altmap)
>  {
> -- 
> 2.54.0
> 
> 

-- 
Oscar Salvador
SUSE Labs


From osalvador at kernel.org  Mon Jun  1 21:44:42 2026
From: osalvador at kernel.org (Oscar Salvador (SUSE))
Date: Tue, 2 Jun 2026 06:44:42 +0200
Subject: [PATCH v3 3/5] riscv/mm: drop vmemmap_pmd helpers and use
 generic code
In-Reply-To: <20260601084845.3792171-4-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-4-songmuchun@bytedance.com>
Message-ID: <ah5fusGeBmwsZuIm@localhost.localdomain>

On Mon, Jun 01, 2026 at 04:48:42PM +0800, Muchun Song wrote:
> The generic implementations now suffice; remove the riscv copies.
> 
> Signed-off-by: Muchun Song <songmuchun at bytedance.com>

Reviewed-by: Oscar Salvador (SUSE) <osalvador at kernel.org>

 

-- 
Oscar Salvador
SUSE Labs


From osalvador at kernel.org  Mon Jun  1 21:45:32 2026
From: osalvador at kernel.org (Oscar Salvador (SUSE))
Date: Tue, 2 Jun 2026 06:45:32 +0200
Subject: [PATCH v3 4/5] loongarch/mm: drop vmemmap_check_pmd helper and
 use generic code
In-Reply-To: <20260601084845.3792171-5-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-5-songmuchun@bytedance.com>
Message-ID: <ah5f7NlrmO0bw-pX@localhost.localdomain>

On Mon, Jun 01, 2026 at 04:48:43PM +0800, Muchun Song wrote:
> The generic implementations now suffice; remove the loongarch copies.
> 
> Signed-off-by: Muchun Song <songmuchun at bytedance.com>

Reviewed-by: Oscar Salvador (SUSE) <osalvador at kernel.org>

 

-- 
Oscar Salvador
SUSE Labs


From osalvador at kernel.org  Mon Jun  1 21:46:55 2026
From: osalvador at kernel.org (Oscar Salvador (SUSE))
Date: Tue, 2 Jun 2026 06:46:55 +0200
Subject: [PATCH v3 5/5] sparc/mm: drop vmemmap_check_pmd helper and use
 generic code
In-Reply-To: <20260601084845.3792171-6-songmuchun@bytedance.com>
References: <20260601084845.3792171-1-songmuchun@bytedance.com>
 <20260601084845.3792171-6-songmuchun@bytedance.com>
Message-ID: <ah5gPx1TuEH1wFzC@localhost.localdomain>

On Mon, Jun 01, 2026 at 04:48:44PM +0800, Muchun Song wrote:
> The generic implementations now suffice; remove the sparc copies.
> 
> Signed-off-by: Muchun Song <songmuchun at bytedance.com>

Reviewed-by: Oscar Salvador (SUSE) <osalvador at kernel.org>

 

-- 
Oscar Salvador
SUSE Labs


From dlan at kernel.org  Mon Jun  1 23:17:34 2026
From: dlan at kernel.org (Yixun Lan)
Date: Tue, 2 Jun 2026 06:17:34 +0000
Subject: [PATCH] MAINTAINERS: add entry for SpacemiT reset controller
 driver
In-Reply-To: <20260601-b4-spacemit-reset-maintainers-v1-1-1ab3014e9a35@gmail.com>
References: <20260601-b4-spacemit-reset-maintainers-v1-1-1ab3014e9a35@gmail.com>
Message-ID: <20260602061734-GKD3815935@kernel.org>

Hi Guodong,

I appreciate someone help on this, only few comments.

On 21:35 Mon 01 Jun     , Guodong Xu wrote:
> The SpacemiT reset controller driver under drivers/reset/spacemit/
> (common code plus the K1 and K3 SoC instances) and its reset-ID header
> have no dedicated MAINTAINERS entry; today they fall only under the
> broad drivers/reset/ entry of the reset subsystem and the N:/K:
> catch-all of the RISC-V SpacemiT SoC umbrella.
> 
It make sense to just fall back to SpacemiT SoC without MAITAINERS
entry, the whole point of adding a didicated entry means someone
willing to put effort in future maintenance, to help review/refactor/fix
you can emphasis on this, and I just want to make sure we algined on
this..

> Add a dedicated entry and list myself as maintainer. I introduced the
> drivers/reset/spacemit/ subdirectory, moved and refactored the existing
> K1 reset support (originally written by Alex Elder) into it, and wrote
> the K3 reset driver. The series that created this directory and these
> files is archived at [1].
> 
This paragraph provide addtional information of the history (which already 
done), I'd personally prefer not puting them into commit message, but put
them below "---" as background introduction if you still want..

> [1] https://lore.kernel.org/spacemit/20260120-k3-reset-v3-0-effe87f4bdbe at riscstar.com/
for the convention, suggest to use more formal format like 
Link: https://.. [1]

> 
also no blank line above

> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> ---
> I contributed this driver as Guodong Xu <guodong at riscstar.com>;
> docular.xu at gmail.com is my current address. A matching .mailmap update
> has been submitted at
> https://lore.kernel.org/all/20260601-b4-mailmap-guodong-xu-v1-1-ee9eff1e57ba at gmail.com/
> ---
>  MAINTAINERS | 7 +++++++
>  1 file changed, 7 insertions(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 9ec290e38b44a..c9d87244c1715 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -25119,6 +25119,13 @@ S:	Maintained
>  F:	Documentation/devicetree/bindings/i2c/spacemit,k1-i2c.yaml
>  F:	drivers/i2c/busses/i2c-k1.c
>  
> +SPACEMIT RESET CONTROLLER DRIVER
> +M:	Guodong Xu <docular.xu at gmail.com>
> +L:	linux-riscv at lists.infradead.org
and I'd still sugest to add spacemit mailing list explicitly

> +S:	Maintained
> +F:	drivers/reset/spacemit/
> +F:	include/dt-bindings/reset/spacemit,k3-resets.h
> +
>  SPANISH DOCUMENTATION
>  M:	Carlos Bilbao <carlos.bilbao at kernel.org>
>  R:	Avadhut Naik <avadhut.naik at amd.com>
> 
> ---
> base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
> change-id: 20260601-b4-spacemit-reset-maintainers-4b5a91599585
> 
> Best regards,
> --  
> Guodong Xu <docular.xu at gmail.com>
> 
> 

-- 
Yixun Lan (dlan)


From dlan at kernel.org  Tue Jun  2 00:10:07 2026
From: dlan at kernel.org (Yixun Lan)
Date: Tue,  2 Jun 2026 07:10:07 +0000
Subject: [GIT PULL] RISC-V SpacemiT Devicetrees for v7.2
Message-ID: <20260602070257-KYC5031219@kernel.org>

Hi SoC Maintainers,

   Please pull SpacemiT's DeviceTree changes for v7.2

Yixun Lan

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  https://github.com/spacemit-com/linux spacemit-dt-for-7.2-1

for you to fetch changes up to 793cc54475b49b5b558902b5c13e4bfe66530a50:

  riscv: dts: spacemit: enable PMIC on OrangePi R2S (2026-06-01 06:32:42 +0000)

----------------------------------------------------------------
RISC-V SpacemiT DT changes for 7.2

For K3 SoC
- Add Ziccrse extension
- Add PWM support
- Add PDMA support
- Add USB2.0 support
- Add CoM260-IFX board
- Add DeepComputing FML13V05 board
- Fix I/O power of pinctrl

For K1 SoC
- Add Micro SD card support
- Add baudrate to console
- Add SPI support
- Enable thermal sensor
- Fix 32K clock

For boards of K1
- Milk-V Jupiter
  - Enable eMMC
- MusePi-Pro
  - Enable EEPROM/PCIe/QSPI/USB
- OrangePi R2S
  - Enable PMIC/USB3
- OrangePi RV2
  - Enable eMMC/I2C/PCIe/PMIC/QSPI/USB

----------------------------------------------------------------
Alex Elder (1):
      riscv: dts: spacemit: define a SPI controller node

Andre Heider (6):
      riscv: dts: spacemit: k1-musepi-pro: add PMIC and power infrastructure
      riscv: dts: spacemit: k1-musepi-pro: add 24c02 eeprom
      riscv: dts: spacemit: k1-musepi-pro: enable QSPI and add SPI NOR
      riscv: dts: spacemit: k1-musepi-pro: enable USB 3 ports
      riscv: dts: spacemit: k1-musepi-pro: enable PCIe ports
      riscv: dts: spacemit: k1-musepi-pro: set default console baud rate

Aurelien Jarno (5):
      riscv: dts: spacemit: set console baud rate on Milk-V Jupiter
      riscv: dts: spacemit: sort aliases on Milk-V Jupiter
      riscv: dts: spacemit: enable eMMC on Milk-V Jupiter
      riscv: dts: spacemit: enable SD card support on Milk-V Jupiter
      riscv: dts: spacemit: fix uboot partition offset on Milk-V Jupiter

Chukun Pan (4):
      riscv: dts: spacemit: enable eMMC for OrangePi RV2
      riscv: dts: spacemit: enable QSPI for OrangePi RV2
      riscv: dts: spacemit: enable USB3 on OrangePi R2S
      riscv: dts: spacemit: enable PMIC on OrangePi R2S

Conor Dooley (1):
      dts: spacemit: set console baud rate on bpif3

Guodong Xu (1):
      riscv: dts: spacemit: k3: Add Ziccrse extension for X100 cores

Han Gao (3):
      riscv: dts: spacemit: Enable i2c8 adapter for OrangePi RV2
      riscv: dts: spacemit: Define the P1 PMIC regulators for OrangePi RV2
      riscv: dts: spacemit: Enable USB3.0/PCIe on OrangePi RV2

Iker Pedrosa (3):
      riscv: dts: spacemit: k1: add SD card controller and pinctrl support
      riscv: dts: spacemit: k1-orangepi-rv2: add SD card support with UHS modes
      riscv: dts: spacemit: k1-bananapi-f3: add SD card support with UHS modes

Sandie Cao (2):
      dt-bindings: riscv: spacemit: add deepcomputing,fml13v05
      riscv: dts: spacemit: add DeepComputing FML13V05 board device tree

Shuwei Wu (1):
      riscv: dts: spacemit: Add thermal sensor for K1 SoC

Trevor Gamblin (1):
      riscv: dts: spacemit: k1-musepi-pro: add SD card support with UHS modes

Troy Mitchell (1):
      riscv: dts: spacemit: Add PDMA controller node for K3 SoC

Yixun Lan (6):
      dts: riscv: spacemit: correct 32k clock frequency
      riscv: dts: spacemit: k3: Add USB2.0 support
      riscv: dts: spacemit: k3: Add pwm support
      dt-bindings: riscv: spacemit: Add K3 CoM260-IFX board
      riscv: dts: spacemit: k3: Initial support for CoM260-IFX board
      dts: riscv: spacemit: k3: Fix I/O power settings

 .../devicetree/bindings/riscv/spacemit.yaml        |   6 +
 arch/riscv/boot/dts/spacemit/Makefile              |   2 +
 arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts    |  33 +-
 arch/riscv/boot/dts/spacemit/k1-milkv-jupiter.dts  |  38 +-
 arch/riscv/boot/dts/spacemit/k1-musepi-pro.dts     | 329 ++++++++++-
 arch/riscv/boot/dts/spacemit/k1-orangepi-r2s.dts   | 157 ++++++
 arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts   | 292 ++++++++++
 arch/riscv/boot/dts/spacemit/k1-pinctrl.dtsi       |  60 ++
 arch/riscv/boot/dts/spacemit/k1.dtsi               | 131 ++++-
 arch/riscv/boot/dts/spacemit/k3-com260-ifx.dts     |  21 +
 arch/riscv/boot/dts/spacemit/k3-com260.dtsi        | 190 +++++++
 .../dts/spacemit/k3-deepcomputing-fml13v05.dts     |  31 +
 arch/riscv/boot/dts/spacemit/k3-pico-itx.dts       |  24 +
 arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi       | 623 +++++++++++++++++++++
 arch/riscv/boot/dts/spacemit/k3.dtsi               | 281 +++++++++-
 15 files changed, 2200 insertions(+), 18 deletions(-)
 create mode 100644 arch/riscv/boot/dts/spacemit/k3-com260-ifx.dts
 create mode 100644 arch/riscv/boot/dts/spacemit/k3-com260.dtsi
 create mode 100644 arch/riscv/boot/dts/spacemit/k3-deepcomputing-fml13v05.dts


From anup at brainfault.org  Tue Jun  2 01:00:34 2026
From: anup at brainfault.org (Anup Patel)
Date: Tue, 2 Jun 2026 13:30:34 +0530
Subject: =?UTF-8?Q?Re=3A_=5BPATCH_2=2F3=5D_RISC=2DV=3A_KVM=3A_Fix_skip_of_valid_pages?=
	=?UTF-8?Q?_in=C2=A0kvm=5Friscv=5Fgstage=5Fwp=5Frange?=
In-Reply-To: <202605111130.64BBUjU6013213@mse-fl2.zte.com.cn>
References: <202605111849442561v1a0B_7W1L2Z-ENusLaP@zte.com.cn> <202605111130.64BBUjU6013213@mse-fl2.zte.com.cn>
Message-ID: <CAAhSdy25JUiM2QnJbvqsQBu5eaB4L2TdSNfkmaaqFMjNOk+Stg@mail.gmail.com>

On Mon, May 11, 2026 at 5:00?PM <wu.fei9 at sanechips.com.cn> wrote:
>
> The current gstage range walker unconditionally advances by 'page_size'
> when a leaf PTE is not found, e.g. when the range to wp is
> [0xfffff01fc000, 0xfffff023c000) and page_size is 2MB, if found_leaf of
> 0xfffff01fc000 returns false, it skip the whole range, but it's possible
> to have valid entries in [0xfffff0200000, 0xfffff023c000).
>
> Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>

I see all tabs converted to spaces. Looks like this patch was
not send using git send-email.

Please rebase and send updated series using git send-email.

Regards,
Anup

> ---
>  arch/riscv/kvm/gstage.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
> index d9fe8be2a151..2b141a78ecac 100644
> --- a/arch/riscv/kvm/gstage.c
> +++ b/arch/riscv/kvm/gstage.c
> @@ -429,14 +429,14 @@ void kvm_riscv_gstage_wp_range(struct kvm_gstage *gstage, gpa_t start, gpa_t end
>                 if (ret)
>                         break;
>
> -               if (!found_leaf)
> -                       goto next;
> -
> -               addr = ALIGN_DOWN(addr, page_size);
> -               kvm_riscv_gstage_op_pte(gstage, addr, ptep,
> -                                       ptep_level, GSTAGE_OP_WP);
> -next:
> -               addr += page_size;
> +               if (!found_leaf) {
> +                       addr = ALIGN(addr + 1, page_size);
> +               } else {
> +                       addr = ALIGN_DOWN(addr, page_size);
> +                       kvm_riscv_gstage_op_pte(gstage, addr, ptep,
> +                                               ptep_level, GSTAGE_OP_WP);
> +                       addr += page_size;
> +               }
>         }
>  }
>
> --
> 2.43.0


From inochiama at gmail.com  Tue Jun  2 01:19:05 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Tue,  2 Jun 2026 16:19:05 +0800
Subject: (subset) [PATCH v5 RESEND 0/5] Add initial Milk-V Duo S board support
In-Reply-To: <20260530173347.33533-1-josh.milas@gmail.com>
References: <20260530173347.33533-1-josh.milas@gmail.com>
Message-ID: <178038833103.2088679.3632311874557644565.b4-ty@b4>

On Sat, 30 May 2026 13:33:42 -0400, Joshua Milas wrote:
> This adds an initial device tree for the Milk-V Duo S board
> with support for reading from the SD card and network over
> Ethernet. This is continued work from Michael Opdenacker's
> v6 series [1] on the ARM64 and RISCV side. It has been tested
> with ARM64 and RISCV64 to boot from an SD card, have networking,
> and read I2C slave devices over i2c4.
> 
> [...]

Applied to for-next, thanks!

[1/5] dt-bindings: soc: sophgo: add Milk-V Duo S board compatibles
      https://github.com/sophgo/linux/commit/eeec80c3ce36ead24e2f53d88a24dac1e3de8041
[4/5] riscv64: dts: sophgo: add SG2000 dtsi
      https://github.com/sophgo/linux/commit/2145cd2f0082c11177b062e1ecbce121c3b50b43

Thanks,
Inochi



From inochiama at gmail.com  Tue Jun  2 01:22:02 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Tue, 2 Jun 2026 16:22:02 +0800
Subject: (subset) [PATCH v5 RESEND 0/5] Add initial Milk-V Duo S board
 support
In-Reply-To: <178038833103.2088679.3632311874557644565.b4-ty@b4>
References: <20260530173347.33533-1-josh.milas@gmail.com>
 <178038833103.2088679.3632311874557644565.b4-ty@b4>
Message-ID: <ah6Se6TJM-wS8UVP@inochi.infowork>

On Tue, Jun 02, 2026 at 04:19:05PM +0800, Inochi Amaoto wrote:
> On Sat, 30 May 2026 13:33:42 -0400, Joshua Milas wrote:
> > This adds an initial device tree for the Milk-V Duo S board
> > with support for reading from the SD card and network over
> > Ethernet. This is continued work from Michael Opdenacker's
> > v6 series [1] on the ARM64 and RISCV side. It has been tested
> > with ARM64 and RISCV64 to boot from an SD card, have networking,
> > and read I2C slave devices over i2c4.
> > 
> > [...]
> 
> Applied to for-next, thanks!
> 
> [1/5] dt-bindings: soc: sophgo: add Milk-V Duo S board compatibles
>       https://github.com/sophgo/linux/commit/eeec80c3ce36ead24e2f53d88a24dac1e3de8041
> [4/5] riscv64: dts: sophgo: add SG2000 dtsi
>       https://github.com/sophgo/linux/commit/2145cd2f0082c11177b062e1ecbce121c3b50b43
> 
> Thanks,
> Inochi
> 

Please ignore this, I apply the wrong patch, A new thanks will be sent 
after I fix this. Sorry for the noise.

Regards,
Inochi


From inochiama at gmail.com  Tue Jun  2 01:26:23 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Tue,  2 Jun 2026 16:26:23 +0800
Subject: (subset) [PATCH v5 RESEND 0/5] Add initial Milk-V Duo S board support
In-Reply-To: <20260530173347.33533-1-josh.milas@gmail.com>
References: <20260530173347.33533-1-josh.milas@gmail.com>
Message-ID: <178038877400.2114604.9271390665852626517.b4-ty@b4>

On Sat, 30 May 2026 13:33:42 -0400, Joshua Milas wrote:
> This adds an initial device tree for the Milk-V Duo S board
> with support for reading from the SD card and network over
> Ethernet. This is continued work from Michael Opdenacker's
> v6 series [1] on the ARM64 and RISCV side. It has been tested
> with ARM64 and RISCV64 to boot from an SD card, have networking,
> and read I2C slave devices over i2c4.
> 
> [...]

Applied to for-next, thanks!

[1/5] dt-bindings: soc: sophgo: add Milk-V Duo S board compatibles
      https://github.com/sophgo/linux/commit/efe66eed43ef507a5b3784d988842d2e621806e1
[3/5] dt-bindings: soc: sophgo: add sg2000 plic and clint documentation
      https://github.com/sophgo/linux/commit/972e8823d93866bc39cf6270bd5ec26d055b9d6f

Thanks,
Inochi



From conor at kernel.org  Tue Jun  2 02:09:42 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 2 Jun 2026 10:09:42 +0100
Subject: [GIT PULL] canaan clk changes for 7.2
Message-ID: <20260602-latitude-unroasted-d88074ae2ebc@spud>

Hey Stephen,

Please pull the addition of a new driver for the Canaan k230 SoC.

It's been on the list for quite a while, with minimal feedback received
on recent versions, so I figured I'd grab it and send a PR so that I can
merge the rest of the SoC support for 7.2. It's been in linux-next for
about two weeks with no issues that I am aware of.

Thanks,
Conor.


The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ clk-canaan-7.2

for you to fetch changes up to a7b7c7c6c01679efef0fd2f2ca1c5114f303e4f5:

  clk: canaan: Add clock driver for Canaan K230 (2026-05-22 17:13:10 +0100)

----------------------------------------------------------------
Canaan k230 clock support

Driver and devicetree bindings for the Canaan k230 SoC.

Signed-off-by: Conor Dooley <conor.dooley at microchip.com>

----------------------------------------------------------------
Xukai Wang (2):
      dt-bindings: clock: Add Canaan K230 clock controller
      clk: canaan: Add clock driver for Canaan K230

 Documentation/devicetree/bindings/clock/canaan,k230-clk.yaml |   59 ++++++
 drivers/clk/Kconfig                                          |    6 +
 drivers/clk/Makefile                                         |    1 +
 drivers/clk/clk-k230.c                                       | 2452 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 include/dt-bindings/clock/canaan,k230-clk.h                  |  220 +++++++++++++++++++
 5 files changed, 2738 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/clock/canaan,k230-clk.yaml
 create mode 100644 drivers/clk/clk-k230.c
 create mode 100644 include/dt-bindings/clock/canaan,k230-clk.h
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260602/a926e557/attachment.sig>

From conor at kernel.org  Tue Jun  2 02:14:20 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 2 Jun 2026 10:14:20 +0100
Subject: [GIT PULL] RISC-V soc fixes for v7.1-rc7
Message-ID: <20260602-brought-impaired-e5cc81043a9e@spud>

Hey folks,

Please pull a single minor fix.

Cheers,
Conor.

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ tags/riscv-soc-fixes-for-v7.1-rc7

for you to fetch changes up to 75ef233975589d9a8c88bc8822a7c725c71ff650:

  soc: microchip: mpfs-sys-controller: fix resource leak on probe error (2026-05-14 21:03:34 +0100)

----------------------------------------------------------------
RISC-V soc fixes for v7.1-rc7

Microchip:
Fix a resource leak in an unlikely probe failure case.

Signed-off-by: Conor Dooley <conor.dooley at microchip.com>

----------------------------------------------------------------
Felix Gu (1):
      soc: microchip: mpfs-sys-controller: fix resource leak on probe error

 drivers/soc/microchip/mpfs-sys-controller.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260602/ab8c9afe/attachment.sig>

From conor at kernel.org  Tue Jun  2 02:16:07 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 2 Jun 2026 10:16:07 +0100
Subject: [PATCH v1] rtc: mpfs: fix counter upload completion condition
In-Reply-To: <20260513-panhandle-ashy-70c6abf84d59@spud>
References: <20260513-panhandle-ashy-70c6abf84d59@spud>
Message-ID: <20260602-buddy-lumber-2be20af90924@spud>

Hey Alexandrew,

On Wed, May 13, 2026 at 06:55:55PM +0100, Conor Dooley wrote:
> From: Conor Dooley <conor.dooley at microchip.com>
> 
> The condition that needs to be checked for upload completion is the
> UPLOAD bit in the completion register going low. The original iterations
> of this driver used a do-while and this was converted to a
> read_poll_timeout() during upstreaming without the condition being
> inverted as it should have been.
> 
> I suspect that this went unnoticed until now because a) the first read
> was done when the bit was still set, immediately completing the
> read_poll_timeout() and b) because the RTC doesn't hold time when power
> is removed from the SoC reducing its utility (I for one keep it
> disabled). If my first suspicion was true when the driver was
> upstreamed, it's not true any longer though, hence the detection of the
> problem.
> 
> Fixes: 0b31d703598dc ("rtc: Add driver for Microchip PolarFire SoC")
> CC: stable at vger.kernel.org
> Signed-off-by: Conor Dooley <conor.dooley at microchip.com>

Any chance this could be applied as 7.1 fixes material?

Apologies if I missed an application mail somewhere,
Conor.

> ---
> CC: Valentina.FernandezAlanis at microchip.com
> CC: Conor Dooley <conor.dooley at microchip.com>
> CC: Daire McNamara <daire.mcnamara at microchip.com>
> CC: Alexandre Belloni <alexandre.belloni at bootlin.com>
> CC: linux-riscv at lists.infradead.org
> CC: linux-rtc at vger.kernel.org
> CC: linux-kernel at vger.kernel.org
> ---
>  drivers/rtc/rtc-mpfs.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c
> index 6aa3eae575d2a..ece6de4a6adbd 100644
> --- a/drivers/rtc/rtc-mpfs.c
> +++ b/drivers/rtc/rtc-mpfs.c
> @@ -112,7 +112,7 @@ static int mpfs_rtc_settime(struct device *dev, struct rtc_time *tm)
>  	ctrl |= CONTROL_UPLOAD_BIT;
>  	writel(ctrl, rtcdev->base + CONTROL_REG);
>  
> -	ret = read_poll_timeout(readl, prog, prog & CONTROL_UPLOAD_BIT, 0, UPLOAD_TIMEOUT_US,
> +	ret = read_poll_timeout(readl, prog, !(prog & CONTROL_UPLOAD_BIT), 0, UPLOAD_TIMEOUT_US,
>  				false, rtcdev->base + CONTROL_REG);
>  	if (ret) {
>  		dev_err(dev, "timed out uploading time to rtc");
> -- 
> 2.53.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260602/c7279194/attachment.sig>

From inochiama at gmail.com  Tue Jun  2 02:21:32 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Tue, 2 Jun 2026 17:21:32 +0800
Subject: (subset) [PATCH 0/2] riscv: sophgo: sg2042: Enable PCIe DMA
 coherence
In-Reply-To: <178028263198.557087.6386925175219722340.b4-ty@b4>
References: <20260331171248.973014-1-gaohan@iscas.ac.cn>
 <178028263198.557087.6386925175219722340.b4-ty@b4>
Message-ID: <ah6gcvKQlHlrW1qn@inochi.infowork>

On Mon, Jun 01, 2026 at 10:57:24AM +0800, Inochi Amaoto wrote:
> On Wed, 01 Apr 2026 01:12:46 +0800, Han Gao wrote:
> > The SG2042 hardware design supports cache-coherent PCIe.
> > 
> > With recent firmware updates [1], it allows to use DMA coherent.
> > 
> > [1] https://github.com/sophgo/edk2-non-osi/commit/017a5aea26a066fd2bf501b7893937183165af36
> > 
> > Han Gao (2):
> >   dt-bindings: pci: sophgo: Add dma-coherent property for SG2042
> >   riscv: dts: sophgo: Add dma-coherent to SG2042 PCIe controllers
> > 
> > [...]
> 
> Applied to for-next, thanks!
> 
> [2/2] riscv: dts: sophgo: Add dma-coherent to SG2042 PCIe controllers
>       https://github.com/sophgo/linux/commit/e728a57834d06b9bbf9bbed69e3ea16416d257d5
> 
> Thanks,
> Inochi
> 

Revoke this apply due to https://lore.kernel.org/sophgo/ahu57vcS0oOFmCI9 at mertle/

Regards,
Inochi


From rppt at kernel.org  Tue Jun  2 02:34:01 2026
From: rppt at kernel.org (Mike Rapoport)
Date: Tue, 2 Jun 2026 12:34:01 +0300
Subject: [PATCH v3 09/11] arm64: kdump: exclude non-dumpable reserved
 memory regions from vmcore
In-Reply-To: <ah0R8pEIyuk4N2Is@MiWiFi-R3L-srv>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <20260527032917.3385849-10-chenwandun1@gmail.com>
 <ahmr-UjoApj2j5JS@willie-the-truck>
 <ahsPcv8G1BR9rLah@kernel.org>
 <ah0R8pEIyuk4N2Is@MiWiFi-R3L-srv>
Message-ID: <ah6jiWwwC6DDSJXd@kernel.org>

Hi Baoquan,

On Mon, Jun 01, 2026 at 01:00:34PM +0800, Baoquan He wrote:
> On 05/30/26 at 07:25pm, Mike Rapoport wrote:
> > On Fri, May 29, 2026 at 04:08:41PM +0100, Will Deacon wrote:
> > > On Wed, May 27, 2026 at 11:29:15AM +0800, Wandun Chen wrote:
> ...snip...
> > There are patches that move common code to kernel/crash_core.c:
> > 
> > https://lore.kernel.org/all/20260525084932.934910-1-ruanjinjie at huawei.com
> >  
> > Review from arch maintainers would be helpful there ;-)
> 
> Before, Andrew would put patch candidates into his mm tree and trigger
> testing. If any adjustment, he would take them off. Can we do the
> similar thing for kexec/kdump patches, unless the patches are objected
> explicitly?

Yes, we can add patches that look reasonable and expose them in -next.
Now is too late in the release cycle, let's start with it after -rc1.
 
> Thanks
> Baoquan

-- 
Sincerely yours,
Mike.


From amadeus at jmu.edu.cn  Tue Jun  2 03:00:00 2026
From: amadeus at jmu.edu.cn (Chukun Pan)
Date: Tue,  2 Jun 2026 18:00:00 +0800
Subject: [PATCH 1/1] riscv: dts: spacemit: enable PCIe on OrangePi R2S
Message-ID: <20260602100000.2402784-1-amadeus@jmu.edu.cn>

Enable the two RTL8125 network controllers and corresponding
PHYs connected via the PCIe controllers on the OrangePi R2S.

Signed-off-by: Chukun Pan <amadeus at jmu.edu.cn>
---
Current PCIe drivers can only negotiate down to Gen.1,
so the RTL8125 cannot reach speeds above 2Gbps.
---
 .../boot/dts/spacemit/k1-orangepi-r2s.dts     | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/arch/riscv/boot/dts/spacemit/k1-orangepi-r2s.dts b/arch/riscv/boot/dts/spacemit/k1-orangepi-r2s.dts
index b13a8d6a2670..919e5b451109 100644
--- a/arch/riscv/boot/dts/spacemit/k1-orangepi-r2s.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-orangepi-r2s.dts
@@ -23,6 +23,14 @@ chosen {
 		stdout-path = "serial0";
 	};
 
+	pcie_vcc3v3: regulator-pcie-vcc3v3 {
+		compatible = "regulator-fixed";
+		regulator-name = "pcie_vcc3v3";
+		regulator-min-microvolt = <3300000>;
+		regulator-max-microvolt = <3300000>;
+		regulator-always-on;
+	};
+
 	vcc4v0: regulator-vcc4v0 {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc4v0";
@@ -228,6 +236,36 @@ dldo7 {
 	};
 };
 
+&pcie1_phy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie1_3_cfg>;
+	status = "okay";
+};
+
+&pcie1_port {
+	phys = <&pcie1_phy>;
+	vpcie3v3-supply = <&pcie_vcc3v3>;
+};
+
+&pcie1 {
+	status = "okay";
+};
+
+&pcie2_phy {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie2_4_cfg>;
+	status = "okay";
+};
+
+&pcie2_port {
+	phys = <&pcie2_phy>;
+	vpcie3v3-supply = <&pcie_vcc3v3>;
+};
+
+&pcie2 {
+	status = "okay";
+};
+
 &pdma {
 	status = "okay";
 };
-- 
2.34.1



From ebiederm at xmission.com  Tue Jun  2 03:23:10 2026
From: ebiederm at xmission.com (Eric W. Biederman)
Date: Tue, 02 Jun 2026 05:23:10 -0500
Subject: [PATCH v23 06/28] riscv/mm : ensure PROT_WRITE leads to VM_READ
 | VM_WRITE
In-Reply-To: <87wlwif04z.fsf@igel.home> (Andreas Schwab's message of "Mon, 01
	Jun 2026 22:58:52 +0200")
References: <20251112-v5_user_cfi_series-v23-0-b55691eacf4f@rivosinc.com>
	<20251112-v5_user_cfi_series-v23-6-b55691eacf4f@rivosinc.com>
	<87jyslndo4.fsf@igel.home>
	<CAKC1njS=AHu6uHrH4ae8VxcdEbhgiPXYCAoN3F_mnppBd3SwOA@mail.gmail.com>
	<875x44o9hj.fsf@igel.home>
	<CAKC1njSn_rtCj8ii876PNQTk0nsCTfWsb4DzdymufHVthh1Rkg@mail.gmail.com>
	<871peqgp9v.fsf@igel.home>
	<CAKC1njR+dTdvp+BmLGPtgd8dufiUwBtkQ9a-qinELT_Fmi13sQ@mail.gmail.com>
	<87wlwif04z.fsf@igel.home>
Message-ID: <87tsrli6lt.fsf@email.froward.int.ebiederm.org>

Andreas Schwab <schwab at linux-m68k.org> writes:

> On Jun 01 2026, Deepak Gupta wrote:
>
>> riscv uses `VM_SHADOW_STACK`. It's just very simple to use `protection_map`
>> with just `VM_WRITE`. On RISC-V, `-W-` is a shadow stack mapping. It's not same
>> on x86 or arm64. So `protection_map[VM_WRITE]` simply picks shadow stack
>> encoding. We just ensure that PROT_WRITE is converted to
>> "VM_READ | VM_WRITE" at vma level.
>
> That does not explain _why_ you need to make that user visible change,
> when others can get away without it.

Especially since as I recall the decision was made was that the user
visible protection bits would match the mmap call.  If there is some
combination an architecture does not support that would simply not be
reflected in hardware until some future version of the hardware gets
around to supporting it.

This is what happened with executable page permissions on x86 for
example.  It used to be that it was not possible to deny execute
permission on a readable page.  Later that proved sufficiently valuable
that support for denying execute permission was added to the hardware.

That all happened quite transparently to userspace, that wasn't trying
to assuming PROT_READ implied PROT_EXEC.

So I am at a complete loss why someone would choose to break userspace
by confusing hardware limitations with what userspace asks for in mmap.

Eric



From xueshuai at linux.alibaba.com  Tue Jun  2 04:18:17 2026
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Tue, 2 Jun 2026 19:18:17 +0800
Subject: [PATCH v2 2/8] riscv: stacktrace: Add frame record metadata
In-Reply-To: <20260528082310.1994388-3-wanghan@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
 <20260528082310.1994388-3-wanghan@linux.alibaba.com>
Message-ID: <425ce2d4-bf35-4bff-8dc8-93093b8aaba2@linux.alibaba.com>



On 5/28/26 4:23 PM, Wang Han wrote:
> Reliable frame-pointer unwinding needs an explicit way to identify
> exception boundaries and the final entry frame. The existing unwinder
> infers those boundaries from return addresses, which is too loose for a
> future reliable unwinder.
> 
> Add a small metadata frame record to pt_regs and initialize it on
> exception entry, kernel thread fork, user fork, and early idle task
> setup. The record uses a zero {fp, ra} sentinel plus a type field so a
> later unwinder can distinguish a final user-to-kernel boundary from a
> nested kernel pt_regs boundary.
> 
> This follows the arm64 metadata frame-record model, adapted to the
> RISC-V {fp, ra} frame record convention.
> 
> The metadata is established at the RISC-V entry boundaries that need an
> explicit unwind marker:
> 
>    * exception entry clears the metadata {fp, ra} pair and uses SPP
>      (or MPP in M-mode) to record whether the pt_regs frame is the final
>      user-to-kernel boundary or a nested kernel boundary;
>    * _start_kernel builds the init task's final metadata record, while
>      the secondary CPU path sets up s0 before smp_callin() so idle-task
>      unwinding does not inherit an undefined caller frame;
>    * copy_thread creates matching final metadata records for new kernel
>      and user tasks, and keeps s0 available for the frame-pointer chain;
>    * call_on_irq_stack still reserves an aligned stack slot, but links the
>      saved {fp, ra} with the raw frame-record size so s0 points at the
>      RISC-V frame record rather than past the alignment padding.
> 
> These changes keep s0 reserved for the frame-pointer chain at task and
> stack-switch boundaries.
> 
> Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
> ---
>   arch/riscv/include/asm/ptrace.h           |  9 ++++
>   arch/riscv/include/asm/stacktrace/frame.h | 53 +++++++++++++++++++++++
>   arch/riscv/kernel/asm-offsets.c           |  4 ++
>   arch/riscv/kernel/entry.S                 | 30 +++++++++++--
>   arch/riscv/kernel/head.S                  | 23 ++++++++++
>   arch/riscv/kernel/process.c               | 31 ++++++++++++-
>   6 files changed, 144 insertions(+), 6 deletions(-)
>   create mode 100644 arch/riscv/include/asm/stacktrace/frame.h
> 
> diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h
> index addc8188152f..4b9b0f279214 100644
> --- a/arch/riscv/include/asm/ptrace.h
> +++ b/arch/riscv/include/asm/ptrace.h
> @@ -8,6 +8,7 @@
>   
>   #include <uapi/asm/ptrace.h>
>   #include <asm/csr.h>
> +#include <asm/stacktrace/frame.h>
>   #include <linux/compiler.h>
>   
>   #ifndef __ASSEMBLER__
> @@ -53,6 +54,14 @@ struct pt_regs {
>   	unsigned long cause;
>   	/* a0 value before the syscall */
>   	unsigned long orig_a0;
> +
> +	/*
> +	 * This frame record is entirely zeroed on exception entry, allowing the
> +	 * unwinder to identify exception boundaries. The type field encodes
> +	 * whether the exception was taken from user (FINAL) or kernel (PT_REGS)
> +	 * mode.
> +	 */
> +	struct frame_record_meta stackframe;
>   };
>   
>   #define PTRACE_SYSEMU			0x1f
> diff --git a/arch/riscv/include/asm/stacktrace/frame.h b/arch/riscv/include/asm/stacktrace/frame.h
> new file mode 100644
> index 000000000000..5720a6c65fe8
> --- /dev/null
> +++ b/arch/riscv/include/asm/stacktrace/frame.h
> @@ -0,0 +1,53 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef __ASM_RISCV_STACKTRACE_FRAME_H
> +#define __ASM_RISCV_STACKTRACE_FRAME_H
> +
> +/*
> + * See: arch/arm64/include/asm/stacktrace/frame.h for the reference
> + * implementation.
> + */
> +
> +/*
> + * - FRAME_META_TYPE_NONE
> + *
> + *   This value is reserved.
> + *
> + * - FRAME_META_TYPE_FINAL
> + *
> + *   The record is the last entry on the stack.
> + *   Unwinding should terminate successfully.
> + *
> + * - FRAME_META_TYPE_PT_REGS
> + *
> + *   The record is embedded within a struct pt_regs, recording the registers at
> + *   an arbitrary point in time.
> + *   Unwinding should consume pt_regs::epc, followed by pt_regs::ra.
> + *
> + * Note: all other values are reserved and should result in unwinding
> + * terminating with an error.
> + */
> +#define FRAME_META_TYPE_NONE		0
> +#define FRAME_META_TYPE_FINAL		1
> +#define FRAME_META_TYPE_PT_REGS		2
> +
> +#ifndef __ASSEMBLER__
> +/*
> + * A standard RISC-V frame record.
> + */
> +struct frame_record {
> +	unsigned long fp;
> +	unsigned long ra;
> +};
> +
> +/*
> + * A metadata frame record indicating a special unwind.
> + * The record::{fp,ra} fields must be zero to indicate the presence of
> + * metadata.
> + */
> +struct frame_record_meta {
> +	struct frame_record record;
> +	unsigned long type;
> +};
> +#endif /* __ASSEMBLER__ */
> +
> +#endif /* __ASM_RISCV_STACKTRACE_FRAME_H */
> diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
> index af827448a609..8dfcb5a44bb8 100644
> --- a/arch/riscv/kernel/asm-offsets.c
> +++ b/arch/riscv/kernel/asm-offsets.c
> @@ -131,6 +131,9 @@ void asm_offsets(void)
>   	OFFSET(PT_BADADDR, pt_regs, badaddr);
>   	OFFSET(PT_CAUSE, pt_regs, cause);
>   
> +	DEFINE(S_STACKFRAME,		offsetof(struct pt_regs, stackframe));
> +	DEFINE(S_STACKFRAME_TYPE,	offsetof(struct pt_regs, stackframe.type));
> +
>   	OFFSET(SUSPEND_CONTEXT_REGS, suspend_context, regs);
>   
>   	OFFSET(HIBERN_PBE_ADDR, pbe, address);
> @@ -501,6 +504,7 @@ void asm_offsets(void)
>   	OFFSET(SBI_HART_BOOT_STACK_PTR_OFFSET, sbi_hart_boot_data, stack_ptr);
>   
>   	DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe), STACK_ALIGN));
> +	DEFINE(STACKFRAME_RECORD_SIZE, sizeof(struct stackframe));
>   	OFFSET(STACKFRAME_FP, stackframe, fp);
>   	OFFSET(STACKFRAME_RA, stackframe, ra);
>   #ifdef CONFIG_FUNCTION_TRACER
> diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
> index d011fb51c59a..9cae0e1eba1c 100644
> --- a/arch/riscv/kernel/entry.S
> +++ b/arch/riscv/kernel/entry.S
> @@ -11,6 +11,7 @@
>   #include <asm/asm.h>
>   #include <asm/csr.h>
>   #include <asm/scs.h>
> +#include <asm/stacktrace/frame.h>
>   #include <asm/unistd.h>
>   #include <asm/page.h>
>   #include <asm/thread_info.h>
> @@ -193,6 +194,27 @@ SYM_CODE_START(handle_exception)
>   	REG_S s4, PT_CAUSE(sp)
>   	REG_S s5, PT_TP(sp)
>   
> +	/*
> +	 * Create a metadata frame record. The unwinder will use this to
> +	 * identify and unwind exception boundaries.
> +	 */
> +	REG_S zero, (S_STACKFRAME + STACKFRAME_FP)(sp) /* stackframe.record.fp = 0 */
> +	REG_S zero, (S_STACKFRAME + STACKFRAME_RA)(sp) /* stackframe.record.ra = 0 */
> +#ifdef CONFIG_RISCV_M_MODE
> +	li t0, SR_MPP
> +	and t0, s1, t0
> +#else
> +	andi t0, s1, SR_SPP
> +#endif
> +	bnez t0, 1f
> +	li t0, FRAME_META_TYPE_FINAL
> +	j 2f
> +1:
> +	li t0, FRAME_META_TYPE_PT_REGS
> +2:
> +	REG_S t0, S_STACKFRAME_TYPE(sp)
> +	addi s0, sp, S_STACKFRAME + STACKFRAME_RECORD_SIZE
> +

One spot for symmetry (non-blocking, robustness only):

handle_kernel_stack_overflow in entry.S allocates a full
PT_SIZE_ON_STACK frame (including the new stackframe metadata fields)
but, unlike .Lsave_context, never initialises stackframe.{record,type}
nor repoints s0 at the metadata. Those three words are therefore left
as whatever was on the overflow_stack.

In practice this is currently harmless: handle_bad_stack() only calls
__show_regs() (register dump, no unwind) followed by panic(), so the
reliable unwinder never actually consumes that metadata today. So this
is not an active bug ? purely a robustness / symmetry gap.

It would still be worth initialising it, because the moment someone
adds a dump_stack() here, or another CPU NMI-backtraces this task, or a
kdump image is walked offline via the frame-record chain, the garbage
type byte would mislead the unwinder. Since the overflow path is by
definition entered from kernel context, FRAME_META_TYPE_PT_REGS is the
right type, and it has the nice property that the unwinder will resume
from frame_pointer(regs)==regs->s0 (the pre-overflow s0 is already
saved into PT_S0 by save_from_x6_to_x31), giving the pre-overflow call
chain instead of a hard stop.


>   	/*
>   	 * Set the scratch register to 0, so that if a recursive exception
>   	 * occurs, the exception vector knows it came from the kernel
> @@ -357,8 +379,8 @@ ASM_NOKPROBE(handle_kernel_stack_overflow)
>   
>   SYM_CODE_START(ret_from_fork_kernel_asm)
>   	call schedule_tail
> -	move a0, s1 /* fn_arg */
> -	move a1, s0 /* fn */
> +	move a0, s3 /* fn_arg */
> +	move a1, s2 /* fn */
>   	move a2, sp /* pt_regs */
>   	call ret_from_fork_kernel
>   	j ret_from_exception
> @@ -383,7 +405,7 @@ SYM_FUNC_START(call_on_irq_stack)
>   	addi	sp, sp, -STACKFRAME_SIZE_ON_STACK
>   	REG_S	ra, STACKFRAME_RA(sp)
>   	REG_S	s0, STACKFRAME_FP(sp)
> -	addi	s0, sp, STACKFRAME_SIZE_ON_STACK
> +	addi	s0, sp, STACKFRAME_RECORD_SIZE
>   
>   	/* Switch to the per-CPU shadow call stack */
>   	scs_save_current
> @@ -399,7 +421,7 @@ SYM_FUNC_START(call_on_irq_stack)
>   	scs_load_current
>   
>   	/* Switch back to the thread stack and restore ra and s0 */
> -	addi	sp, s0, -STACKFRAME_SIZE_ON_STACK
> +	addi	sp, s0, -STACKFRAME_RECORD_SIZE

Worth calling out explicitly that this is more than a cosmetic refactor:
on RV32 the previous code is actually wrong, and this hunk fixes it.

   STACKFRAME_SIZE_ON_STACK = ALIGN(sizeof(struct stackframe), STACK_ALIGN)
   STACKFRAME_RECORD_SIZE   = sizeof(struct stackframe)

   RV64: sizeof(stackframe) == STACK_ALIGN == 16, so the two are equal
         and the old code happened to work.
   RV32: sizeof(stackframe) == 8 but STACK_ALIGN == 16, so the old
         "addi s0, sp, STACKFRAME_SIZE_ON_STACK" left s0 pointing 8 bytes
         past the saved {fp, ra} pair, into the alignment padding. An FP
         unwinder that derives the frame record from s0 (e.g. via
         "(struct stackframe *)s0 - 1" or fixed -8/-16(s0) loads) would
         then read garbage instead of the saved fp/ra at the IRQ-stack

After the change s0 lands exactly at the end of the {fp, ra} record on
both RV32 and RV64, while the aligned slot is still reserved by the
unchanged "addi sp, sp, -STACKFRAME_SIZE_ON_STACK" / matching restore.

Could you mention this in the v3 commit message? It's load-bearing
context for anyone bisecting an RV32 unwind regression later, and it
also justifies why the change is correct to apply ahead of the reliable
unwinder rather than folded into it.

>   	REG_L	ra, STACKFRAME_RA(sp)
>   	REG_L	s0, STACKFRAME_FP(sp)
>   	addi	sp, sp, STACKFRAME_SIZE_ON_STACK
> diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
> index f6a8ca49e627..00e16a24f149 100644
> --- a/arch/riscv/kernel/head.S
> +++ b/arch/riscv/kernel/head.S
> @@ -14,6 +14,7 @@
>   #include <asm/hwcap.h>
>   #include <asm/image.h>
>   #include <asm/scs.h>
> +#include <asm/stacktrace/frame.h>
>   #include <asm/usercfi.h>
>   #include "efi-header.S"
>   
> @@ -177,6 +178,14 @@ secondary_start_sbi:
>   	REG_S a0, (a1)
>   1:
>   #endif
> +
> +	/*
> +	 * Set up the frame pointer for the secondary idle task so reliable
> +	 * stack unwinding terminates at the metadata frame in task_pt_regs().
> +	 * Without this, the first frame records can inherit an undefined caller
> +	 * fp and unwind past smp_callin() into .Lsecondary_park.
> +	 */
> +	addi s0, sp, S_STACKFRAME + STACKFRAME_RECORD_SIZE
>   	scs_load_current
>   	call smp_callin
>   #endif /* CONFIG_SMP */
> @@ -305,6 +314,20 @@ SYM_CODE_START(_start_kernel)
>   	la tp, init_task
>   	la sp, init_thread_union + THREAD_SIZE
>   	addi sp, sp, -PT_SIZE_ON_STACK
> +
> +	/*
> +	 * Set up a metadata frame record for the init task so that
> +	 * the unwinder can identify the outermost frame by its
> +	 * {fp, ra} = {0, 0} sentinel at the bottom of pt_regs.
> +	 * fp/s0 points above the metadata record (RISC-V
> +	 * convention).
> +	 */
> +	REG_S zero, (S_STACKFRAME + STACKFRAME_FP)(sp)
> +	REG_S zero, (S_STACKFRAME + STACKFRAME_RA)(sp)
> +	li t0, FRAME_META_TYPE_FINAL
> +	REG_S t0, S_STACKFRAME_TYPE(sp)
> +	addi s0, sp, S_STACKFRAME + STACKFRAME_RECORD_SIZE
> +
>   #if defined(CONFIG_RISCV_SBI) && defined(CONFIG_RISCV_USER_CFI)
>   	li a7, SBI_EXT_FWFT
>   	li a6, SBI_EXT_FWFT_SET
> diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
> index b2df7f72241a..5212926b926b 100644
> --- a/arch/riscv/kernel/process.c
> +++ b/arch/riscv/kernel/process.c
> @@ -258,8 +258,23 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
>   		/* Supervisor/Machine, irqs on: */
>   		childregs->status = SR_PP | SR_PIE;
>   
> -		p->thread.s[0] = (unsigned long)args->fn;
> -		p->thread.s[1] = (unsigned long)args->fn_arg;
> +		/*
> +		 * Set up a metadata frame record at the bottom of the
> +		 * stack for the unwinder. Use FRAME_META_TYPE_FINAL
> +		 * since this is the outermost kernel entry for the new
> +		 * task. The frame_record::{fp,ra} are already zero from
> +		 * memset().
> +		 *
> +		 * fp/s0 points above the metadata record (RISC-V
> +		 * convention). fn and fn_arg are passed via s2/s3,
> +		 * keeping s0 available for the frame pointer chain.
> +		 */
> +		childregs->stackframe.type = FRAME_META_TYPE_FINAL;
> +
> +		p->thread.s[0] = (unsigned long)(&childregs->stackframe)
> +				+ sizeof(struct frame_record);
> +		p->thread.s[2] = (unsigned long)args->fn;
> +		p->thread.s[3] = (unsigned long)args->fn_arg;
>   		p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
>   	} else {
>   		/* allocate new shadow stack if needed. In case of CLONE_VM we have to */
> @@ -278,6 +293,18 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
>   		if (clone_flags & CLONE_SETTLS)
>   			childregs->tp = tls;
>   		childregs->a0 = 0; /* Return value of fork() */
> +
> +		/*
> +		 * Set up the unwind boundary: ensure the metadata
> +		 * frame record has its {fp,ra} sentinel zeroed and
> +		 * point fp/s0 above the metadata record. The type
> +		 * field is inherited from the parent's pt_regs.
> +		 */
> +		childregs->stackframe.record.fp = 0;
> +		childregs->stackframe.record.ra = 0;

This relies on the parent always entering kernel via handle_exception
on a user->kernel boundary (which writes FRAME_META_TYPE_FINAL).
That is true for fork()/clone() today, but:

   - The kernel-thread path right above explicitly assigns type =
     FINAL, so the user-thread path looks asymmetric and like a
     possible omission to anyone reading it cold.
   - A future caller invoking kernel_clone() from a nested-kernel
     context (parent pt_regs.type == PT_REGS) would silently produce
     a broken unwind boundary on the new task.

Recommend explicitly setting it here too:

       childregs->stackframe.type = FRAME_META_TYPE_FINAL;

Even if currently redundant, it is one assignment, costs nothing, is
self-documenting, and fails closed instead of open.


Thanks.
Shuai


From xueshuai at linux.alibaba.com  Tue Jun  2 04:22:49 2026
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Tue, 2 Jun 2026 19:22:49 +0800
Subject: [PATCH v2 3/8] riscv: stacktrace: disable KASAN instrumentation
 for stacktrace.o
In-Reply-To: <20260528082310.1994388-4-wanghan@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
 <20260528082310.1994388-4-wanghan@linux.alibaba.com>
Message-ID: <a385e57a-e895-4044-ae94-8cd8dfbd3bed@linux.alibaba.com>



On 5/28/26 4:23 PM, Wang Han wrote:
> KASAN records stack traces for every alloc/free, which means it walks
> the unwinder very frequently. Instrumenting the stack trace collection
> code itself adds substantial overhead and makes the traces themselves
> noisier.
> 
> Mark stacktrace.o as not KASAN-instrumented, matching the arm, arm64
> and x86 treatment of their stack unwinding code. This is a prerequisite
> preference for the upcoming reliable unwinder, but the change is valid
> on its own.
> 
> Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
> ---
>   arch/riscv/kernel/Makefile | 5 +++++
>   1 file changed, 5 insertions(+)
> 
> diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
> index cabb99cadfb6..1cb6c9ab2981 100644
> --- a/arch/riscv/kernel/Makefile
> +++ b/arch/riscv/kernel/Makefile
> @@ -44,6 +44,11 @@ CFLAGS_REMOVE_return_address.o	= $(CC_FLAGS_FTRACE)
>   CFLAGS_REMOVE_sbi_ecall.o = $(CC_FLAGS_FTRACE)
>   endif
>   
> +# When KASAN is enabled, a stack trace is recorded for every alloc/free, which
> +# can significantly impact performance. Avoid instrumenting the stack trace
> +# collection code to minimize this impact.
> +KASAN_SANITIZE_stacktrace.o := n
> +

I checked the three referenced arches:
   - arm    (arch/arm/kernel/Makefile):    KASAN only
   - arm64  (arch/arm64/kernel/Makefile):  KASAN only
   - x86    (arch/x86/kernel/Makefile):    KASAN *and* KCOV
            (KCOV_INSTRUMENT_stacktrace.o := n, plus dumpstack and
             the unwind_*.o TUs)

So as written, this patch matches arm/arm64 but NOT x86. KCOV
instruments every basic-block edge; the unwinder is a hot path
(doubly so under KASAN, where it runs on every alloc/free), so the
same rationale that justifies disabling KASAN applies to KCOV. I'd
suggest making the claim true by adding:

  KCOV_INSTRUMENT_stacktrace.o := n

(RISC-V keeps its entire unwinder in stacktrace.o, so unlike x86
there's no dumpstack/unwind_*.o to also annotate ? the single TU
covers the equivalent scope.)

Alternatively, if you'd rather keep it minimal, just drop "and x86"
from the changelog so the claim matches the code.


Thanks.
Shuai


From mayuresh.chitale at oss.qualcomm.com  Tue Jun  2 04:24:38 2026
From: mayuresh.chitale at oss.qualcomm.com (Mayuresh Chitale)
Date: Tue, 2 Jun 2026 16:54:38 +0530
Subject: [PATCH v4 07/12] rvtrace: Add trace ramsink driver
In-Reply-To: <ahC2y59MHRZa9Ayh@curiosity>
References: <20260429125135.1983498-1-anup.patel@oss.qualcomm.com>
 <20260429125135.1983498-8-anup.patel@oss.qualcomm.com> <ahC2y59MHRZa9Ayh@curiosity>
Message-ID: <CAHuiULA4UxJBpZxCNBbmHXZWHtmZbTo0_uipV2oLiyOjkC-rLA@mail.gmail.com>

Hi Sergey,

On Sat, May 23, 2026 at 1:34?AM Sergey Matyukevich <geomatsi at gmail.com> wrote:
>
> On Wed, Apr 29, 2026 at 06:21:30PM +0530, Anup Patel wrote:
> > From: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
> >
> > Add initial implementation of RISC-V trace ramsink driver. The ramsink
> > is defined in the RISC-V Trace Control Interface specification.
> >
> > Co-developed-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > Signed-off-by: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
> > ---
> >  drivers/hwtracing/rvtrace/Kconfig           |   9 +
> >  drivers/hwtracing/rvtrace/Makefile          |   1 +
> >  drivers/hwtracing/rvtrace/rvtrace-ramsink.c | 338 ++++++++++++++++++++
> >  3 files changed, 348 insertions(+)
> >  create mode 100644 drivers/hwtracing/rvtrace/rvtrace-ramsink.c
>
> ...
>
> > +static int rvtrace_ramsink_probe(struct rvtrace_component *comp)
> > +{
> > +     int ret;
> > +
> > +     ret = rvtrace_ramsink_setup(comp);
> > +     if (ret)
> > +             return dev_err_probe(&comp->dev, ret, "failed to setup ramsink.\n");
> > +
> > +     ret = rvtrace_enable_component(comp->pdata);
>
> Does it make sense to enable such components (ramsink and encoder) on probe ?
> IIUC they will be enabled/disabled later in start/stop operations when
> rvtrace graph is activated e.g. during perf tool work. It looks like
> reset (primary activation) should be sufficient, and it is already done
> by the core framework on probing.
Yes, that is correct. I will fix in the next version.
>
> > +     if (ret)
> > +             return dev_err_probe(&comp->dev, ret, "failed to enable ramsink.\n");
> > +
> > +     return ret;
> > +}
>
> Regards,
> Sergey


From mayuresh.chitale at oss.qualcomm.com  Tue Jun  2 04:29:36 2026
From: mayuresh.chitale at oss.qualcomm.com (Mayuresh Chitale)
Date: Tue, 2 Jun 2026 16:59:36 +0530
Subject: [PATCH v4 05/12] rvtrace: Add trace encoder driver
In-Reply-To: <ahCkjH-sGnGLHpG-@curiosity>
References: <20260429125135.1983498-1-anup.patel@oss.qualcomm.com>
 <20260429125135.1983498-6-anup.patel@oss.qualcomm.com> <ahCkjH-sGnGLHpG-@curiosity>
Message-ID: <CAHuiULB4PKngzUYg65gj3k+OeKnUXL6NQQmwm3697Uq3Fijknw@mail.gmail.com>

Hi Sergey,

On Sat, May 23, 2026 at 12:16?AM Sergey Matyukevich <geomatsi at gmail.com> wrote:
>
> Hi,
>
> > From: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
> >
> > Add initial implementation of RISC-V trace encoder driver. The encoder
> > is defined in the RISC-V Trace Control Interface specification.
> >
> > Co-developed-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > Signed-off-by: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
> > ---
> >  drivers/hwtracing/rvtrace/Kconfig           |   7 ++
> >  drivers/hwtracing/rvtrace/Makefile          |   1 +
> >  drivers/hwtracing/rvtrace/rvtrace-encoder.c | 130 ++++++++++++++++++++
> >  3 files changed, 138 insertions(+)
> >  create mode 100644 drivers/hwtracing/rvtrace/rvtrace-encoder.c
>
> ...
>
> > +static int rvtrace_encoder_start(struct rvtrace_component *comp)
> > +{
> > +     int ret;
> > +     u32 val;
> > +
> > +     val = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     val |= BIT(RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT);
> > +     rvtrace_write32(comp->pdata, val, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     ret = rvtrace_poll_bit(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET,
> > +                            RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT, 1,
> > +                            comp->pdata->control_poll_timeout_usecs);
>
> IIUC the code fragment above duplicates 'rvtrace_enable_component' from
> rvtrace-core.c.
>
> > +     if (ret) {
> > +             dev_err(&comp->dev, "failed to enable encoder.\n");
> > +             return ret;
> > +     }
> > +
> > +     /* set mode */
> > +     val = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     val |= (RVTRACE_COMPONENT_CTRL_INSTMODE_OPIT << RVTRACE_COMPONENT_CTRL_INSTMODE_SHIFT);
> > +     rvtrace_write32(comp->pdata, val, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +
> > +     val = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     val |= BIT(RVTRACE_COMPONENT_CTRL_ITRACE_SHIFT);
> > +     rvtrace_write32(comp->pdata, val, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     ret = rvtrace_poll_bit(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET,
> > +                            RVTRACE_COMPONENT_CTRL_ITRACE_SHIFT, 1,
> > +                            comp->pdata->control_poll_timeout_usecs);
> > +     if (ret)
> > +             dev_err(&comp->dev, "failed to enable tracing.\n");
> > +
> > +     return ret;
> > +}
> > +
> > +static int rvtrace_encoder_stop(struct rvtrace_component *comp)
> > +{
> > +     int ret;
> > +     u32 val;
> > +
> > +     val = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     val &= ~BIT(RVTRACE_COMPONENT_CTRL_ITRACE_SHIFT);
> > +     rvtrace_write32(comp->pdata, val, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     ret = rvtrace_poll_bit(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET,
> > +                            RVTRACE_COMPONENT_CTRL_ITRACE_SHIFT, 0,
> > +                            comp->pdata->control_poll_timeout_usecs);
> > +     if (ret) {
> > +             dev_err(&comp->dev, "failed to stop tracing.\n");
> > +             return ret;
> > +     }
> > +
> > +     val = rvtrace_read32(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     val &= ~BIT(RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT);
> > +     rvtrace_write32(comp->pdata, val, RVTRACE_COMPONENT_CTRL_OFFSET);
> > +     ret = rvtrace_poll_bit(comp->pdata, RVTRACE_COMPONENT_CTRL_OFFSET,
> > +                            RVTRACE_COMPONENT_CTRL_ENABLE_SHIFT, 0,
> > +                            comp->pdata->control_poll_timeout_usecs);
>
> IIUC the code fragment above duplicates 'rvtrace_disable_component' from
> rvtrace-core.c.
>
I will replace both of these with calls to the respective core functions.
> > +     if (ret) {
> > +             dev_err(&comp->dev, "failed to disable encoder.\n");
> > +             return ret;
> > +     }
> > +
> > +     return rvtrace_comp_poll_empty(comp);
> > +}
>
> Regards,
> Sergey


From mayuresh.chitale at oss.qualcomm.com  Tue Jun  2 04:31:31 2026
From: mayuresh.chitale at oss.qualcomm.com (Mayuresh Chitale)
Date: Tue, 2 Jun 2026 17:01:31 +0530
Subject: [PATCH v4 10/12] perf tools: Add RISC-V trace PMU record capabilities
In-Reply-To: <a56d974c-64c2-450e-8668-f987de64468b@intel.com>
References: <20260429125135.1983498-1-anup.patel@oss.qualcomm.com>
 <20260429125135.1983498-11-anup.patel@oss.qualcomm.com> <a56d974c-64c2-450e-8668-f987de64468b@intel.com>
Message-ID: <CAHuiULCzUNkXTSwcHHUDFXM-oU=_gpCeTNM+VAHdwZP47Xw4qw@mail.gmail.com>

Hi Adrian,

On Wed, May 20, 2026 at 5:00?PM Adrian Hunter <adrian.hunter at intel.com> wrote:
>
> On 29/04/2026 15:51, Anup Patel wrote:
> > From: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
> >
> > Introduce the required auxiliary API functions allowing the perf core
> > to interact with RISC-V trace perf driver.
> >
> > Co-developed-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > Signed-off-by: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
> > Reviewed-by: Nutty Liu <nutty.liu at hotmail.com>
>
> A few minor comments, otherwise:
>
> Reviewed-by: Adrian Hunter <adrian.hunter at intel.com>

Thanks, I will address the comments below in the next version.
>
> > ---
> >  tools/perf/arch/riscv/util/Build      |   1 +
> >  tools/perf/arch/riscv/util/auxtrace.c | 219 ++++++++++++++++++++++++++
> >  tools/perf/util/auxtrace.c            |   1 +
> >  tools/perf/util/auxtrace.h            |   1 +
> >  tools/perf/util/rvtrace.h             |  18 +++
> >  5 files changed, 240 insertions(+)
> >  create mode 100644 tools/perf/arch/riscv/util/auxtrace.c
> >  create mode 100644 tools/perf/util/rvtrace.h
> >
> > diff --git a/tools/perf/arch/riscv/util/Build b/tools/perf/arch/riscv/util/Build
> > index 2328fb9a30a3..e07d5525ece6 100644
> > --- a/tools/perf/arch/riscv/util/Build
> > +++ b/tools/perf/arch/riscv/util/Build
> > @@ -1 +1,2 @@
> >  perf-util-y += header.o
> > +perf-util-y += auxtrace.o
> > diff --git a/tools/perf/arch/riscv/util/auxtrace.c b/tools/perf/arch/riscv/util/auxtrace.c
> > new file mode 100644
> > index 000000000000..5293ece2147d
> > --- /dev/null
> > +++ b/tools/perf/arch/riscv/util/auxtrace.c
> > @@ -0,0 +1,219 @@
> > +// SPDX-License-Identifier: GPL-2.0
> > +/*
> > + * Risc-V E-Trace support
> > + */
> > +
> > +#include <linux/kernel.h>
> > +#include <linux/types.h>
> > +#include <linux/bitops.h>
> > +#include <linux/log2.h>
> > +#include <linux/zalloc.h>
> > +#include <errno.h>
> > +#include <time.h>
> > +
> > +#include <internal/lib.h>
> > +#include "../../../util/auxtrace.h"
> > +#include "../../../util/cpumap.h"
> > +#include "../../../util/debug.h"
> > +#include "../../../util/event.h"
> > +#include "../../../util/evlist.h"
> > +#include "../../../util/evsel.h"
> > +#include "../../../util/rvtrace.h"
> > +#include "../../../util/pmu.h"
> > +#include "../../../util/record.h"
> > +#include "../../../util/session.h"
> > +#include "../../../util/tsc.h"
>
> tsc.h not needed if rdtsc() is dropped
>
> > +
> > +#define RVTRACE_PMU_NAME "rvtrace"
> > +#define KiB(x) ((x) * 1024)
> > +#define MiB(x) ((x) * 1024 * 1024)
> > +
> > +struct rvtrace_recording {
> > +     struct auxtrace_record  itr;
> > +     struct perf_pmu *rvtrace_pmu;
> > +     struct evlist *evlist;
> > +};
> > +
> > +static size_t rvtrace_info_priv_size(struct auxtrace_record *itr __maybe_unused,
> > +                                  struct evlist *evlist __maybe_unused)
> > +{
> > +     return RVTRACE_AUXTRACE_PRIV_SIZE;
> > +}
> > +
> > +static int rvtrace_info_fill(struct auxtrace_record *itr, struct perf_session *session,
> > +                          struct perf_record_auxtrace_info *auxtrace_info, size_t priv_size)
> > +{
> > +     struct rvtrace_recording *ptr = container_of(itr, struct rvtrace_recording, itr);
> > +     struct perf_pmu *rvtrace_pmu = ptr->rvtrace_pmu;
> > +
> > +     if (priv_size != RVTRACE_AUXTRACE_PRIV_SIZE)
> > +             return -EINVAL;
> > +
> > +     if (!session->evlist->core.nr_mmaps)
> > +             return -EINVAL;
>
> This check is not needed
>
> > +
> > +     auxtrace_info->type = PERF_AUXTRACE_RISCV_TRACE;
> > +     auxtrace_info->priv[0] = rvtrace_pmu->type;
> > +
> > +     return 0;
> > +}
> > +
> > +static int rvtrace_set_auxtrace_mmap_page(struct record_opts *opts)
> > +{
> > +     bool privileged = perf_event_paranoid_check(-1);
> > +
> > +     if (!opts->full_auxtrace)
> > +             return 0;
> > +
> > +     if (opts->full_auxtrace && !opts->auxtrace_mmap_pages) {
> > +             if (privileged) {
> > +                     opts->auxtrace_mmap_pages = MiB(16) / page_size;
> > +             } else {
> > +                     opts->auxtrace_mmap_pages = KiB(128) / page_size;
> > +                     if (opts->mmap_pages == UINT_MAX)
> > +                             opts->mmap_pages = KiB(256) / page_size;
> > +             }
> > +     }
> > +
> > +     /* Validate auxtrace_mmap_pages */
> > +     if (opts->auxtrace_mmap_pages) {
> > +             size_t sz = opts->auxtrace_mmap_pages * (size_t)page_size;
> > +             size_t min_sz = KiB(8);
> > +
> > +             if (sz < min_sz || !is_power_of_2(sz)) {
> > +                     pr_err("Invalid mmap size : must be at least %zuKiB and a power of 2\n",
> > +                            min_sz / 1024);
> > +                     return -EINVAL;
> > +             }
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int rvtrace_recording_options(struct auxtrace_record *itr, struct evlist *evlist,
> > +                                  struct record_opts *opts)
> > +{
> > +     struct rvtrace_recording *ptr = container_of(itr, struct rvtrace_recording, itr);
> > +     struct perf_pmu *rvtrace_pmu = ptr->rvtrace_pmu;
> > +     struct evsel *evsel, *rvtrace_evsel = NULL;
> > +     struct evsel *tracking_evsel;
> > +     int err;
> > +
> > +     ptr->evlist = evlist;
> > +     evlist__for_each_entry(evlist, evsel) {
> > +             if (evsel->core.attr.type == rvtrace_pmu->type) {
> > +                     if (rvtrace_evsel) {
> > +                             pr_err("There may be only one " RVTRACE_PMU_NAME "x event\n");
>
> Should "x event\n" be just " event\n"
>
> > +                             return -EINVAL;
> > +                     }
> > +                     evsel->core.attr.freq = 0;
> > +                     evsel->core.attr.sample_period = 1;
> > +                     evsel->needs_auxtrace_mmap = true;
> > +                     rvtrace_evsel = evsel;
> > +                     opts->full_auxtrace = true;
> > +             }
> > +     }
> > +
> > +     err = rvtrace_set_auxtrace_mmap_page(opts);
> > +     if (err)
> > +             return err;
> > +     /*
> > +      * To obtain the auxtrace buffer file descriptor, the auxtrace event
> > +      * must come first.
> > +      */
> > +     evlist__to_front(evlist, rvtrace_evsel);
> > +     evsel__set_sample_bit(rvtrace_evsel, TIME);
> > +
> > +     /* Add dummy event to keep tracking */
> > +     err = parse_event(evlist, "dummy:u");
> > +     if (err)
> > +             return err;
> > +
> > +     tracking_evsel = evlist__last(evlist);
> > +     evlist__set_tracking_event(evlist, tracking_evsel);
> > +
> > +     tracking_evsel->core.attr.freq = 0;
> > +     tracking_evsel->core.attr.sample_period = 1;
> > +     evsel__set_sample_bit(tracking_evsel, TIME);
> > +
> > +     return 0;
> > +}
> > +
> > +static u64 rvtrace_reference(struct auxtrace_record *itr __maybe_unused)
> > +{
> > +     return rdtsc();
>
> rdtsc() is 0 (weak fn) for riscv, and does not make sense,
> so just return 0.
>
> > +}
> > +
> > +static void rvtrace_recording_free(struct auxtrace_record *itr)
> > +{
> > +     struct rvtrace_recording *ptr =
> > +                     container_of(itr, struct rvtrace_recording, itr);
>
> Does not need line wrap
>
> > +
> > +     free(ptr);
> > +}
> > +
> > +static struct auxtrace_record *rvtrace_recording_init(int *err, struct perf_pmu *rvtrace_pmu)
> > +{
> > +     struct rvtrace_recording *ptr;
> > +
> > +     if (!rvtrace_pmu) {
> > +             *err = -ENODEV;
> > +             return NULL;
> > +     }
> > +
> > +     ptr = zalloc(sizeof(*ptr));
> > +     if (!ptr) {
> > +             *err = -ENOMEM;
> > +             return NULL;
> > +     }
> > +
> > +     ptr->rvtrace_pmu = rvtrace_pmu;
> > +     ptr->itr.recording_options = rvtrace_recording_options;
> > +     ptr->itr.info_priv_size = rvtrace_info_priv_size;
> > +     ptr->itr.info_fill = rvtrace_info_fill;
> > +     ptr->itr.free = rvtrace_recording_free;
> > +     ptr->itr.reference = rvtrace_reference;
> > +     ptr->itr.read_finish = auxtrace_record__read_finish;
> > +     ptr->itr.alignment = 0;
> > +
> > +     *err = 0;
> > +     return &ptr->itr;
> > +}
> > +
> > +static struct perf_pmu *find_pmu_for_event(struct perf_pmu **pmus,
> > +                                        int pmu_nr, struct evsel *evsel)
> > +{
> > +     int i;
> > +
> > +     if (!pmus)
> > +             return NULL;
> > +
> > +     for (i = 0; i < pmu_nr; i++) {
> > +             if (evsel->core.attr.type == pmus[i]->type)
> > +                     return pmus[i];
> > +     }
> > +
> > +     return NULL;
> > +}
> > +
> > +struct auxtrace_record *auxtrace_record__init(struct evlist *evlist, int *err)
> > +{
> > +     struct perf_pmu *rvtrace_pmu = NULL;
> > +     struct perf_pmu *found_pmu = NULL;
> > +     struct evsel *evsel;
> > +
> > +     if (!evlist)
> > +             return NULL;
> > +
> > +     rvtrace_pmu = perf_pmus__find(RVTRACE_PMU_NAME);
> > +     evlist__for_each_entry(evlist, evsel) {
> > +             if (rvtrace_pmu && !found_pmu)
> > +                     found_pmu = find_pmu_for_event(&rvtrace_pmu, 1, evsel);
> > +     }
> > +
> > +     if (found_pmu)
> > +             return rvtrace_recording_init(err, rvtrace_pmu);
> > +
> > +     *err = 0;
> > +     return NULL;
> > +}
> > diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c
> > index a224687ffbc1..944a43d48739 100644
> > --- a/tools/perf/util/auxtrace.c
> > +++ b/tools/perf/util/auxtrace.c
> > @@ -1411,6 +1411,7 @@ int perf_event__process_auxtrace_info(const struct perf_tool *tool __maybe_unuse
> >       case PERF_AUXTRACE_VPA_DTL:
> >               err = powerpc_vpadtl_process_auxtrace_info(event, session);
> >               break;
> > +     case PERF_AUXTRACE_RISCV_TRACE:
> >       case PERF_AUXTRACE_UNKNOWN:
> >       default:
> >               return -EINVAL;
> > diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h
> > index 6947f3f284c0..4f4714c1b53f 100644
> > --- a/tools/perf/util/auxtrace.h
> > +++ b/tools/perf/util/auxtrace.h
> > @@ -46,6 +46,7 @@ enum auxtrace_type {
> >       PERF_AUXTRACE_S390_CPUMSF,
> >       PERF_AUXTRACE_HISI_PTT,
> >       PERF_AUXTRACE_VPA_DTL,
> > +     PERF_AUXTRACE_RISCV_TRACE,
> >  };
> >
> >  enum itrace_period_type {
> > diff --git a/tools/perf/util/rvtrace.h b/tools/perf/util/rvtrace.h
> > new file mode 100644
> > index 000000000000..24b32947fb4c
> > --- /dev/null
> > +++ b/tools/perf/util/rvtrace.h
> > @@ -0,0 +1,18 @@
> > +/* SPDX-License-Identifier: GPL-2.0 */
> > +/*
> > + * Copyright (c) 2026 Qualcomm Technologies, Inc.
> > + * Author: Mayuresh Chitale <mayuresh.chitale at oss.qualcomm.com>
> > + */
> > +
> > +#ifndef INCLUDE__UTIL_PERF_RVTRACE_H__
> > +#define INCLUDE__UTIL_PERF_RVTRACE_H__
> > +
> > +#include "debug.h"
> > +#include "auxtrace.h"
> > +#include "util/event.h"
> > +#include "util/session.h"
> > +#include <linux/bits.h>
> > +
> > +#define RVTRACE_AUXTRACE_PRIV_SIZE   sizeof(u64)
> > +
> > +#endif
>


From xueshuai at linux.alibaba.com  Tue Jun  2 04:37:23 2026
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Tue, 2 Jun 2026 19:37:23 +0800
Subject: [PATCH v2 4/8] riscv: ftrace: always preserve s0 in dynamic
 ftrace register frame
In-Reply-To: <20260528082310.1994388-5-wanghan@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
 <20260528082310.1994388-5-wanghan@linux.alibaba.com>
Message-ID: <d0ea70d2-f38b-4ec9-9522-d2d5b6d92f5c@linux.alibaba.com>



On 5/28/26 4:23 PM, Wang Han wrote:
> The dynamic ftrace entry/exit only saved s0 (the architectural frame
> pointer) when HAVE_FUNCTION_GRAPH_FP_TEST was selected. The upcoming
> reliable frame-pointer unwinder needs s0 to be present in
> ftrace_regs unconditionally so it can use the frame pointer as the
> function-graph return-address cookie regardless of FP_TEST.

Nit: A prefered commit log:

struct __arch_ftrace_regs declares s0 unconditionally, and both
ftrace_regs_get_frame_pointer() and ftrace_partial_regs() read it
unconditionally. But the SAVE_ABI_REGS / RESTORE_ABI_REGS macros in
mcount-dyn.S only stored s0 under HAVE_FUNCTION_GRAPH_FP_TEST
(CONFIG_FUNCTION_GRAPH_TRACER && CONFIG_FRAME_POINTER). With
CONFIG_FRAME_POINTER=n the slot held whatever was on the stack before,
so any callback going through ftrace_partial_regs() saw a garbage
regs->s0. RISC-V kernels default to FRAME_POINTER=y, which is why
this has not bitten in practice.

Save and restore s0 unconditionally in the dynamic ftrace ABI register
frame. This fixes the latent garbage-s0 case, brings the dynamic ftrace
path in line with the static _mcount path (mcount.S SAVE_ABI_STATE
already saves s0 unconditionally), and matches the frame layout already
documented in the comment above SAVE_ABI_REGS. It is also a
prerequisite for the upcoming reliable unwinder, which reads
ftrace_regs_get_frame_pointer(fregs) directly.

Save and restore s0 unconditionally in the dynamic ftrace ABI register
frame. This fixes the latent garbage-s0 case, brings the dynamic ftrace
path in line with the static _mcount path (mcount.S SAVE_ABI_STATE
already saves s0 unconditionally), and matches the frame layout already
documented in the comment above SAVE_ABI_REGS. It is also a
prerequisite for the upcoming reliable unwinder, which reads
ftrace_regs_get_frame_pointer(fregs) directly.

The cost is one extra REG_S/REG_L pair per traced call, negligible
compared to the overall ftrace cost; the existing FREGS_SIZE_ON_STACK
already reserved the slot, so no extra stack space is used.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai


From broonie at kernel.org  Mon Jun  1 08:00:52 2026
From: broonie at kernel.org (Mark Brown)
Date: Mon, 01 Jun 2026 16:00:52 +0100
Subject: [PATCH v3 0/2] ASoC: spacemit: add K3 SoC support
In-Reply-To: <20260522-k3-i2s-v3-0-08e3eb811d93@linux.spacemit.com>
References: <20260522-k3-i2s-v3-0-08e3eb811d93@linux.spacemit.com>
Message-ID: <178032605224.44654.17377992015065063925.b4-ty@b4>

On Fri, 22 May 2026 21:12:13 +0800, Troy Mitchell wrote:
> ASoC: spacemit: add K3 SoC support
> 
> This series adds K3 SoC support for the SpacemiT I2S controller driver.
> 
> Patch 1 adds the dt-bindings for the spacemit,k3-i2s compatible. The K3
> SoC uses the same I2S IP as K1 but requires additional clocks
> (sysclk_div, c_sysclk, c_bclk) that are shared across multiple I2S
> controllers.
> 
> [...]

Applied to

   https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.2

Thanks!

[1/2] ASoC: dt-bindings: add SpacemiT K3 SoC compatible
      https://git.kernel.org/broonie/sound/c/6bc6b28c0314
[2/2] ASoC: spacemit: add K3 SoC support with additional clocks
      https://git.kernel.org/broonie/sound/c/1c6ca2ca5c1b

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark



From Valentina.FernandezAlanis at microchip.com  Tue Jun  2 06:14:02 2026
From: Valentina.FernandezAlanis at microchip.com (Valentina.FernandezAlanis at microchip.com)
Date: Tue, 2 Jun 2026 13:14:02 +0000
Subject: [PATCH v1] rtc: mpfs: fix counter upload completion condition
In-Reply-To: <20260513-panhandle-ashy-70c6abf84d59@spud>
References: <20260513-panhandle-ashy-70c6abf84d59@spud>
Message-ID: <fa8c35eb-7572-4413-867d-db42df92790f@microchip.com>

On 13/05/2026 18:55, Conor Dooley wrote:
> From: Conor Dooley <conor.dooley at microchip.com>
>
> The condition that needs to be checked for upload completion is the
> UPLOAD bit in the completion register going low. The original iterations
> of this driver used a do-while and this was converted to a
> read_poll_timeout() during upstreaming without the condition being
> inverted as it should have been.
>
> I suspect that this went unnoticed until now because a) the first read
> was done when the bit was still set, immediately completing the
> read_poll_timeout() and b) because the RTC doesn't hold time when power
> is removed from the SoC reducing its utility (I for one keep it
> disabled). If my first suspicion was true when the driver was
> upstreamed, it's not true any longer though, hence the detection of the
> problem.
>
> Fixes: 0b31d703598dc ("rtc: Add driver for Microchip PolarFire SoC")
> CC: stable at vger.kernel.org
> Signed-off-by: Conor Dooley <conor.dooley at microchip.com>
Tested-by: Valentina Fernandez <valentina.fernandezalanis at microchip.com>
> ---
> CC: Valentina.FernandezAlanis at microchip.com
> CC: Conor Dooley <conor.dooley at microchip.com>
> CC: Daire McNamara <daire.mcnamara at microchip.com>
> CC: Alexandre Belloni <alexandre.belloni at bootlin.com>
> CC: linux-riscv at lists.infradead.org
> CC: linux-rtc at vger.kernel.org
> CC: linux-kernel at vger.kernel.org
> ---
>   drivers/rtc/rtc-mpfs.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/rtc/rtc-mpfs.c b/drivers/rtc/rtc-mpfs.c
> index 6aa3eae575d2a..ece6de4a6adbd 100644
> --- a/drivers/rtc/rtc-mpfs.c
> +++ b/drivers/rtc/rtc-mpfs.c
> @@ -112,7 +112,7 @@ static int mpfs_rtc_settime(struct device *dev, struct rtc_time *tm)
>   	ctrl |= CONTROL_UPLOAD_BIT;
>   	writel(ctrl, rtcdev->base + CONTROL_REG);
>   
> -	ret = read_poll_timeout(readl, prog, prog & CONTROL_UPLOAD_BIT, 0, UPLOAD_TIMEOUT_US,
> +	ret = read_poll_timeout(readl, prog, !(prog & CONTROL_UPLOAD_BIT), 0, UPLOAD_TIMEOUT_US,
>   				false, rtcdev->base + CONTROL_REG);
>   	if (ret) {
>   		dev_err(dev, "timed out uploading time to rtc");



From debug at rivosinc.com  Tue Jun  2 09:19:50 2026
From: debug at rivosinc.com (Deepak Gupta)
Date: Tue, 2 Jun 2026 09:19:50 -0700
Subject: [PATCH v23 06/28] riscv/mm : ensure PROT_WRITE leads to VM_READ | VM_WRITE
In-Reply-To: <87tsrli6lt.fsf@email.froward.int.ebiederm.org>
References: <20251112-v5_user_cfi_series-v23-0-b55691eacf4f@rivosinc.com>
 <20251112-v5_user_cfi_series-v23-6-b55691eacf4f@rivosinc.com>
 <87jyslndo4.fsf@igel.home> <CAKC1njS=AHu6uHrH4ae8VxcdEbhgiPXYCAoN3F_mnppBd3SwOA@mail.gmail.com>
 <875x44o9hj.fsf@igel.home> <CAKC1njSn_rtCj8ii876PNQTk0nsCTfWsb4DzdymufHVthh1Rkg@mail.gmail.com>
 <871peqgp9v.fsf@igel.home> <CAKC1njR+dTdvp+BmLGPtgd8dufiUwBtkQ9a-qinELT_Fmi13sQ@mail.gmail.com>
 <87wlwif04z.fsf@igel.home> <87tsrli6lt.fsf@email.froward.int.ebiederm.org>
Message-ID: <CAKC1njRapOxS6ibQdCuES1E3aAjsA+yGz4yZ1xJAZHU2vkAm_A@mail.gmail.com>

On Tue, Jun 2, 2026 at 3:23?AM Eric W. Biederman <ebiederm at xmission.com> wrote:
>
> Andreas Schwab <schwab at linux-m68k.org> writes:
>
> > On Jun 01 2026, Deepak Gupta wrote:
> >
> >> riscv uses `VM_SHADOW_STACK`. It's just very simple to use `protection_map`
> >> with just `VM_WRITE`. On RISC-V, `-W-` is a shadow stack mapping. It's not same
> >> on x86 or arm64. So `protection_map[VM_WRITE]` simply picks shadow stack
> >> encoding. We just ensure that PROT_WRITE is converted to
> >> "VM_READ | VM_WRITE" at vma level.
> >
> > That does not explain _why_ you need to make that user visible change,
> > when others can get away without it.
>
> Especially since as I recall the decision was made was that the user
> visible protection bits would match the mmap call.  If there is some
> combination an architecture does not support that would simply not be
> reflected in hardware until some future version of the hardware gets
> around to supporting it.
>
> This is what happened with executable page permissions on x86 for
> example.  It used to be that it was not possible to deny execute
> permission on a readable page.  Later that proved sufficiently valuable
> that support for denying execute permission was added to the hardware.
>
> That all happened quite transparently to userspace, that wasn't trying
> to assuming PROT_READ implied PROT_EXEC.
>
> So I am at a complete loss why someone would choose to break userspace
> by confusing hardware limitations with what userspace asks for in mmap.

Initially my plan was to re-use (only) VM_WRITE as (alias to) VM_SHADOW_STACK
on risc-v to match hardware Write-only PTE encoding and I didn't see
any opposition
to that initially. Until later when it was suggested to  use distinct
VM_SHADOW_STACK
encoding.
Although there wasn't any oppostion to this patch, seems like it made it in.

Now that I take a look at it, I think it can be made to work. Sorry about that.

Now that I have switched my affiliation to meta, I'll have to spend
some time to set
up risc-v dev environment.

I'll send a patch. Thanks.

>
> Eric
>


From robh at kernel.org  Tue Jun  2 09:24:50 2026
From: robh at kernel.org (Rob Herring)
Date: Tue, 2 Jun 2026 11:24:50 -0500
Subject: [PATCH v3 03/11] of: reserved_mem: avoid post-init UAF when
 alloc_reserved_mem_array() fails
In-Reply-To: <20260527032917.3385849-4-chenwandun1@gmail.com>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <20260527032917.3385849-4-chenwandun1@gmail.com>
Message-ID: <20260602162450.GA442759-robh@kernel.org>

On Wed, May 27, 2026 at 11:29:09AM +0800, Wandun Chen wrote:
> From: Wandun Chen <chenwandun at lixiang.com>
> 
> The global pointer 'reserved_mem' continues to reference the
> reserved_mem_array which lives in __initdata if
> alloc_reserved_mem_array() fails. of_reserved_mem_lookup() is
> exported for post-init use, that would dereference freed memory
> and trigger a use-after-free.
> 
> So reset reserved_mem_count to 0 when alloc_reserved_mem_array()
> fails.
> 
> Fixes: 00c9a452a235 ("of: reserved_mem: Add code to dynamically allocate reserved_mem array")

Fixes should come first in a series.

> Signed-off-by: Wandun Chen <chenwandun at lixiang.com>
> ---
>  drivers/of/of_reserved_mem.c | 20 ++++++++++++++------
>  1 file changed, 14 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
> index 313cbc57aa45..6d479381ff1f 100644
> --- a/drivers/of/of_reserved_mem.c
> +++ b/drivers/of/of_reserved_mem.c
> @@ -69,29 +69,31 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
>   * the initial static array is copied over to this new array and
>   * the new array is used from this point on.
>   */
> -static void __init alloc_reserved_mem_array(void)
> +static bool __init alloc_reserved_mem_array(void)
>  {
>  	struct reserved_mem *new_array;
>  	size_t alloc_size, copy_size, memset_size;
>  
> +	if (!total_reserved_mem_cnt)
> +		return true;
> +
>  	alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array));
>  	if (alloc_size == SIZE_MAX) {
>  		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
> -		return;
> +		goto fail;
>  	}
>  
>  	new_array = memblock_alloc(alloc_size, SMP_CACHE_BYTES);
>  	if (!new_array) {
>  		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -ENOMEM);
> -		return;
> +		goto fail;
>  	}
>  
>  	copy_size = array_size(reserved_mem_count, sizeof(*new_array));
>  	if (copy_size == SIZE_MAX) {
>  		memblock_free(new_array, alloc_size);
> -		total_reserved_mem_cnt = MAX_RESERVED_REGIONS;
>  		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);

These prints could be moved to 'fail'. Perhaps instead of just printing 
an error value, you can return the error value instead of boolean.

If you respin just this patch, I can pick it up for 7.2.

Rob


From fustini at kernel.org  Tue Jun  2 10:08:09 2026
From: fustini at kernel.org (Drew Fustini)
Date: Tue, 2 Jun 2026 10:08:09 -0700
Subject: [PATCH V5] riscv: errata: Add ERRATA_THEAD_WRITE_ONCE fixup
In-Reply-To: <20260421143154.1590156-1-guoren@kernel.org>
References: <20260421143154.1590156-1-guoren@kernel.org>
Message-ID: <ah8N+UThw4JnOdDb@x1>

On Tue, Apr 21, 2026 at 10:31:40AM -0400, guoren at kernel.org wrote:
> From: "Guo Ren (Alibaba DAMO Academy)" <guoren at kernel.org>
> 
> The early version of XuanTie C910 core has a store merge buffer
> delay problem. The store merge buffer could improve the store queue
> performance by merging multi-store requests, but when there are not
> continued store requests, the prior single store request would be
> waiting in the store queue for a long time. That would cause
> significant problems for communication between multi-cores. This
> problem was found on sg2042 & th1520 platforms with the qspinlock
> lock torture test.
> 
> So appending a fence w.o could immediately flush the store merge
> buffer and let other cores see the write result.
> 
> This will apply the WRITE_ONCE errata to handle the non-standard
> behavior via appending a fence w.o instruction for WRITE_ONCE().
> 
> This problem is only observed on the sg2042 hardware platform by
> running the lock_torture test program for half an hour. The problem
> was not found in the user space application, because interrupt can
> break the livelock.
> 
> Acked-by: Arnd Bergmann <arnd at arndb.de>
> Reviewed-by: Alexandre Ghiti <alexghiti at rivosinc.com>
> Reviewed-by: Leonardo Bras <leobras at redhat.com>
> Reviewed-by: Inochi Amaoto <inochiama at gmail.com>
> Tested-by: Han Gao <gaohan at iscas.ac.cn>
> Tested-by: Yao Zi <me at ziyao.cc>
> Cc: Chen Wang <unicorn_wang at outlook.com>
> Cc: Xiaoguang Xing <xiaoguang.xing at sophgo.com>
> Cc: Paul Walmsley <pjw at kernel.org>
> Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren at kernel.org>
> ---
> Changelog
> 
> v5:
>  - Add Acked-by: Arnd Bergmann <arnd at arndb.de> for asm/generic
>  - Add Reviewed-by: Inochi Amaoto <inochiama at gmail.com>
>  - Rebase on v7.0

Hi Paul,

Han Gao (revy) let me know that there is now an errata entry for 'Writes
might stick in C910/C920v1 store buffer for too long' [1].

Does that address the concern you had about documenting the errata?

Thanks,
Drew

[1] https://github.com/revyos/xuantie-c900-bugs#writes-might-stick-in-c910c920v1-store-buffer-for-too-long


From varunrmallya at gmail.com  Tue Jun  2 13:58:45 2026
From: varunrmallya at gmail.com (Varun R Mallya)
Date: Wed,  3 Jun 2026 02:28:45 +0530
Subject: [PATCH bpf-next 0/2] RISC-V JIT support for bpf_get_current_task/_btf
Message-ID: <20260602205847.102825-1-varunrmallya@gmail.com>

These two patches add support for the bpf_get_current_task and
bpf_get_current_task_btf kfuncs in RISC-V JIT and add a selftest.

The first patch adds support for cpu and feature detection on
the JIT disassembly helper function as RISC-V JITed code was not
being disassembled using `LLVMCreateDisasm` as it was missing the
"+c" CPU feature and JITed code contained RISC-V Compressed (C)
Extension. This patch generalizes that to detect CPU features and
enables testing on more RISC-V JIT work ahead.

The second patch, which actually adds this support has been benchmarked
on QEMU RISC-V and shows significant improvements.
It was benchmarked using a simple loop inside a bpf program that ran
bpf_get_current_task() and execution time was measured. It used
bpf_prog_test_run_opts() to repeatedly trigger the BPF program. The loop
ran in 1 second intervals and it kept firing bpf_prog_test_run_opts() as
fast as possible until a second had elapsed and then reported statistics.

Varun R Mallya (2):
  selftests/bpf: use host CPU features in JIT disassembler
  bpf, riscv: inline bpf_get_current_task() and
    bpf_get_current_task_btf()

 arch/riscv/net/bpf_jit_comp64.c                     |  9 +++++++++
 tools/testing/selftests/bpf/jit_disasm_helpers.c    | 13 +++++++++++--
 .../selftests/bpf/progs/verifier_jit_inline.c       |  2 ++
 3 files changed, 22 insertions(+), 2 deletions(-)

-- 
2.54.0



From varunrmallya at gmail.com  Tue Jun  2 13:58:46 2026
From: varunrmallya at gmail.com (Varun R Mallya)
Date: Wed,  3 Jun 2026 02:28:46 +0530
Subject: [PATCH bpf-next 1/2] selftests/bpf: use host CPU features in JIT disassembler
In-Reply-To: <20260602205847.102825-1-varunrmallya@gmail.com>
References: <20260602205847.102825-1-varunrmallya@gmail.com>
Message-ID: <20260602205847.102825-2-varunrmallya@gmail.com>

Pass the host CPU name and feature string to
LLVMCreateDisasmCPUFeatures() instead of using LLVMCreateDisasm(), so
the disassembler correctly decodes CPU-specific instructions and
extensions such as RISC-V compressed and vector instructions.

Signed-off-by: Varun R Mallya <varunrmallya at gmail.com>
---
 tools/testing/selftests/bpf/jit_disasm_helpers.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/bpf/jit_disasm_helpers.c b/tools/testing/selftests/bpf/jit_disasm_helpers.c
index 364c557c5115..3558fe10e28c 100644
--- a/tools/testing/selftests/bpf/jit_disasm_helpers.c
+++ b/tools/testing/selftests/bpf/jit_disasm_helpers.c
@@ -96,10 +96,19 @@ static int disasm_one_func(FILE *text_out, uint8_t *image, __u32 len)
 	__u32 *label_pc, pc;
 	int i, cnt, err = 0;
 	char buf[64];
+	char *cpu, *features;
 
 	triple = LLVMGetDefaultTargetTriple();
-	ctx = LLVMCreateDisasm(triple, &labels, 0, NULL, lookup_symbol);
-	if (!ASSERT_OK_PTR(ctx, "LLVMCreateDisasm")) {
+
+	cpu = LLVMGetHostCPUName();
+	features = LLVMGetHostCPUFeatures();
+
+	ctx = LLVMCreateDisasmCPUFeatures(triple, cpu, features, &labels, 0, NULL, lookup_symbol);
+
+	LLVMDisposeMessage(cpu);
+	LLVMDisposeMessage(features);
+
+	if (!ASSERT_OK_PTR(ctx, "LLVMCreateDisasmCPUFeatures")) {
 		err = -EINVAL;
 		goto out;
 	}
-- 
2.54.0



From varunrmallya at gmail.com  Tue Jun  2 13:58:47 2026
From: varunrmallya at gmail.com (Varun R Mallya)
Date: Wed,  3 Jun 2026 02:28:47 +0530
Subject: [PATCH bpf-next 2/2] bpf, riscv: inline bpf_get_current_task() and bpf_get_current_task_btf()
In-Reply-To: <20260602205847.102825-1-varunrmallya@gmail.com>
References: <20260602205847.102825-1-varunrmallya@gmail.com>
Message-ID: <20260602205847.102825-3-varunrmallya@gmail.com>

On RISC-V, the current task pointer is stored in the thread pointer
register (tp). Emit a single `mv a5, tp` instead of a full helper
call for BPF_FUNC_get_current_task and BPF_FUNC_get_current_task_btf.

Register bpf_jit_inlines_helper_call() entries for both helpers so the
verifier treats them as inlined, and add the expected `mv a5, tp`
annotation to the riscv64 selftests.

The following show changes before and after this patch.

Before patch:

      auipc  t1,0x817a    # load upper PC-relative address
      jalr   -2004(t1)    # call bpf_get_current_task helper
      mv     a5,a0        # move return value to BPF_REG_0

After patch:

      mv     a5,tp        # directly: a5 = current (tp = thread pointer)

Benchmark (bpf_prog_test_run wrapping bpf_get_current_task in loop,
batch=100, 10s, QEMU RISC-V):

              | runs/sec  | helper-calls/sec | ns/call
 -------------+-----------+------------------+---------
 Before patch |   173,490 |       17,349,090 |      57
 After patch  |   320,497 |       32,049,780 |      31
 -------------+-----------+------------------+---------
 Improvement  |   +84.7%  |          +84.7%  |  -45.6%

Signed-off-by: Varun R Mallya <varunrmallya at gmail.com>
---
 arch/riscv/net/bpf_jit_comp64.c                         | 9 +++++++++
 tools/testing/selftests/bpf/progs/verifier_jit_inline.c | 2 ++
 2 files changed, 11 insertions(+)

diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
index 2f1109dbf105..e2c70c70cca8 100644
--- a/arch/riscv/net/bpf_jit_comp64.c
+++ b/arch/riscv/net/bpf_jit_comp64.c
@@ -1808,6 +1808,13 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
 			break;
 		}
 
+		/* Implement helper call to bpf_get_current_task/_btf() inline */
+		if (insn->src_reg == 0 && (insn->imm == BPF_FUNC_get_current_task ||
+					   insn->imm == BPF_FUNC_get_current_task_btf)) {
+			emit_mv(bpf_to_rv_reg(BPF_REG_0, ctx), RV_REG_TP, ctx);
+			break;
+		}
+
 		mark_call(ctx);
 		ret = bpf_jit_get_func_addr(ctx->prog, insn, extra_pass,
 					    &addr, &fixed_addr);
@@ -2138,6 +2145,8 @@ bool bpf_jit_inlines_helper_call(s32 imm)
 {
 	switch (imm) {
 	case BPF_FUNC_get_smp_processor_id:
+	case BPF_FUNC_get_current_task:
+	case BPF_FUNC_get_current_task_btf:
 		return true;
 	default:
 		return false;
diff --git a/tools/testing/selftests/bpf/progs/verifier_jit_inline.c b/tools/testing/selftests/bpf/progs/verifier_jit_inline.c
index 885ff69a3a62..76d80605ec7f 100644
--- a/tools/testing/selftests/bpf/progs/verifier_jit_inline.c
+++ b/tools/testing/selftests/bpf/progs/verifier_jit_inline.c
@@ -10,6 +10,8 @@ __arch_x86_64
 __jited("	addq	%gs:{{.*}}, %rax")
 __arch_arm64
 __jited("	mrs	x8, SP_EL0")
+__arch_riscv64
+__jited("	mv	a5, tp")
 int inline_bpf_get_current_task(void)
 {
 	bpf_get_current_task();
-- 
2.54.0



From docular.xu at gmail.com  Tue Jun  2 14:42:51 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 3 Jun 2026 05:42:51 +0800
Subject: [PATCH] MAINTAINERS: add entry for SpacemiT reset controller driver
In-Reply-To: <20260602061734-GKD3815935@kernel.org>
References: <20260601-b4-spacemit-reset-maintainers-v1-1-1ab3014e9a35@gmail.com>
 <20260602061734-GKD3815935@kernel.org>
Message-ID: <CA+Ck9FZH=b8yc=d=s3n5k7dO5keZDQBxOJVc+ms4A8e_rVDDNw@mail.gmail.com>

Hi, Yixun

Thanks for the review.

> entry, the whole point of adding a didicated entry means someone
> willing to put effort in future maintenance, to help review/refactor/fix
> you can emphasis on this, and I just want to make sure we algined on

Right, that's the part I should have made explicit. I do plan to keep
maintaining drivers/reset/spacemit/, K1 and K3 now, K5 and K7 as they
land. I'll keep up with review and fixes, and reword the commit message
to say that.

> done), I'd personally prefer not puting them into commit message, but put
> them below "---" as background introduction if you still want..

Sure, will move that below '---'.

>
> > [1] https://lore.kernel.org/spacemit/20260120-k3-reset-v3-0-effe87f4bdbe at riscstar.com/
> for the convention, suggest to use more formal format like
> Link: https://.. [1]
>
> >
> also no blank line above
>

Agree, will do.

> and I'd still sugest to add spacemit mailing list explicitly

I will add that line:
L: spacemit at lists.linux.dev

I'll send v2 with these.

Thank you.
Guodong Xu

>
> --
> Yixun Lan (dlan)


From wang.yechao255 at zte.com.cn  Mon Jun  1 00:05:12 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Mon, 1 Jun 2026 15:05:12 +0800 (CST)
Subject: =?UTF-8?B?UmU6IMKgW1BBVENIIHYyIDIvM10gUklTQy1WOiBLVk06IGFkZCB0cmFjZXBvaW50cyBmb3IgZ3Vlc3QgcGFnZSBmYXVsdHM=?=
In-Reply-To: <CAAhSdy2qqpZ6qucwsuRZWnKgno03Ok4czv8RTgpjA73i+yFhng@mail.gmail.com>
References: 20260429173002565bdp1o7P0bvOs6yTz64yNx@zte.com.cn,20260429173534386Dfz8RALJT73-jMfif0nSb@zte.com.cn,CAAhSdy2qqpZ6qucwsuRZWnKgno03Ok4czv8RTgpjA73i+yFhng@mail.gmail.com
Message-ID: <20260601150512301NeokJXDe2YUikK2-C1yKG@zte.com.cn>

> > From: Wang Yechao <wang.yechao255 at zte.com.cn>
> >
> >
> > Add the kvm_page_fault event tracepoints to count the number of KVM
> >
> > guest page faults.
> >
> >
> > Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
> 
> Lot of redundant newlines in this patch. Looks like this patch
> was not sent using "git send-email".
> 
Sorry for the messy formatting. I'll resend the patch properly with git send-email
in the next version.

Best regards,
Yechao

> Regards,
> Anup


From wang.yechao255 at zte.com.cn  Mon Jun  1 00:18:27 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Mon, 1 Jun 2026 15:18:27 +0800 (CST)
Subject: =?UTF-8?B?UmU6IFtQQVRDSCB2MiAxLzNdIFJJU0MtVjogS1ZNOiBSZWZhY3RvciBrdm1fYXJjaF9jb21taXRfbWVtb3J5X3JlZ2lvbigp?=
In-Reply-To: <CAAhSdy3W4U_wYuH_pKq-V6iP6UE7e9h9Zhv=hKLykvWpiTEGVg@mail.gmail.com>
References: 20260429173002565bdp1o7P0bvOs6yTz64yNx@zte.com.cn,20260429173529259zFOx-ZsqSl_DS82KLXv0S@zte.com.cn,CAAhSdy3W4U_wYuH_pKq-V6iP6UE7e9h9Zhv=hKLykvWpiTEGVg@mail.gmail.com
Message-ID: <202606011518277289v9DwCtREfa34rRwjUhqn@zte.com.cn>

> > From: Wang Yechao <wang.yechao255 at zte.com.cn>
> >
> > Refactor kvm_arch_commit_memory_region() as a preparation for a future
> > commit to look cleaner and more understandable. Also, it looks more
> > like its arm64 and x86 counterparts.
> 
> This claim of making it similar to arm64 and x86 is incorrect. See below.
> 
> >
> > Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
> > ---
> >  arch/riscv/kvm/mmu.c | 12 +++++++++++-
> >  1 file changed, 11 insertions(+), 1 deletion(-)
> >
> > diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> > index 2d3def024270..dc6a8efde99e 100644
> > --- a/arch/riscv/kvm/mmu.c
> > +++ b/arch/riscv/kvm/mmu.c
> > @@ -141,12 +141,22 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
> >                                 const struct kvm_memory_slot *new,
> >                                 enum kvm_mr_change change)
> >  {
> > +       bool log_dirty_pages = new && new->flags & KVM_MEM_LOG_DIRTY_PAGES;
> > +       bool read_only = new && new->flags & KVM_MEM_READONLY;
> > +
> > +       /*
> > +        * Nothing more to do for RO slots (which can't be dirtied and can't be
> > +        * made writable) or CREATE/MOVE/DELETE of a slot.
> > +        */
> > +       if ((change != KVM_MR_FLAGS_ONLY) || read_only)
> > +               return;
> > +
> 
> I don't see how this is same as what x86 and arm64 does. There is
> no special casing for KVM_MR_FLAGS_ONLY in x86 and arm64.
> 
This is closer to the `kvm_mmu_slot_apply_flags` function on x86, so perhaps
it would be better to refer to the arm64 implementation to modify this function.

> >         /*
> >          * At this point memslot has been committed and there is an
> >          * allocated dirty_bitmap[], dirty pages will be tracked while
> >          * the memory slot is write protected.
> >          */
> > -       if (change != KVM_MR_DELETE && new->flags & KVM_MEM_LOG_DIRTY_PAGES) {
> > +       if (log_dirty_pages) {
> 
> Why drop "change != KVM_MR_DELETE" ?

The above condition "change != KVM_MR_FLAGS_ONLY" already filters out the
condition "change != KVM_MR_DELETE".

Best regards,
Yechao
> 
> >                 if (kvm_dirty_log_manual_protect_and_init_set(kvm))
> >                         return;
> >                 mmu_wp_memory_region(kvm, new->id);
> > --
> > 2.43.5
> 
> Regards,
> Anup


From wang.yechao255 at zte.com.cn  Mon Jun  1 00:50:34 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Mon, 1 Jun 2026 15:50:34 +0800 (CST)
Subject: =?UTF-8?B?UmU6IFtQQVRDSCB2MiAzLzNdIFJJU0MtVjogS1ZNOiBSZWNvdmVyIGdzdGFnZSBodWdlIHBhZ2UgbWFwcGluZ3MgZHVyaW5nwqBkaXNhYmxlLWRpcnR5LWxvZw==?=
In-Reply-To: <CAAhSdy1LE+oTMgO_C9SBvpqF=SHLOdDLGms5_ajO8pqDm=fFuA@mail.gmail.com>
References: 20260429173002565bdp1o7P0bvOs6yTz64yNx@zte.com.cn,20260429173539941luiwhNDDtflTHOClbNtk4@zte.com.cn,CAAhSdy1LE+oTMgO_C9SBvpqF=SHLOdDLGms5_ajO8pqDm=fFuA@mail.gmail.com
Message-ID: <20260601155034636JGXXXIkBJCy5tetcmoevj@zte.com.cn>

> > From: Wang Yechao <wang.yechao255 at zte.com.cn>
> >
> > When dirty logging is enabled, the gstage mappings are split into
> > 4K pages to track dirty pages. If the migration fails or is canceled,
> > in order to keep the VM's performance consistent with that before
> > dirty logging was enabled, the gstage huge page mappings are recoverd
> > when dirty logging is disabled.
> >
> > With this patch, dirty_log_perf_test shows a decrease in the number of
> > vCPU faults:
> >
> > $ perf stat -e kvm:kvm_page_fault \
> > /dirty_log_perf_test -s anonymous_hugetlb_1gb -v 1 -e -b 1G
> >
> > Before: 524,819      kvm:kvm_page_fault
> > After : 263,211      kvm:kvm_page_fault
> >
> > Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
> > ---
> >  arch/riscv/include/asm/kvm_gstage.h |  4 +++
> >  arch/riscv/kvm/gstage.c             | 42 ++++++++++++++++++++++++++
> >  arch/riscv/kvm/mmu.c                | 47 +++++++++++++++++++++++++++++
> >  3 files changed, 93 insertions(+)
> >
> > diff --git a/arch/riscv/include/asm/kvm_gstage.h b/arch/riscv/include/asm/kvm_gstage.h
> > index 9c908432bc17..a074493596d1 100644
> > --- a/arch/riscv/include/asm/kvm_gstage.h
> > +++ b/arch/riscv/include/asm/kvm_gstage.h
> > @@ -64,6 +64,10 @@ int kvm_riscv_gstage_split_huge(struct kvm_gstage *gstage,
> >                                 struct kvm_mmu_memory_cache *pcache,
> >                                 gpa_t addr, u32 target_level, bool flush);
> >
> > +void kvm_riscv_gstage_recover_huge(struct kvm_gstage *gstage, gpa_t addr,
> > +                                  unsigned long taget_page_size,
> > +                                  unsigned long *page_size);
> > +
> >  enum kvm_riscv_gstage_op {
> >         GSTAGE_OP_NOP = 0,      /* Nothing */
> >         GSTAGE_OP_CLEAR,        /* Clear/Unmap */
> > diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
> > index d9fe8be2a151..e2c8cbac30d9 100644
> > --- a/arch/riscv/kvm/gstage.c
> > +++ b/arch/riscv/kvm/gstage.c
> > @@ -337,6 +337,48 @@ int kvm_riscv_gstage_split_huge(struct kvm_gstage *gstage,
> >         return 0;
> >  }
> >
> > +void kvm_riscv_gstage_recover_huge(struct kvm_gstage *gstage, gpa_t addr,
> > +                                  unsigned long target_page_size,
> > +                                  unsigned long *page_size)
> > +{
> > +       u32 current_level = gstage->pgd_levels - 1;
> > +       pte_t *next_ptep = (pte_t *)gstage->pgd;
> > +       u32 target_level, out_level;
> > +       pte_t *ptep, *child_ptep;
> > +       int ret;
> > +
> > +       out_level = 0;
> > +       ret = gstage_page_size_to_level(gstage, target_page_size, &target_level);
> > +       if (ret)
> > +               goto out;
> > +
> > +       while (current_level >= target_level) {
> > +               ptep = (pte_t *)&next_ptep[gstage_pte_index(gstage, addr, current_level)];
> > +
> > +               out_level = current_level;
> > +               if (!pte_val(ptep_get(ptep)))
> > +                       goto out;
> > +
> > +               /* The mapping is already a huge page mapping. */
> > +               if (gstage_pte_leaf(ptep))
> > +                       goto out;
> > +
> > +               next_ptep = (pte_t *)gstage_pte_page_vaddr(ptep_get(ptep));
> > +               current_level--;
> > +       }
> > +
> > +       /* Replace the huge PTE with the first PTE entry of the child.*/
> > +       child_ptep = (pte_t *)&next_ptep[0];
> > +       if (gstage_pte_leaf(child_ptep)) {
> > +               set_pte(ptep, __pte(pte_val(ptep_get(child_ptep))));
> > +               gstage_tlb_flush(gstage, target_level, addr);
> > +               put_page(virt_to_page(next_ptep));
> > +       }
> > +
> > +out:
> > +       gstage_level_to_page_size(gstage, out_level, page_size);
> > +}
> > +
> >  void kvm_riscv_gstage_op_pte(struct kvm_gstage *gstage, gpa_t addr,
> >                              pte_t *ptep, u32 ptep_level, enum kvm_riscv_gstage_op op)
> >  {
> > diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> > index dc6a8efde99e..789e3362144f 100644
> > --- a/arch/riscv/kvm/mmu.c
> > +++ b/arch/riscv/kvm/mmu.c
> > @@ -16,6 +16,8 @@
> >  #include <asm/kvm_mmu.h>
> >  #include <asm/kvm_nacl.h>
> >
> > +static void kvm_mmu_recover_huge_pages(struct kvm *kvm, int slot);
> > +
> >  static void mmu_wp_memory_region(struct kvm *kvm, int slot)
> >  {
> >         struct kvm_memslots *slots = kvm_memslots(kvm);
> > @@ -160,6 +162,17 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
> >                 if (kvm_dirty_log_manual_protect_and_init_set(kvm))
> >                         return;
> >                 mmu_wp_memory_region(kvm, new->id);
> > +       } else {
> > +               /*
> > +                * Recover huge page mappings in the slot now that dirty logging
> > +                * is disabled, i.e. now that KVM does not have to track guest
> > +                * writes at 4KiB granularity.
> > +                *
> > +                * Dirty logging might be disabled by userspace if an ongoing VM
> > +                * live migration is cancelled and the VM must continue running
> > +                * on the source.
> > +                */
> > +               kvm_mmu_recover_huge_pages(kvm, new->id);
> >         }
> >  }
> >
> > @@ -598,3 +611,37 @@ void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu)
> >         if (!kvm_riscv_gstage_vmid_bits())
> >                 kvm_riscv_local_hfence_gvma_all();
> >  }
> > +
> > +static void kvm_mmu_recover_huge_pages(struct kvm *kvm, int slot)
> > +{
> > +       struct kvm_memslots *slots = kvm_memslots(kvm);
> > +       struct kvm_memory_slot *memslot = id_to_memslot(slots, slot);
> > +       unsigned long hva = gfn_to_hva(kvm, memslot->base_gfn);
> > +       phys_addr_t start = memslot->base_gfn << PAGE_SHIFT;
> > +       phys_addr_t end = (memslot->base_gfn + memslot->npages) << PAGE_SHIFT;
> > +       phys_addr_t addr = start;
> > +       struct kvm_gstage gstage;
> > +       unsigned long page_size;
> > +
> > +       if (!fault_supports_gstage_huge_mapping(memslot, hva))
> > +               return;
> > +
> > +       kvm_riscv_gstage_init(&gstage, kvm);
> > +
> > +       spin_lock(&kvm->mmu_lock);
> > +
> > +       while (addr < end) {
> > +               if (get_hva_mapping_size(kvm, hva) < PMD_SIZE) {
> 
> This is hard-coded to work only for 2MB hugepages.
> 
This does not only apply to 2M hugepages; 1G hugepages can also work. 
However, for 1G hugepages, they will only be recovered into 2M mappings, 
rather than being restored to the original 1G mapping before splitting.

In the next version, for 1G hugepages, I will consider recovering the gstage
mapping into 1G mappings.

Best regards,
Yechao

> > +                       addr += PMD_SIZE;
> > +                       hva  += PMD_SIZE;
> > +                       continue;
> > +               }
> > +
> > +               kvm_riscv_gstage_recover_huge(&gstage, addr, PMD_SIZE, &page_size);
> > +
> > +               addr += page_size;
> > +               hva  += page_size;
> > +               cond_resched_lock(&kvm->mmu_lock);
> > +       }
> > +       spin_unlock(&kvm->mmu_lock);
> > +}
> > --
> > 2.43.5
> 
> Regards,
> Anup


From inochiama at gmail.com  Tue Jun  2 15:15:08 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Wed, 3 Jun 2026 06:15:08 +0800
Subject: (subset) [PATCH 0/2] riscv: sophgo: sg2042: Enable PCIe DMA
 coherence
In-Reply-To: <ah6gcvKQlHlrW1qn@inochi.infowork>
References: <20260331171248.973014-1-gaohan@iscas.ac.cn>
 <178028263198.557087.6386925175219722340.b4-ty@b4>
 <ah6gcvKQlHlrW1qn@inochi.infowork>
Message-ID: <ah9VwHZbIuDSqmbe@inochi.infowork>

On Tue, Jun 02, 2026 at 05:21:32PM +0800, Inochi Amaoto wrote:
> On Mon, Jun 01, 2026 at 10:57:24AM +0800, Inochi Amaoto wrote:
> > On Wed, 01 Apr 2026 01:12:46 +0800, Han Gao wrote:
> > > The SG2042 hardware design supports cache-coherent PCIe.
> > > 
> > > With recent firmware updates [1], it allows to use DMA coherent.
> > > 
> > > [1] https://github.com/sophgo/edk2-non-osi/commit/017a5aea26a066fd2bf501b7893937183165af36
> > > 
> > > Han Gao (2):
> > >   dt-bindings: pci: sophgo: Add dma-coherent property for SG2042
> > >   riscv: dts: sophgo: Add dma-coherent to SG2042 PCIe controllers
> > > 
> > > [...]
> > 
> > Applied to for-next, thanks!
> > 
> > [2/2] riscv: dts: sophgo: Add dma-coherent to SG2042 PCIe controllers
> >       https://github.com/sophgo/linux/commit/e728a57834d06b9bbf9bbed69e3ea16416d257d5
> > 
> > Thanks,
> > Inochi
> > 
> 
> Revoke this apply due to https://lore.kernel.org/sophgo/ahu57vcS0oOFmCI9 at mertle/
> 

Reapply this as this error is resolved.

Regards,
Inochi


From docular.xu at gmail.com  Wed Jun  3 03:26:11 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 06:26:11 -0400
Subject: [PATCH v2] MAINTAINERS: add entry for SpacemiT reset controller
 driver
Message-ID: <20260603-b4-spacemit-reset-maintainers-v2-1-db0716d43a7f@gmail.com>

Add a MAINTAINERS entry for the SpacemiT reset controller driver
(drivers/reset/spacemit/) and its reset-ID header. I intend to
maintain it: the K1 and K3 instances now, and future SpacemiT SoCs
that reuse the common code.

Link: https://lore.kernel.org/spacemit/20260120-k3-reset-v3-0-effe87f4bdbe at riscstar.com/
Acked-by: Alex Elder <elder at riscstar.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
I introduced the drivers/reset/spacemit/ subdirectory, moved and
refactored the existing K1 reset support (originally written by
Alex Elder) into it, and wrote the K3 reset driver.
  
I contributed it as Guodong Xu <guodong at riscstar.com>;
docular.xu at gmail.com is my current address. A matching .mailmap update
is summited at
https://lore.kernel.org/all/20260601-b4-mailmap-guodong-xu-v1-1-ee9eff1e57ba at gmail.com/

Changes in v2:
- Reword the commit message
- Add L: spacemit at lists.linux.dev
- Collect Alex Elder's Acked-by
- Link to v1: https://patch.msgid.link/20260601-b4-spacemit-reset-maintainers-v1-1-1ab3014e9a35 at gmail.com
---
 MAINTAINERS | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 9ec290e38b44a..b7ef4ff2a2054 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25119,6 +25119,14 @@ S:	Maintained
 F:	Documentation/devicetree/bindings/i2c/spacemit,k1-i2c.yaml
 F:	drivers/i2c/busses/i2c-k1.c
 
+SPACEMIT RESET CONTROLLER DRIVER
+M:	Guodong Xu <docular.xu at gmail.com>
+L:	linux-riscv at lists.infradead.org
+L:	spacemit at lists.linux.dev
+S:	Maintained
+F:	drivers/reset/spacemit/
+F:	include/dt-bindings/reset/spacemit,k3-resets.h
+
 SPANISH DOCUMENTATION
 M:	Carlos Bilbao <carlos.bilbao at kernel.org>
 R:	Avadhut Naik <avadhut.naik at amd.com>

---
base-commit: e43ffb69e0438cddd72aaa30898b4dc446f664f8
change-id: 20260601-b4-spacemit-reset-maintainers-4b5a91599585

Best regards,
--  
Guodong Xu <docular.xu at gmail.com>



From thorsten.blum at linux.dev  Tue Jun  2 15:47:22 2026
From: thorsten.blum at linux.dev (Thorsten Blum)
Date: Wed,  3 Jun 2026 00:47:22 +0200
Subject: [PATCH RESEND] riscv: kexec: use min to simplify riscv_kexec_elf_load
Message-ID: <20260602224725.1088385-3-thorsten.blum@linux.dev>

Use min() to replace the open-coded version and assign the result
directly to kbuf.bufsz. Drop the now-unused local size variable.

Signed-off-by: Thorsten Blum <thorsten.blum at linux.dev>
---
 arch/riscv/kernel/kexec_elf.c | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/arch/riscv/kernel/kexec_elf.c b/arch/riscv/kernel/kexec_elf.c
index 531d348db84d..528141df90ba 100644
--- a/arch/riscv/kernel/kexec_elf.c
+++ b/arch/riscv/kernel/kexec_elf.c
@@ -19,6 +19,7 @@
 #include <linux/libfdt.h>
 #include <linux/types.h>
 #include <linux/memblock.h>
+#include <linux/minmax.h>
 #include <asm/setup.h>
 
 static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
@@ -27,7 +28,6 @@ static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
 {
 	int i;
 	int ret = 0;
-	size_t size;
 	struct kexec_buf kbuf = {};
 	const struct elf_phdr *phdr;
 
@@ -38,12 +38,8 @@ static int riscv_kexec_elf_load(struct kimage *image, struct elfhdr *ehdr,
 		if (phdr->p_type != PT_LOAD)
 			continue;
 
-		size = phdr->p_filesz;
-		if (size > phdr->p_memsz)
-			size = phdr->p_memsz;
-
 		kbuf.buffer = (void *) elf_info->buffer + phdr->p_offset;
-		kbuf.bufsz = size;
+		kbuf.bufsz = min(phdr->p_filesz, phdr->p_memsz);
 		kbuf.buf_align = phdr->p_align;
 		kbuf.mem = phdr->p_paddr - old_pbase + new_pbase;
 		kbuf.memsz = phdr->p_memsz;


From docular.xu at gmail.com  Wed Jun  3 04:11:55 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:11:55 -0400
Subject: [PATCH v3 00/15] riscv: hwprobe: Expose RVA23U64 base behavior
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>

This series builds on Andrew Jones's earlier RFC [1]. It lets
userspace check for RVA23U64 conformance in one call, instead of
walking hwprobe + prctl across every mandatory extension.

The series adds a small framework that resolves profile-class
bases (IMA and RVA23U64) from the kernel's ISA extension bitmap at
init time, and surfaces the result through both /proc/cpuinfo and
hwprobe. Later patches can add RVA23S64, and backward RVA22 / RVA20
detection, to riscv_set_isa_bases() without changes to the
surrounding code.

Changes in v3 came from these sources:
1. A rebase from v7.1-rc2 to v7.1-rc6;
2. hwprobe.rst clean-up is moved to first;
3. Zic64b is added as a first-class ISA extension (dt-binding,
   cpufeature parsing, and hwprobe export);
4. Resolve review comments from v2.

V3 Series outline:

  1-3. hwprobe.rst clean-ups: normalize indentation first, then
       document EXT_ZICFISS / EXT_ZICFILP, and standardize single-letter
       extension capitalization.

   4.  Zicclsm: cpufeature parsing + hwprobe export.
   5.  Ziccamoa, Ziccif, Ziccrse, Za64rs: cpufeature parsing + hwprobe export.
   6.  B: cpuufeature pasrsing + hwprobe export, as the Zba/Zbb/Zbs set.

   7.  Zic64b: dt-bindings, with a schema check.
   8.  Zic64b: cpufeature parsing + hwprobe export.
 9-11. dts: Declare zic64b in the SpacemiT K3, SpacemiT K1, and Sophgo
       SG2044 device trees.

  12.  riscv_have_user_pmlen(): arch-level accessor for user
       pointer-masking PMLEN support, used by RVA23U64 detection.

  13.  cpufeature: per-hart and host-wide isa_bases bitmaps,
       populated at init time. IMA and RVA23U64 detection lives
       here.

  14.  /proc/cpuinfo: print "isa bases:" and "hart isa bases:", eg. rva23u64.
  15.  hwprobe: expose RVA23U64.

Tested on both K3 Pico ITX and Qemu with -cpu rva23s64,sv39=on:
  - /proc/cpuinfo reports "isa bases : rv64ima rva23u64" on both the
    aggregated and per-hart lines.
  - hwprobe RISCV_HWPROBE_KEY_BASE_BEHAVIOR returns
    BASE_BEHAVIOR_IMA | BASE_BEHAVIOR_RVA23U64.

Based on v7.1-rc6 plus [2]; happy to rebase onto another tree if needed.
A branch is available for all patches in the series: [3].

Note: [2] is only required in order to save the merge effort for adding
      'Zic64b' and 'Ziccrse' into the same k3.dtsi.

Link: https://lore.kernel.org/linux-riscv/20260206002349.96740-1-andrew.jones at oss.qualcomm.com/ [1]
Link: https://lore.kernel.org/all/20260602070257-KYC5031219 at kernel.org/ [2]
Link: https://github.com/docularxu/linux/commits/b4/rva23u64-hwprobe/ [3]
---
Changes in v3:
- Add Zic64b as a first-class ISA extension: dt-binding, cpufeature
  parsing with a validate check, hwprobe export, and device-tree
  declarations for K3/K1/SG2044.
- Patch 1 is now a clean up of hwprobe.rst indentation.
- Document RISCV_HWPROBE_EXT_ZICFILP alongside ZICFISS.
- Move the Zicclsm hwprobe.rst entry to the IMA_EXT_1 section to match
  its bit allocation.
- Collect Anup Patel's Acked-by/Reviewed-by on Patch 3, the capitalization.
- In cpufeature.c, set the local ext_mask with __set_bit().
- Update Guodong Xu's email to docular.xu at gmail.com.

- Link to v2: https://patch.msgid.link/20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc at riscstar.com

Changes in v2 (since Andrew's RFC v1):
- Rebased onto v7.1-rc2.
- Reworked rva23u64 detection into per-hart and host isa_bases bitmaps,
  shared by /proc/cpuinfo and hwprobe.
- Scoped to IMA and RVA23U64 (RVA23S64, RVA20/RVA22 cpuinfo output deferred).

- Link to v1:  https://lore.kernel.org/linux-riscv/20260206002349.96740-1-andrew.jones at oss.qualcomm.com

BR,
Guodong Xu

To: Jonathan Corbet <corbet at lwn.net>
To: Paul Walmsley <pjw at kernel.org>
To: Palmer Dabbelt <palmer at dabbelt.com>
To: Conor Dooley <conor.dooley at microchip.com>
To: Albert Ou <aou at eecs.berkeley.edu>
To: Alexandre Ghiti <alex at ghiti.fr>
To: Shuah Khan <shuah at kernel.org>
To: Anup Patel <anup at brainfault.org>
To: Atish Patra <atish.patra at linux.dev>
To: Shuah Khan <skhan at linuxfoundation.org>
To: Deepak Gupta <debug at rivosinc.com>
To: Zong Li <zong.li at sifive.com>
To: Christian Brauner <brauner at kernel.org>
Cc: Andrew Jones <andrew.jones at oss.qualcomm.com>
Cc: Charles Jenkins <thecharlesjenkins at gmail.com>
Cc: Samuel Holland <samuel.holland at sifive.com>
Cc: linux-doc at vger.kernel.org
Cc: linux-riscv at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
Cc: linux-kselftest at vger.kernel.org
Cc: kvm at vger.kernel.org
Cc: kvm-riscv at lists.infradead.org
Signed-off-by: Guodong Xu <docular.xu at gmail.com>

---
Andrew Jones (4):
      riscv: hwprobe.rst: Make indentation consistent
      riscv: Add Ziccamoa, Ziccif, Ziccrse, and Za64rs to cpufeature and hwprobe
      riscv: Add B to hwcap and hwprobe
      riscv: Add a getter for user PMLEN support

Charlie Jenkins (1):
      riscv: Standardize extension capitalization

Guodong Xu (9):
      riscv: hwprobe.rst: Document EXT_ZICFISS and EXT_ZICFILP
      dt-bindings: riscv: Add Zic64b extension description
      riscv: Add Zic64b to cpufeature and hwprobe
      riscv: dts: spacemit: k3: Add Zic64b ISA extension
      riscv: dts: spacemit: k1: Add Zic64b ISA extension
      riscv: dts: sophgo: sg2044: Add Zic64b ISA extension
      riscv: cpufeature: Introduce ISA bases bitmap and rva23u64 detection
      riscv: cpu: Output isa bases lines in cpuinfo
      riscv: hwprobe: Introduce rva23u64 base behavior

Jesse Taube (1):
      riscv: Add Zicclsm to cpufeature and hwprobe

 Documentation/arch/riscv/hwprobe.rst               | 239 ++++++++++++---------
 .../devicetree/bindings/riscv/extensions.yaml      |  20 ++
 arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi        | 128 +++++------
 arch/riscv/boot/dts/spacemit/k1.dtsi               |  80 +++----
 arch/riscv/boot/dts/spacemit/k3.dtsi               |  48 ++---
 arch/riscv/include/asm/cpufeature.h                |  14 ++
 arch/riscv/include/asm/hwcap.h                     |  24 ++-
 arch/riscv/include/asm/processor.h                 |   4 +
 arch/riscv/include/asm/switch_to.h                 |   4 +-
 arch/riscv/include/uapi/asm/hwcap.h                |   1 +
 arch/riscv/include/uapi/asm/hwprobe.h              |  10 +-
 arch/riscv/kernel/cpu.c                            |  26 +++
 arch/riscv/kernel/cpufeature.c                     | 182 ++++++++++++++--
 arch/riscv/kernel/process.c                        |  12 ++
 arch/riscv/kernel/sys_hwprobe.c                    |  34 ++-
 arch/riscv/kvm/isa.c                               |  16 +-
 arch/riscv/kvm/main.c                              |   2 +-
 arch/riscv/kvm/vcpu_fp.c                           |  20 +-
 arch/riscv/kvm/vcpu_onereg.c                       |   6 +-
 arch/riscv/kvm/vcpu_vector.c                       |  10 +-
 tools/testing/selftests/riscv/hwprobe/which-cpus.c |   2 +-
 21 files changed, 586 insertions(+), 296 deletions(-)
---
base-commit: a04586b3d291a349301c2463bc485d05a3968383
change-id: 20260508-rva23u64-hwprobe-v2-1d20739cbb8e

Best regards,
--  
Guodong Xu <docular.xu at gmail.com>



From docular.xu at gmail.com  Wed Jun  3 04:11:56 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:11:56 -0400
Subject: [PATCH v3 01/15] riscv: hwprobe.rst: Make indentation consistent
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-1-5529a7b28384@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

A handful of vendor-extension entries indent continuation lines with a
tab character, while the rest of hwprobe.rst uses spaces.  In addition,
many list items align their continuation lines under the 'm' of
':c:macro:' (column 7) rather than under the item text (column 4), so
the file mixes several indentation styles.

Replace the tabs with spaces and align every list item's continuation
lines under the item text, giving the whole file one consistent style.

Whitespace-only change, no functional change.

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
[Guodong: extend from tabs->spaces to normalizing all continuation-line
 indentation across the file]
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3:
- Move to the front of the series.
- Extend from replacing tabs to normalizing all continuation-line
  indentation, so later patches add documentation on top of a
  consistent base (Andrew).
---
 Documentation/arch/riscv/hwprobe.rst | 194 +++++++++++++++++------------------
 1 file changed, 97 insertions(+), 97 deletions(-)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index c420a8349bc68..a09a8f16bd16f 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -82,121 +82,121 @@ The following keys are defined:
     version 1.0 of the RISC-V Vector extension manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBA`: The Zba address generation extension is
-       supported, as defined in version 1.0 of the Bit-Manipulation ISA
-       extensions.
+    supported, as defined in version 1.0 of the Bit-Manipulation ISA
+    extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBB`: The Zbb extension is supported, as defined
-       in version 1.0 of the Bit-Manipulation ISA extensions.
+    in version 1.0 of the Bit-Manipulation ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBS`: The Zbs extension is supported, as defined
-       in version 1.0 of the Bit-Manipulation ISA extensions.
+    in version 1.0 of the Bit-Manipulation ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICBOZ`: The Zicboz extension is supported, as
-       ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+    ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBC` The Zbc extension is supported, as defined
-       in version 1.0 of the Bit-Manipulation ISA extensions.
+    in version 1.0 of the Bit-Manipulation ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBKB` The Zbkb extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBKC` The Zbkc extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBKX` The Zbkx extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKND` The Zknd extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKNE` The Zkne extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKNH` The Zknh extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKSED` The Zksed extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKSH` The Zksh extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKT` The Zkt extension is supported, as defined
-       in version 1.0 of the Scalar Crypto ISA extensions.
+    in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVBB`: The Zvbb extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVBC`: The Zvbc extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKB`: The Zvkb extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKG`: The Zvkg extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKNED`: The Zvkned extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKNHA`: The Zvknha extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKNHB`: The Zvknhb extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKSED`: The Zvksed extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKSH`: The Zvksh extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKT`: The Zvkt extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZFH`: The Zfh extension version 1.0 is supported
-       as defined in the RISC-V ISA manual.
+    as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZFHMIN`: The Zfhmin extension version 1.0 is
-       supported as defined in the RISC-V ISA manual.
+    supported as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZIHINTNTL`: The Zihintntl extension version 1.0
-       is supported as defined in the RISC-V ISA manual.
+    is supported as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVFH`: The Zvfh extension is supported as
-       defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
-       ("Remove draft warnings from Zvfh[min]").
+    defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
+    ("Remove draft warnings from Zvfh[min]").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVFHMIN`: The Zvfhmin extension is supported as
-       defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
-       ("Remove draft warnings from Zvfh[min]").
+    defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
+    ("Remove draft warnings from Zvfh[min]").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZFA`: The Zfa extension is supported as
-       defined in the RISC-V ISA manual starting from commit 056b6ff467c7
-       ("Zfa is ratified").
+    defined in the RISC-V ISA manual starting from commit 056b6ff467c7
+    ("Zfa is ratified").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZTSO`: The Ztso extension is supported as
-       defined in the RISC-V ISA manual starting from commit 5618fb5a216b
-       ("Ztso is now ratified.")
+    defined in the RISC-V ISA manual starting from commit 5618fb5a216b
+    ("Ztso is now ratified.")
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZACAS`: The Zacas extension is supported as
-       defined in the Atomic Compare-and-Swap (CAS) instructions manual starting
-       from commit 5059e0ca641c ("update to ratified").
+    defined in the Atomic Compare-and-Swap (CAS) instructions manual starting
+    from commit 5059e0ca641c ("update to ratified").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICNTR`: The Zicntr extension version 2.0
-       is supported as defined in the RISC-V ISA manual.
+    is supported as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICOND`: The Zicond extension is supported as
-       defined in the RISC-V Integer Conditional (Zicond) operations extension
-       manual starting from commit 95cf1f9 ("Add changes requested by Ved
-       during signoff")
+    defined in the RISC-V Integer Conditional (Zicond) operations extension
+    manual starting from commit 95cf1f9 ("Add changes requested by Ved
+    during signoff")
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZIHINTPAUSE`: The Zihintpause extension is
-       supported as defined in the RISC-V ISA manual starting from commit
-       d8ab5c78c207 ("Zihintpause is ratified").
+    supported as defined in the RISC-V ISA manual starting from commit
+    d8ab5c78c207 ("Zihintpause is ratified").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZIHPM`: The Zihpm extension version 2.0
-       is supported as defined in the RISC-V ISA manual.
+    is supported as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVE32X`: The Vector sub-extension Zve32x is
     supported, as defined by version 1.0 of the RISC-V Vector extension manual.
@@ -214,84 +214,84 @@ The following keys are defined:
     supported, as defined by version 1.0 of the RISC-V Vector extension manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZIMOP`: The Zimop May-Be-Operations extension is
-       supported as defined in the RISC-V ISA manual starting from commit
-       58220614a5f ("Zimop is ratified/1.0").
+    supported as defined in the RISC-V ISA manual starting from commit
+    58220614a5f ("Zimop is ratified/1.0").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCA`: The Zca extension part of Zc* standard
-       extensions for code size reduction, as ratified in commit 8be3419c1c0
-       ("Zcf doesn't exist on RV64 as it contains no instructions") of
-       riscv-code-size-reduction.
+    extensions for code size reduction, as ratified in commit 8be3419c1c0
+    ("Zcf doesn't exist on RV64 as it contains no instructions") of
+    riscv-code-size-reduction.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCB`: The Zcb extension part of Zc* standard
-       extensions for code size reduction, as ratified in commit 8be3419c1c0
-       ("Zcf doesn't exist on RV64 as it contains no instructions") of
-       riscv-code-size-reduction.
+    extensions for code size reduction, as ratified in commit 8be3419c1c0
+    ("Zcf doesn't exist on RV64 as it contains no instructions") of
+    riscv-code-size-reduction.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCD`: The Zcd extension part of Zc* standard
-       extensions for code size reduction, as ratified in commit 8be3419c1c0
-       ("Zcf doesn't exist on RV64 as it contains no instructions") of
-       riscv-code-size-reduction.
+    extensions for code size reduction, as ratified in commit 8be3419c1c0
+    ("Zcf doesn't exist on RV64 as it contains no instructions") of
+    riscv-code-size-reduction.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCF`: The Zcf extension part of Zc* standard
-       extensions for code size reduction, as ratified in commit 8be3419c1c0
-       ("Zcf doesn't exist on RV64 as it contains no instructions") of
-       riscv-code-size-reduction.
+    extensions for code size reduction, as ratified in commit 8be3419c1c0
+    ("Zcf doesn't exist on RV64 as it contains no instructions") of
+    riscv-code-size-reduction.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCMOP`: The Zcmop May-Be-Operations extension is
-       supported as defined in the RISC-V ISA manual starting from commit
-       c732a4f39a4 ("Zcmop is ratified/1.0").
+    supported as defined in the RISC-V ISA manual starting from commit
+    c732a4f39a4 ("Zcmop is ratified/1.0").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZAWRS`: The Zawrs extension is supported as
-       ratified in commit 98918c844281 ("Merge pull request #1217 from
-       riscv/zawrs") of riscv-isa-manual.
+    ratified in commit 98918c844281 ("Merge pull request #1217 from
+    riscv/zawrs") of riscv-isa-manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZAAMO`: The Zaamo extension is supported as
-       defined in the in the RISC-V ISA manual starting from commit e87412e621f1
-       ("integrate Zaamo and Zalrsc text (#1304)").
+    defined in the in the RISC-V ISA manual starting from commit e87412e621f1
+    ("integrate Zaamo and Zalrsc text (#1304)").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZALASR`: The Zalasr extension is supported as
-       frozen at commit 194f0094 ("Version 0.9 for freeze") of riscv-zalasr.
+    frozen at commit 194f0094 ("Version 0.9 for freeze") of riscv-zalasr.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZALRSC`: The Zalrsc extension is supported as
-       defined in the in the RISC-V ISA manual starting from commit e87412e621f1
-       ("integrate Zaamo and Zalrsc text (#1304)").
+    defined in the in the RISC-V ISA manual starting from commit e87412e621f1
+    ("integrate Zaamo and Zalrsc text (#1304)").
 
   * :c:macro:`RISCV_HWPROBE_EXT_SUPM`: The Supm extension is supported as
-       defined in version 1.0 of the RISC-V Pointer Masking extensions.
+    defined in version 1.0 of the RISC-V Pointer Masking extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZFBFMIN`: The Zfbfmin extension is supported as
-       defined in the RISC-V ISA manual starting from commit 4dc23d6229de
-       ("Added Chapter title to BF16").
+    defined in the RISC-V ISA manual starting from commit 4dc23d6229de
+    ("Added Chapter title to BF16").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVFBFMIN`: The Zvfbfmin extension is supported as
-       defined in the RISC-V ISA manual starting from commit 4dc23d6229de
-       ("Added Chapter title to BF16").
+    defined in the RISC-V ISA manual starting from commit 4dc23d6229de
+    ("Added Chapter title to BF16").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVFBFWMA`: The Zvfbfwma extension is supported as
-       defined in the RISC-V ISA manual starting from commit 4dc23d6229de
-       ("Added Chapter title to BF16").
+    defined in the RISC-V ISA manual starting from commit 4dc23d6229de
+    ("Added Chapter title to BF16").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICBOM`: The Zicbom extension is supported, as
-       ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+    ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZABHA`: The Zabha extension is supported as
-       ratified in commit 49f49c842ff9 ("Update to Rafified state") of
-       riscv-zabha.
+    ratified in commit 49f49c842ff9 ("Update to Rafified state") of
+    riscv-zabha.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICBOP`: The Zicbop extension is supported, as
-       ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+    ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZILSD`: The Zilsd extension is supported as
-       defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
-       load/store pair for RV32 with the main manual") of the riscv-isa-manual.
+    defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
+    load/store pair for RV32 with the main manual") of the riscv-isa-manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCLSD`: The Zclsd extension is supported as
-       defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
-       load/store pair for RV32 with the main manual") of the riscv-isa-manual.
+    defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
+    load/store pair for RV32 with the main manual") of the riscv-isa-manual.
 
 * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated.  Returns similar values to
-     :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
-     mistakenly classified as a bitmask rather than a value.
+  :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
+  mistakenly classified as a bitmask rather than a value.
 
 * :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`: An enum value describing
   the performance of misaligned scalar native word accesses on the selected set
@@ -326,7 +326,7 @@ The following keys are defined:
 * :c:macro:`RISCV_HWPROBE_KEY_TIME_CSR_FREQ`: Frequency (in Hz) of `time CSR`.
 
 * :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF`: An enum value describing the
-     performance of misaligned vector accesses on the selected set of processors.
+  performance of misaligned vector accesses on the selected set of processors.
 
   * :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN`: The performance of misaligned
     vector accesses is unknown.
@@ -348,7 +348,7 @@ The following keys are defined:
   * MIPS
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XMIPSEXECTL`: The xmipsexectl vendor
-        extension is supported in the MIPS ISA extensions spec.
+      extension is supported in the MIPS ISA extensions spec.
 
 * :c:macro:`RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0`: A bitmask containing the
   thead vendor extensions that are compatible with the
@@ -357,8 +357,8 @@ The following keys are defined:
   * T-HEAD
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XTHEADVECTOR`: The xtheadvector vendor
-        extension is supported in the T-Head ISA extensions spec starting from
-	commit a18c801634 ("Add T-Head VECTOR vendor extension. ").
+      extension is supported in the T-Head ISA extensions spec starting from
+      commit a18c801634 ("Add T-Head VECTOR vendor extension. ").
 
 * :c:macro:`RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE`: An unsigned int which
   represents the size of the Zicbom block in bytes.
@@ -370,20 +370,20 @@ The following keys are defined:
   * SIFIVE
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCDOD`: The Xsfqmaccdod vendor
-        extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
-	Extensions Specification.
+      extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
+      Extensions Specification.
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCQOQ`: The Xsfqmaccqoq vendor
-        extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
-	Instruction Extensions Specification.
+      extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
+      Instruction Extensions Specification.
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFNRCLIPXFQF`: The Xsfvfnrclipxfqf
-        vendor extension is supported in version 1.0 of SiFive FP32-to-int8 Ranged
-	Clip Instructions Extensions Specification.
+      vendor extension is supported in version 1.0 of SiFive FP32-to-int8 Ranged
+      Clip Instructions Extensions Specification.
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ`: The Xsfvfwmaccqqq
-        vendor extension is supported in version 1.0 of Matrix Multiply Accumulate
-	Instruction Extensions Specification.
+      vendor extension is supported in version 1.0 of Matrix Multiply Accumulate
+      Instruction Extensions Specification.
 
 * :c:macro:`RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE`: An unsigned int which
   represents the size of the Zicbop block in bytes.

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:11:57 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:11:57 -0400
Subject: [PATCH v3 02/15] riscv: hwprobe.rst: Document EXT_ZICFISS and
 EXT_ZICFILP
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-2-5529a7b28384@gmail.com>

Commit 30c3099036a9 ("riscv/hwprobe: add zicfilp / zicfiss
enumeration in hwprobe") added RISCV_HWPROBE_EXT_ZICFISS and
RISCV_HWPROBE_EXT_ZICFILP, but did not add matching entries to
Documentation/arch/riscv/hwprobe.rst.  Add them now.

Fixes: 30c3099036a9 ("riscv/hwprobe: add zicfilp / zicfiss enumeration in hwprobe")
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3:
- Also document RISCV_HWPROBE_EXT_ZICFILP (bit 63 of IMA_EXT_0), the
  sibling enumeration added by the same commit (Andrew).
v2: New patch.
---
 Documentation/arch/riscv/hwprobe.rst | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index a09a8f16bd16f..3cedaaa53f331 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -289,6 +289,11 @@ The following keys are defined:
     defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
     load/store pair for RV32 with the main manual") of the riscv-isa-manual.
 
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICFILP`: The Zicfilp extension is supported,
+    as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
+    extensions specification, ratified in commit ff03d8485a04 ("Update to
+    ratified state") of riscv-cfi.
+
 * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated.  Returns similar values to
   :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
   mistakenly classified as a bitmask rather than a value.
@@ -391,3 +396,8 @@ The following keys are defined:
 * :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_1`: A bitmask containing additional
   extensions that are compatible with the
   :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICFISS`: The Zicfiss extension is supported,
+    as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
+    extensions specification, ratified in commit ff03d8485a04 ("Update to
+    ratified state") of riscv-cfi.

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:11:58 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:11:58 -0400
Subject: [PATCH v3 03/15] riscv: Standardize extension capitalization
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-3-5529a7b28384@gmail.com>

From: Charlie Jenkins <charlie at rivosinc.com>

The base extensions are often lowercase and were written as lowercase in
hwcap, but other references to these extensions in the kernel are
uppercase. Standardize the case to make it easier to handle macro
expansion.

Signed-off-by: Charlie Jenkins <thecharlesjenkins at gmail.com>
[Apply KVM_ISA_EXT_ARR(), fixup all KVM use.]
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
Acked-by: Anup Patel <anup at brainfault.org>
Reviewed-by: Anup Patel <anup at brainfault.org>

---
v3:
- Collected Anup's Acked-by and Reviewed-by.
- Rebased onto v7.1-rc6: two more occurances between -rc2 and -rc6:
   1). isa2hwcap[] indices added by commit 41337097f2823
   2). the T-Head "v" workaround's clear_bit() added by commit d272b8d2dd132
v2:
- Rebased onto v7.1-rc2.
- KVM_ISA_EXT_ARR() consolidation moved to its new upstream location
  (kvm/isa.c); host-side checks now use kvm_riscv_isa_check_host().
---
 arch/riscv/include/asm/hwcap.h     | 18 ++++++++--------
 arch/riscv/include/asm/switch_to.h |  4 ++--
 arch/riscv/kernel/cpufeature.c     | 44 +++++++++++++++++++-------------------
 arch/riscv/kernel/sys_hwprobe.c    |  4 ++--
 arch/riscv/kvm/isa.c               | 16 +++++++-------
 arch/riscv/kvm/main.c              |  2 +-
 arch/riscv/kvm/vcpu_fp.c           | 20 ++++++++---------
 arch/riscv/kvm/vcpu_onereg.c       |  6 +++---
 arch/riscv/kvm/vcpu_vector.c       | 10 ++++-----
 9 files changed, 62 insertions(+), 62 deletions(-)

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 7ef8e5f55c8dc..44bf8c7d8acc5 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -10,15 +10,15 @@
 
 #include <uapi/asm/hwcap.h>
 
-#define RISCV_ISA_EXT_a		('a' - 'a')
-#define RISCV_ISA_EXT_c		('c' - 'a')
-#define RISCV_ISA_EXT_d		('d' - 'a')
-#define RISCV_ISA_EXT_f		('f' - 'a')
-#define RISCV_ISA_EXT_h		('h' - 'a')
-#define RISCV_ISA_EXT_i		('i' - 'a')
-#define RISCV_ISA_EXT_m		('m' - 'a')
-#define RISCV_ISA_EXT_q		('q' - 'a')
-#define RISCV_ISA_EXT_v		('v' - 'a')
+#define RISCV_ISA_EXT_A		('a' - 'a')
+#define RISCV_ISA_EXT_C		('c' - 'a')
+#define RISCV_ISA_EXT_D		('d' - 'a')
+#define RISCV_ISA_EXT_F		('f' - 'a')
+#define RISCV_ISA_EXT_H		('h' - 'a')
+#define RISCV_ISA_EXT_I		('i' - 'a')
+#define RISCV_ISA_EXT_M		('m' - 'a')
+#define RISCV_ISA_EXT_Q		('q' - 'a')
+#define RISCV_ISA_EXT_V		('v' - 'a')
 
 /*
  * These macros represent the logical IDs of each multi-letter RISC-V ISA
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 0e71eb82f920c..ff35a4d04f85a 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -60,8 +60,8 @@ static inline void __switch_to_fpu(struct task_struct *prev,
 
 static __always_inline bool has_fpu(void)
 {
-	return riscv_has_extension_likely(RISCV_ISA_EXT_f) ||
-		riscv_has_extension_likely(RISCV_ISA_EXT_d);
+	return riscv_has_extension_likely(RISCV_ISA_EXT_F) ||
+		riscv_has_extension_likely(RISCV_ISA_EXT_D);
 }
 #else
 static __always_inline bool has_fpu(void) { return false; }
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index f46aa5602d74d..686dde3ce3b98 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
 static int riscv_ext_f_depends(const struct riscv_isa_ext_data *data,
 			       const unsigned long *isa_bitmap)
 {
-	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f))
+	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_F))
 		return 0;
 
 	return -EPROBE_DEFER;
@@ -146,7 +146,7 @@ static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data,
 	 * Due to extension ordering, d is checked before f, so no deferral
 	 * is required.
 	 */
-	if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d)) {
+	if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D)) {
 		pr_warn_once("This kernel does not support systems with F but not D\n");
 		return -EINVAL;
 	}
@@ -189,7 +189,7 @@ static int riscv_ext_vector_float_validate(const struct riscv_isa_ext_data *data
 	 * Since this function validates vector only, and v/Zve* are probed
 	 * after f/d, there's no need for a deferral here.
 	 */
-	if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d))
+	if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D))
 		return -EINVAL;
 
 	return 0;
@@ -224,7 +224,7 @@ static int riscv_ext_zcd_validate(const struct riscv_isa_ext_data *data,
 				  const unsigned long *isa_bitmap)
 {
 	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) &&
-	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d))
+	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D))
 		return 0;
 
 	return -EPROBE_DEFER;
@@ -237,7 +237,7 @@ static int riscv_ext_zcf_validate(const struct riscv_isa_ext_data *data,
 		return -EINVAL;
 
 	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) &&
-	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f))
+	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_F))
 		return 0;
 
 	return -EPROBE_DEFER;
@@ -490,15 +490,15 @@ static const unsigned int riscv_c_exts[] = {
  * New entries to this struct should follow the ordering rules described above.
  */
 const struct riscv_isa_ext_data riscv_isa_ext[] = {
-	__RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_i),
-	__RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_m),
-	__RISCV_ISA_EXT_SUPERSET(a, RISCV_ISA_EXT_a, riscv_a_exts),
-	__RISCV_ISA_EXT_DATA_VALIDATE(f, RISCV_ISA_EXT_f, riscv_ext_f_validate),
-	__RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_d, riscv_ext_d_validate),
-	__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
-	__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts),
-	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate),
-	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
+	__RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_I),
+	__RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_M),
+	__RISCV_ISA_EXT_SUPERSET(a, RISCV_ISA_EXT_A, riscv_a_exts),
+	__RISCV_ISA_EXT_DATA_VALIDATE(f, RISCV_ISA_EXT_F, riscv_ext_f_validate),
+	__RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_D, riscv_ext_d_validate),
+	__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_Q),
+	__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_C, riscv_c_exts),
+	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate),
+	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
@@ -897,7 +897,7 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
 		 * marchid.
 		 */
 		if (acpi_disabled && boot_vendorid == THEAD_VENDOR_ID && boot_archid == 0x0)
-			clear_bit(RISCV_ISA_EXT_v, source_isa);
+			clear_bit(RISCV_ISA_EXT_V, source_isa);
 
 		riscv_resolve_isa(source_isa, isainfo->isa, &this_hwcap, isa2hwcap);
 
@@ -1105,13 +1105,13 @@ void __init riscv_fill_hwcap(void)
 	unsigned long isa2hwcap[RISCV_ISA_EXT_BASE] = {0};
 	int i, j;
 
-	isa2hwcap[RISCV_ISA_EXT_i] = COMPAT_HWCAP_ISA_I;
-	isa2hwcap[RISCV_ISA_EXT_m] = COMPAT_HWCAP_ISA_M;
-	isa2hwcap[RISCV_ISA_EXT_a] = COMPAT_HWCAP_ISA_A;
-	isa2hwcap[RISCV_ISA_EXT_f] = COMPAT_HWCAP_ISA_F;
-	isa2hwcap[RISCV_ISA_EXT_d] = COMPAT_HWCAP_ISA_D;
-	isa2hwcap[RISCV_ISA_EXT_c] = COMPAT_HWCAP_ISA_C;
-	isa2hwcap[RISCV_ISA_EXT_v] = COMPAT_HWCAP_ISA_V;
+	isa2hwcap[RISCV_ISA_EXT_I] = COMPAT_HWCAP_ISA_I;
+	isa2hwcap[RISCV_ISA_EXT_M] = COMPAT_HWCAP_ISA_M;
+	isa2hwcap[RISCV_ISA_EXT_A] = COMPAT_HWCAP_ISA_A;
+	isa2hwcap[RISCV_ISA_EXT_F] = COMPAT_HWCAP_ISA_F;
+	isa2hwcap[RISCV_ISA_EXT_D] = COMPAT_HWCAP_ISA_D;
+	isa2hwcap[RISCV_ISA_EXT_C] = COMPAT_HWCAP_ISA_C;
+	isa2hwcap[RISCV_ISA_EXT_V] = COMPAT_HWCAP_ISA_V;
 
 	if (!acpi_disabled) {
 		riscv_fill_hwcap_from_isa_string(isa2hwcap);
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 1659d31fd288f..f8f68ba781b45 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -88,10 +88,10 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair,
 	if (has_fpu())
 		pair->value |= RISCV_HWPROBE_IMA_FD;
 
-	if (riscv_isa_extension_available(NULL, c))
+	if (riscv_isa_extension_available(NULL, C))
 		pair->value |= RISCV_HWPROBE_IMA_C;
 
-	if (has_vector() && riscv_isa_extension_available(NULL, v))
+	if (has_vector() && riscv_isa_extension_available(NULL, V))
 		pair->value |= RISCV_HWPROBE_IMA_V;
 
 	/*
diff --git a/arch/riscv/kvm/isa.c b/arch/riscv/kvm/isa.c
index 1132d909cc25c..94077117d1136 100644
--- a/arch/riscv/kvm/isa.c
+++ b/arch/riscv/kvm/isa.c
@@ -17,14 +17,14 @@
 /* Mapping between KVM ISA Extension ID & guest ISA extension ID */
 static const unsigned long kvm_isa_ext_arr[] = {
 	/* Single letter extensions (alphabetically sorted) */
-	[KVM_RISCV_ISA_EXT_A] = RISCV_ISA_EXT_a,
-	[KVM_RISCV_ISA_EXT_C] = RISCV_ISA_EXT_c,
-	[KVM_RISCV_ISA_EXT_D] = RISCV_ISA_EXT_d,
-	[KVM_RISCV_ISA_EXT_F] = RISCV_ISA_EXT_f,
-	[KVM_RISCV_ISA_EXT_H] = RISCV_ISA_EXT_h,
-	[KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i,
-	[KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m,
-	[KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v,
+	KVM_ISA_EXT_ARR(A),
+	KVM_ISA_EXT_ARR(C),
+	KVM_ISA_EXT_ARR(D),
+	KVM_ISA_EXT_ARR(F),
+	KVM_ISA_EXT_ARR(H),
+	KVM_ISA_EXT_ARR(I),
+	KVM_ISA_EXT_ARR(M),
+	KVM_ISA_EXT_ARR(V),
 	/* Multi letter extensions (alphabetically sorted) */
 	KVM_ISA_EXT_ARR(SMNPM),
 	KVM_ISA_EXT_ARR(SMSTATEEN),
diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c
index cb8a65273c1f0..70640701310c8 100644
--- a/arch/riscv/kvm/main.c
+++ b/arch/riscv/kvm/main.c
@@ -85,7 +85,7 @@ static int __init riscv_kvm_init(void)
 	char slist[64];
 	const char *str;
 
-	if (!riscv_isa_extension_available(NULL, h)) {
+	if (!riscv_isa_extension_available(NULL, H)) {
 		kvm_info("hypervisor extension not available\n");
 		return -ENODEV;
 	}
diff --git a/arch/riscv/kvm/vcpu_fp.c b/arch/riscv/kvm/vcpu_fp.c
index 6ad6df26a2fd4..bb11e6757d349 100644
--- a/arch/riscv/kvm/vcpu_fp.c
+++ b/arch/riscv/kvm/vcpu_fp.c
@@ -21,8 +21,8 @@ void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu)
 	struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
 
 	cntx->sstatus &= ~SR_FS;
-	if (riscv_isa_extension_available(vcpu->arch.isa, f) ||
-	    riscv_isa_extension_available(vcpu->arch.isa, d))
+	if (riscv_isa_extension_available(vcpu->arch.isa, F) ||
+	    riscv_isa_extension_available(vcpu->arch.isa, D))
 		cntx->sstatus |= SR_FS_INITIAL;
 	else
 		cntx->sstatus |= SR_FS_OFF;
@@ -38,9 +38,9 @@ void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx,
 				  const unsigned long *isa)
 {
 	if ((cntx->sstatus & SR_FS) == SR_FS_DIRTY) {
-		if (riscv_isa_extension_available(isa, d))
+		if (riscv_isa_extension_available(isa, D))
 			__kvm_riscv_fp_d_save(cntx);
-		else if (riscv_isa_extension_available(isa, f))
+		else if (riscv_isa_extension_available(isa, F))
 			__kvm_riscv_fp_f_save(cntx);
 		kvm_riscv_vcpu_fp_clean(cntx);
 	}
@@ -50,9 +50,9 @@ void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx,
 				     const unsigned long *isa)
 {
 	if ((cntx->sstatus & SR_FS) != SR_FS_OFF) {
-		if (riscv_isa_extension_available(isa, d))
+		if (riscv_isa_extension_available(isa, D))
 			__kvm_riscv_fp_d_restore(cntx);
-		else if (riscv_isa_extension_available(isa, f))
+		else if (riscv_isa_extension_available(isa, F))
 			__kvm_riscv_fp_f_restore(cntx);
 		kvm_riscv_vcpu_fp_clean(cntx);
 	}
@@ -89,7 +89,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu,
 	void *reg_val;
 
 	if ((rtype == KVM_REG_RISCV_FP_F) &&
-	    riscv_isa_extension_available(vcpu->arch.isa, f)) {
+	    riscv_isa_extension_available(vcpu->arch.isa, F)) {
 		if (KVM_REG_SIZE(reg->id) != sizeof(u32))
 			return -EINVAL;
 		if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr))
@@ -102,7 +102,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu,
 		} else
 			return -ENOENT;
 	} else if ((rtype == KVM_REG_RISCV_FP_D) &&
-		   riscv_isa_extension_available(vcpu->arch.isa, d)) {
+		   riscv_isa_extension_available(vcpu->arch.isa, D)) {
 		if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) {
 			if (KVM_REG_SIZE(reg->id) != sizeof(u32))
 				return -EINVAL;
@@ -138,7 +138,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu,
 	void *reg_val;
 
 	if ((rtype == KVM_REG_RISCV_FP_F) &&
-	    riscv_isa_extension_available(vcpu->arch.isa, f)) {
+	    riscv_isa_extension_available(vcpu->arch.isa, F)) {
 		if (KVM_REG_SIZE(reg->id) != sizeof(u32))
 			return -EINVAL;
 		if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr))
@@ -151,7 +151,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu,
 		} else
 			return -ENOENT;
 	} else if ((rtype == KVM_REG_RISCV_FP_D) &&
-		   riscv_isa_extension_available(vcpu->arch.isa, d)) {
+		   riscv_isa_extension_available(vcpu->arch.isa, D)) {
 		if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) {
 			if (KVM_REG_SIZE(reg->id) != sizeof(u32))
 				return -EINVAL;
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index bb920e8923c93..5cc7ddd4aa276 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -770,7 +770,7 @@ static inline unsigned long num_fp_f_regs(const struct kvm_vcpu *vcpu)
 {
 	const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
 
-	if (riscv_isa_extension_available(vcpu->arch.isa, f))
+	if (riscv_isa_extension_available(vcpu->arch.isa, F))
 		return sizeof(cntx->fp.f) / sizeof(u32);
 	else
 		return 0;
@@ -799,7 +799,7 @@ static inline unsigned long num_fp_d_regs(const struct kvm_vcpu *vcpu)
 {
 	const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
 
-	if (riscv_isa_extension_available(vcpu->arch.isa, d))
+	if (riscv_isa_extension_available(vcpu->arch.isa, D))
 		return sizeof(cntx->fp.d.f) / sizeof(u64) + 1;
 	else
 		return 0;
@@ -878,7 +878,7 @@ static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu)
 
 static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu)
 {
-	if (!riscv_isa_extension_available(vcpu->arch.isa, v))
+	if (!riscv_isa_extension_available(vcpu->arch.isa, V))
 		return 0;
 
 	/* vstart, vl, vtype, vcsr, vlenb and 32 vector regs */
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index 62d2fb77bb9b9..f26108a4e601e 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -26,7 +26,7 @@ void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu)
 
 	cntx->vector.vlenb = riscv_v_vsize / 32;
 
-	if (riscv_isa_extension_available(isa, v)) {
+	if (riscv_isa_extension_available(isa, V)) {
 		cntx->sstatus |= SR_VS_INITIAL;
 		WARN_ON(!cntx->vector.datap);
 		memset(cntx->vector.datap, 0, riscv_v_vsize);
@@ -45,7 +45,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
 				      unsigned long *isa)
 {
 	if ((cntx->sstatus & SR_VS) == SR_VS_DIRTY) {
-		if (riscv_isa_extension_available(isa, v))
+		if (riscv_isa_extension_available(isa, V))
 			__kvm_riscv_vector_save(cntx);
 		kvm_riscv_vcpu_vector_clean(cntx);
 	}
@@ -55,7 +55,7 @@ void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
 					 unsigned long *isa)
 {
 	if ((cntx->sstatus & SR_VS) != SR_VS_OFF) {
-		if (riscv_isa_extension_available(isa, v))
+		if (riscv_isa_extension_available(isa, V))
 			__kvm_riscv_vector_restore(cntx);
 		kvm_riscv_vcpu_vector_clean(cntx);
 	}
@@ -154,7 +154,7 @@ int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu,
 	void *reg_addr;
 	int rc;
 
-	if (!riscv_isa_extension_available(isa, v))
+	if (!riscv_isa_extension_available(isa, V))
 		return -ENOENT;
 
 	rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, &reg_addr);
@@ -180,7 +180,7 @@ int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu,
 	void *reg_addr;
 	int rc;
 
-	if (!riscv_isa_extension_available(isa, v))
+	if (!riscv_isa_extension_available(isa, V))
 		return -ENOENT;
 
 	if (reg_num == KVM_REG_RISCV_VECTOR_CSR_REG(vlenb)) {

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:11:59 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:11:59 -0400
Subject: [PATCH v3 04/15] riscv: Add Zicclsm to cpufeature and hwprobe
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-4-5529a7b28384@gmail.com>

From: Jesse Taube <jesse at rivosinc.com>

Zicclsm requires misaligned support for all regular load and store
instructions, both scalar and vector, but not AMOs or other
specialized forms of memory access, to main memory regions with both
the cacheability and coherence PMAs, as defined in the profiles spec.
Even though mandated, misaligned loads and stores might execute
extremely slowly. Standard software distributions should assume their
existence only for correctness, not for performance.

Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
Reviewed-by: Andy Chiu <andy.chiu at sifive.com>
Reviewed-by: Charlie Jenkins <charlie at rivosinc.com>
Tested-by: Charlie Jenkins <charlie at rivosinc.com>
Signed-off-by: Jesse Taube <jesse at rivosinc.com>
[Rebased, rewrote doc text, minor commit message revisions]
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>

---
v3:
- Move the hwprobe.rst entry to the IMA_EXT_1 section so its
  documentation matches the IMA_EXT_1 bit it was allocated in v2
  (Sashiko, agreed by Andrew).
v2:
- Rebased onto v7.1-rc2; moved ZICCLSM to IMA_EXT_1 and
  allocated a new bit for it
---
 Documentation/arch/riscv/hwprobe.rst  | 4 ++++
 arch/riscv/include/asm/hwcap.h        | 1 +
 arch/riscv/include/uapi/asm/hwprobe.h | 1 +
 arch/riscv/kernel/cpufeature.c        | 1 +
 arch/riscv/kernel/sys_hwprobe.c       | 1 +
 5 files changed, 8 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index 3cedaaa53f331..fa2810bfc1477 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -401,3 +401,7 @@ The following keys are defined:
     as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
     extensions specification, ratified in commit ff03d8485a04 ("Update to
     ratified state") of riscv-cfi.
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICCLSM`: The Zicclsm extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 44bf8c7d8acc5..e8f4a7dd96a93 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -112,6 +112,7 @@
 #define RISCV_ISA_EXT_ZCLSD		103
 #define RISCV_ISA_EXT_ZICFILP		104
 #define RISCV_ISA_EXT_ZICFISS		105
+#define RISCV_ISA_EXT_ZICCLSM		106
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 9139edba0aecb..6819df159c51e 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -116,6 +116,7 @@ struct riscv_hwprobe {
 #define RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE	15
 #define RISCV_HWPROBE_KEY_IMA_EXT_1		16
 #define		RISCV_HWPROBE_EXT_ZICFISS	(1ULL << 0)
+#define		RISCV_HWPROBE_EXT_ZICCLSM	(1ULL << 1)
 
 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 686dde3ce3b98..1fb595581adcf 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -502,6 +502,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
+	__RISCV_ISA_EXT_DATA(zicclsm, RISCV_ISA_EXT_ZICCLSM),
 	__RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicfilp, RISCV_ISA_EXT_ZICFILP, riscv_xlinuxenvcfg_exts,
 					  riscv_cfilp_validate),
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index f8f68ba781b45..9cf62266f1890 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -205,6 +205,7 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
 		 * in the hart_isa bitmap, are made.
 		 */
 		EXT_KEY(isainfo->isa, ZICFISS, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZICCLSM, pair->value, missing);
 	}
 
 	/* Now turn off reporting features if any CPU is missing it. */

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:00 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:00 -0400
Subject: [PATCH v3 05/15] riscv: Add Ziccamoa, Ziccif, Ziccrse, and Za64rs
 to cpufeature and hwprobe
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-5-5529a7b28384@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

Add Ziccamoa, Ziccif, and Za64rs to riscv_isa_ext[] so they can be
parsed from devicetree/ACPI ISA strings. Ziccrse is already present
in cpufeature; this patch only adds its hwprobe exposure.

Expose all four extensions via hwprobe through new bits in
RISCV_HWPROBE_KEY_IMA_EXT_1 (RISCV_HWPROBE_EXT_ZICCAMOA, _ZICCIF,
_ZICCRSE, _ZA64RS), so userspace can probe each of these
RVA23U64-mandatory extensions individually.

Rationale for the validation dependencies added for Ziccamoa and Za64rs:

1) Ziccamoa depends on Zaamo.  The RVA23 profile prose was updated
post-ratification to spell out the Zaamo reference: commit
2b218613752d in riscv/riscv-profiles ("Improve description of
Ziccamoa (#224)") reworded the rva23-profile.adoc (and other profiles
that include Ziccamoa) text from "must support all atomics in A" to
"must support all atomics in the Zaamo extension" [1].

2) Za64rs depends on Zalrsc. The unprivileged ISA manual src/zars.adoc,
integrated in commit ebe06adc22cd ("Integrate profiles as Volume III
(#2771)"), defines Za64rs as: "The Za64rs extension requires that the
reservation sets used by the instructions in the Zalrsc extension be
contiguous, naturally aligned, and at most 64 bytes in size" [2].

Link: https://github.com/riscv/riscv-profiles/commit/2b218613752d63287286b5ae801b820cbd8cc10c [1]
Link: https://github.com/riscv/riscv-isa-manual/blob/main/src/unpriv/zars.adoc [2]
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: Indent the added hwprobe.rst entries to match the normalized style; no other change.
v2:
- Rebased to v7.1-rc2.
- Reworded subject and expanded commit message.
- Validation added for Ziccamoa depending on Zaamo and Za64rs depending
  on Zalrsc.
---
 Documentation/arch/riscv/hwprobe.rst  | 16 ++++++++++++++++
 arch/riscv/include/asm/hwcap.h        |  3 +++
 arch/riscv/include/uapi/asm/hwprobe.h |  4 ++++
 arch/riscv/kernel/cpufeature.c        | 21 +++++++++++++++++++++
 arch/riscv/kernel/sys_hwprobe.c       |  4 ++++
 5 files changed, 48 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index fa2810bfc1477..b1b2d8803e5c2 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -405,3 +405,19 @@ The following keys are defined:
   * :c:macro:`RISCV_HWPROBE_EXT_ZICCLSM`: The Zicclsm extension is supported,
     as defined in the RISC-V Profiles specification starting from commit
     b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICCAMOA`: The Ziccamoa extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICCIF`: The Ziccif extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICCRSE`: The Ziccrse extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZA64RS`: The Za64rs extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index e8f4a7dd96a93..0acb7a01ecc0f 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -113,6 +113,9 @@
 #define RISCV_ISA_EXT_ZICFILP		104
 #define RISCV_ISA_EXT_ZICFISS		105
 #define RISCV_ISA_EXT_ZICCLSM		106
+#define RISCV_ISA_EXT_ZICCAMOA		107
+#define RISCV_ISA_EXT_ZICCIF		108
+#define RISCV_ISA_EXT_ZA64RS		109
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 6819df159c51e..58d1e86e47ae7 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -117,6 +117,10 @@ struct riscv_hwprobe {
 #define RISCV_HWPROBE_KEY_IMA_EXT_1		16
 #define		RISCV_HWPROBE_EXT_ZICFISS	(1ULL << 0)
 #define		RISCV_HWPROBE_EXT_ZICCLSM	(1ULL << 1)
+#define		RISCV_HWPROBE_EXT_ZICCAMOA	(1ULL << 2)
+#define		RISCV_HWPROBE_EXT_ZICCIF	(1ULL << 3)
+#define		RISCV_HWPROBE_EXT_ZICCRSE	(1ULL << 4)
+#define		RISCV_HWPROBE_EXT_ZA64RS	(1ULL << 5)
 
 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 1fb595581adcf..b9538e69fa1b3 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -90,6 +90,24 @@ static int riscv_ext_f_depends(const struct riscv_isa_ext_data *data,
 	return -EPROBE_DEFER;
 }
 
+static int riscv_ext_zaamo_depends(const struct riscv_isa_ext_data *data,
+				   const unsigned long *isa_bitmap)
+{
+	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZAAMO))
+		return 0;
+
+	return -EPROBE_DEFER;
+}
+
+static int riscv_ext_zalrsc_depends(const struct riscv_isa_ext_data *data,
+				    const unsigned long *isa_bitmap)
+{
+	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZALRSC))
+		return 0;
+
+	return -EPROBE_DEFER;
+}
+
 static int riscv_ext_zicbom_validate(const struct riscv_isa_ext_data *data,
 				     const unsigned long *isa_bitmap)
 {
@@ -502,6 +520,8 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
+	__RISCV_ISA_EXT_DATA_VALIDATE(ziccamoa, RISCV_ISA_EXT_ZICCAMOA, riscv_ext_zaamo_depends),
+	__RISCV_ISA_EXT_DATA(ziccif, RISCV_ISA_EXT_ZICCIF),
 	__RISCV_ISA_EXT_DATA(zicclsm, RISCV_ISA_EXT_ZICCLSM),
 	__RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicfilp, RISCV_ISA_EXT_ZICFILP, riscv_xlinuxenvcfg_exts,
@@ -516,6 +536,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
 	__RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM),
 	__RISCV_ISA_EXT_DATA(zimop, RISCV_ISA_EXT_ZIMOP),
+	__RISCV_ISA_EXT_DATA_VALIDATE(za64rs, RISCV_ISA_EXT_ZA64RS, riscv_ext_zalrsc_depends),
 	__RISCV_ISA_EXT_DATA(zaamo, RISCV_ISA_EXT_ZAAMO),
 	__RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA),
 	__RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 9cf62266f1890..b15ac9adf7920 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -206,6 +206,10 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
 		 */
 		EXT_KEY(isainfo->isa, ZICFISS, pair->value, missing);
 		EXT_KEY(isainfo->isa, ZICCLSM, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZICCAMOA, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZICCIF, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZICCRSE, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZA64RS, pair->value, missing);
 	}
 
 	/* Now turn off reporting features if any CPU is missing it. */

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:01 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:01 -0400
Subject: [PATCH v3 06/15] riscv: Add B to hwcap and hwprobe
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-6-5529a7b28384@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

Add B to hwcap and ensure when B is present that Zba, Zbb, and Zbs
are all set. Also expose B via hwprobe (RISCV_HWPROBE_EXT_B in
RISCV_HWPROBE_KEY_IMA_EXT_1) so that userspace can probe B directly,
mirroring the F/D/C/V pattern where each is reported via both hwcap
and hwprobe.

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
[Add B to hwprobe]
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3:
- Indent the added hwprobe.rst entry to match the normalized style.
- Rebased onto v7.1-rc6: index isa2hwcap[] via RISCV_ISA_EXT_B to match the
  macro-ization in commit 41337097f2823.
v2:
- Rebased to v7.1-rc2
- Add B to hwprobe (RISCV_HWPROBE_EXT_B at IMA_EXT_1 bit 6) and
  document it in hwprobe.rst, so userspace can probe B directly.
---
 Documentation/arch/riscv/hwprobe.rst  | 4 ++++
 arch/riscv/include/asm/hwcap.h        | 1 +
 arch/riscv/include/uapi/asm/hwcap.h   | 1 +
 arch/riscv/include/uapi/asm/hwprobe.h | 1 +
 arch/riscv/kernel/cpufeature.c        | 8 ++++++++
 arch/riscv/kernel/sys_hwprobe.c       | 1 +
 6 files changed, 16 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index b1b2d8803e5c2..002d5046ab689 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -421,3 +421,7 @@ The following keys are defined:
   * :c:macro:`RISCV_HWPROBE_EXT_ZA64RS`: The Za64rs extension is supported,
     as defined in the RISC-V Profiles specification starting from commit
     b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_B`: The B extension is supported, as defined
+    in version 1.0 of the Bit-Manipulation ISA extensions, and implies the
+    presence of the Zba, Zbb, and Zbs sub-extensions.
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 0acb7a01ecc0f..58523b3a1998a 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -11,6 +11,7 @@
 #include <uapi/asm/hwcap.h>
 
 #define RISCV_ISA_EXT_A		('a' - 'a')
+#define RISCV_ISA_EXT_B		('b' - 'a')
 #define RISCV_ISA_EXT_C		('c' - 'a')
 #define RISCV_ISA_EXT_D		('d' - 'a')
 #define RISCV_ISA_EXT_F		('f' - 'a')
diff --git a/arch/riscv/include/uapi/asm/hwcap.h b/arch/riscv/include/uapi/asm/hwcap.h
index c52bb7bbbabe9..96b7cf854e090 100644
--- a/arch/riscv/include/uapi/asm/hwcap.h
+++ b/arch/riscv/include/uapi/asm/hwcap.h
@@ -21,6 +21,7 @@
 #define COMPAT_HWCAP_ISA_F	(1 << ('F' - 'A'))
 #define COMPAT_HWCAP_ISA_D	(1 << ('D' - 'A'))
 #define COMPAT_HWCAP_ISA_C	(1 << ('C' - 'A'))
+#define COMPAT_HWCAP_ISA_B	(1 << ('B' - 'A'))
 #define COMPAT_HWCAP_ISA_V	(1 << ('V' - 'A'))
 
 #endif /* _UAPI_ASM_RISCV_HWCAP_H */
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 58d1e86e47ae7..430dc49a82863 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -121,6 +121,7 @@ struct riscv_hwprobe {
 #define		RISCV_HWPROBE_EXT_ZICCIF	(1ULL << 3)
 #define		RISCV_HWPROBE_EXT_ZICCRSE	(1ULL << 4)
 #define		RISCV_HWPROBE_EXT_ZA64RS	(1ULL << 5)
+#define		RISCV_HWPROBE_EXT_B		(1ULL << 6)
 
 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index b9538e69fa1b3..e0197160af6dd 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -468,6 +468,12 @@ static const unsigned int riscv_c_exts[] = {
 	RISCV_ISA_EXT_ZCD,
 };
 
+static const unsigned int riscv_b_exts[] = {
+	RISCV_ISA_EXT_ZBA,
+	RISCV_ISA_EXT_ZBB,
+	RISCV_ISA_EXT_ZBS,
+};
+
 /*
  * The canonical order of ISA extension names in the ISA string is defined in
  * chapter 27 of the unprivileged specification.
@@ -515,6 +521,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_D, riscv_ext_d_validate),
 	__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_Q),
 	__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_C, riscv_c_exts),
+	__RISCV_ISA_EXT_SUPERSET(b, RISCV_ISA_EXT_B, riscv_b_exts),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate),
 	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
@@ -1133,6 +1140,7 @@ void __init riscv_fill_hwcap(void)
 	isa2hwcap[RISCV_ISA_EXT_F] = COMPAT_HWCAP_ISA_F;
 	isa2hwcap[RISCV_ISA_EXT_D] = COMPAT_HWCAP_ISA_D;
 	isa2hwcap[RISCV_ISA_EXT_C] = COMPAT_HWCAP_ISA_C;
+	isa2hwcap[RISCV_ISA_EXT_B] = COMPAT_HWCAP_ISA_B;
 	isa2hwcap[RISCV_ISA_EXT_V] = COMPAT_HWCAP_ISA_V;
 
 	if (!acpi_disabled) {
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index b15ac9adf7920..dcc102bf8f183 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -210,6 +210,7 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
 		EXT_KEY(isainfo->isa, ZICCIF, pair->value, missing);
 		EXT_KEY(isainfo->isa, ZICCRSE, pair->value, missing);
 		EXT_KEY(isainfo->isa, ZA64RS, pair->value, missing);
+		EXT_KEY(isainfo->isa, B, pair->value, missing);
 	}
 
 	/* Now turn off reporting features if any CPU is missing it. */

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:02 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:02 -0400
Subject: [PATCH v3 07/15] dt-bindings: riscv: Add Zic64b extension
 description
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-7-5529a7b28384@gmail.com>

Zic64b mandates that cache blocks are 64 bytes in size and naturally
aligned in the address space.  It is a mandatory extension of both the
RVA22 (U64/S64) and RVA23 (U64/S64) profiles, ratified with RISC-V
Profiles Version 1.0.

Document it so it can be described in the riscv,isa-extensions property,
alongside the related Zicbom/Zicbop/Zicboz cache-block extensions.  As
Zic64b is the architectural guarantee that the cache block size is 64
bytes, also require a hart that advertises it to report cbom/cbop/cboz
block sizes of 64, so dtbs_check rejects an inconsistent description.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: New patch.
---
 .../devicetree/bindings/riscv/extensions.yaml        | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb214..ec1c9473d4256 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -590,6 +590,12 @@ properties:
             in version 1.0 of RISC-V Cryptography Extensions Volume I
             specification.
 
+        - const: zic64b
+          description:
+            The standard Zic64b extension for 64-byte naturally aligned cache
+            blocks, as ratified in RISC-V Profiles Version 1.0, with commit
+            b1d806605f87 ("Updated to ratified state.")
+
         - const: zicbom
           description:
             The standard Zicbom extension for base cache management operations as
@@ -1142,6 +1148,20 @@ allOf:
           not:
             contains:
               const: zilsd
+  # Zic64b mandates 64-byte naturally aligned cache blocks
+  - if:
+      properties:
+        riscv,isa-extensions:
+          contains:
+            const: zic64b
+    then:
+      properties:
+        riscv,cbom-block-size:
+          const: 64
+        riscv,cbop-block-size:
+          const: 64
+        riscv,cboz-block-size:
+          const: 64
 
 additionalProperties: true
 ...

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:03 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:03 -0400
Subject: [PATCH v3 08/15] riscv: Add Zic64b to cpufeature and hwprobe
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-8-5529a7b28384@gmail.com>

Zic64b mandates 64-byte naturally aligned cache blocks and is a
mandatory extension of the RVA22 and RVA23 profiles.  Allocate a
RISCV_ISA_EXT_ZIC64B id, parse "zic64b" from the ISA string with a
validate callback that requires cbom/cbop/cboz cache block sizes of 64
bytes, and export it through hwprobe.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: New patch.
---
 Documentation/arch/riscv/hwprobe.rst  |  3 +++
 arch/riscv/include/asm/hwcap.h        |  1 +
 arch/riscv/include/uapi/asm/hwprobe.h |  1 +
 arch/riscv/kernel/cpufeature.c        | 18 ++++++++++++++++++
 arch/riscv/kernel/sys_hwprobe.c       |  1 +
 5 files changed, 24 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index 002d5046ab689..601e81f561421 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -425,3 +425,6 @@ The following keys are defined:
   * :c:macro:`RISCV_HWPROBE_EXT_B`: The B extension is supported, as defined
     in version 1.0 of the Bit-Manipulation ISA extensions, and implies the
     presence of the Zba, Zbb, and Zbs sub-extensions.
+  * :c:macro:`RISCV_HWPROBE_EXT_ZIC64B`: The Zic64b extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 58523b3a1998a..36572c1ff438a 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -117,6 +117,7 @@
 #define RISCV_ISA_EXT_ZICCAMOA		107
 #define RISCV_ISA_EXT_ZICCIF		108
 #define RISCV_ISA_EXT_ZA64RS		109
+#define RISCV_ISA_EXT_ZIC64B		110
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 430dc49a82863..36ec8ab470423 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -122,6 +122,7 @@ struct riscv_hwprobe {
 #define		RISCV_HWPROBE_EXT_ZICCRSE	(1ULL << 4)
 #define		RISCV_HWPROBE_EXT_ZA64RS	(1ULL << 5)
 #define		RISCV_HWPROBE_EXT_B		(1ULL << 6)
+#define		RISCV_HWPROBE_EXT_ZIC64B	(1ULL << 7)
 
 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index e0197160af6dd..79ff431768139 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -154,6 +154,23 @@ static int riscv_ext_zicbop_validate(const struct riscv_isa_ext_data *data,
 	return 0;
 }
 
+static int riscv_ext_zic64b_validate(const struct riscv_isa_ext_data *data,
+				     const unsigned long *isa_bitmap)
+{
+	/*
+	 * Zic64b mandates 64-byte naturally aligned cache blocks; cross-check the
+	 * cbom/cbop/cboz block-size device-tree properties to avoid inconsistency.
+	 */
+	if (riscv_cbom_block_size != 64 ||
+	    riscv_cbop_block_size != 64 ||
+	    riscv_cboz_block_size != 64) {
+		pr_err("Zic64b detected in ISA string, disabling as the cache block size is not 64 bytes\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data,
 				const unsigned long *isa_bitmap)
 {
@@ -524,6 +541,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_SUPERSET(b, RISCV_ISA_EXT_B, riscv_b_exts),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate),
 	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H),
+	__RISCV_ISA_EXT_DATA_VALIDATE(zic64b, RISCV_ISA_EXT_ZIC64B, riscv_ext_zic64b_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index dcc102bf8f183..3e80e5551ae0d 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -211,6 +211,7 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
 		EXT_KEY(isainfo->isa, ZICCRSE, pair->value, missing);
 		EXT_KEY(isainfo->isa, ZA64RS, pair->value, missing);
 		EXT_KEY(isainfo->isa, B, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZIC64B, pair->value, missing);
 	}
 
 	/* Now turn off reporting features if any CPU is missing it. */

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:04 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:04 -0400
Subject: [PATCH v3 09/15] riscv: dts: spacemit: k3: Add Zic64b ISA
 extension
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-9-5529a7b28384@gmail.com>

The K3 X100 cores have 64-byte cache blocks, already described by their
cbom/cbop/cboz-block-size of 64, so they implement Zic64b, a mandatory
RVA23 extension.  Declare it in each core's riscv,isa-extensions.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: New patch.
---
 arch/riscv/boot/dts/spacemit/k3.dtsi | 48 ++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/riscv/boot/dts/spacemit/k3.dtsi b/arch/riscv/boot/dts/spacemit/k3.dtsi
index 4ac457399b583..b5aa983f0bfa1 100644
--- a/arch/riscv/boot/dts/spacemit/k3.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3.dtsi
@@ -35,9 +35,9 @@ cpu_0: cpu at 0 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -76,9 +76,9 @@ cpu_1: cpu at 1 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -117,9 +117,9 @@ cpu_2: cpu at 2 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -158,9 +158,9 @@ cpu_3: cpu at 3 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -199,9 +199,9 @@ cpu_4: cpu at 4 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -240,9 +240,9 @@ cpu_5: cpu at 5 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -281,9 +281,9 @@ cpu_6: cpu at 6 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -322,9 +322,9 @@ cpu_7: cpu at 7 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:05 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:05 -0400
Subject: [PATCH v3 10/15] riscv: dts: spacemit: k1: Add Zic64b ISA
 extension
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-10-5529a7b28384@gmail.com>

The K1 X60 cores have 64-byte cache blocks, described by their
cbom/cbop/cboz-block-size of 64, so they implement Zic64b.  Declare it in
each core's riscv,isa-extensions and in the deprecated riscv,isa string.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: New patch.
---
 arch/riscv/boot/dts/spacemit/k1.dtsi | 80 ++++++++++++++++++------------------
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index f0bad6855c970..e6fc684ad3898 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -54,12 +54,12 @@ cpu_0: cpu at 0 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <0>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -84,12 +84,12 @@ cpu_1: cpu at 1 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <1>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -114,12 +114,12 @@ cpu_2: cpu at 2 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <2>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -144,12 +144,12 @@ cpu_3: cpu at 3 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <3>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -174,12 +174,12 @@ cpu_4: cpu at 4 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <4>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -204,12 +204,12 @@ cpu_5: cpu at 5 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <5>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -234,12 +234,12 @@ cpu_6: cpu at 6 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <6>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -264,12 +264,12 @@ cpu_7: cpu at 7 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <7>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:06 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:06 -0400
Subject: [PATCH v3 11/15] riscv: dts: sophgo: sg2044: Add Zic64b ISA
 extension
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-11-5529a7b28384@gmail.com>

The SG2044 cores have 64-byte cache blocks, described by their
cbom/cbop/cboz-block-size of 64, so they implement Zic64b.  Declare it in
each core's riscv,isa-extensions.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: New patch.
---
 arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi | 128 ++++++++++++++--------------
 1 file changed, 64 insertions(+), 64 deletions(-)

diff --git a/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi b/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
index 3135409c21492..2ac4a41bbc3a7 100644
--- a/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
+++ b/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
@@ -31,7 +31,7 @@ cpu0: cpu at 0 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -67,7 +67,7 @@ cpu1: cpu at 1 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -103,7 +103,7 @@ cpu2: cpu at 2 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -139,7 +139,7 @@ cpu3: cpu at 3 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -175,7 +175,7 @@ cpu4: cpu at 4 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -211,7 +211,7 @@ cpu5: cpu at 5 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -247,7 +247,7 @@ cpu6: cpu at 6 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -283,7 +283,7 @@ cpu7: cpu at 7 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -319,7 +319,7 @@ cpu8: cpu at 8 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -355,7 +355,7 @@ cpu9: cpu at 9 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -391,7 +391,7 @@ cpu10: cpu at 10 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -427,7 +427,7 @@ cpu11: cpu at 11 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -463,7 +463,7 @@ cpu12: cpu at 12 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -499,7 +499,7 @@ cpu13: cpu at 13 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -535,7 +535,7 @@ cpu14: cpu at 14 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -571,7 +571,7 @@ cpu15: cpu at 15 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -607,7 +607,7 @@ cpu16: cpu at 16 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -643,7 +643,7 @@ cpu17: cpu at 17 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -679,7 +679,7 @@ cpu18: cpu at 18 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -715,7 +715,7 @@ cpu19: cpu at 19 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -751,7 +751,7 @@ cpu20: cpu at 20 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -787,7 +787,7 @@ cpu21: cpu at 21 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -823,7 +823,7 @@ cpu22: cpu at 22 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -859,7 +859,7 @@ cpu23: cpu at 23 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -895,7 +895,7 @@ cpu24: cpu at 24 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -931,7 +931,7 @@ cpu25: cpu at 25 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -967,7 +967,7 @@ cpu26: cpu at 26 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1003,7 +1003,7 @@ cpu27: cpu at 27 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1039,7 +1039,7 @@ cpu28: cpu at 28 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1075,7 +1075,7 @@ cpu29: cpu at 29 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1111,7 +1111,7 @@ cpu30: cpu at 30 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1147,7 +1147,7 @@ cpu31: cpu at 31 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1183,7 +1183,7 @@ cpu32: cpu at 32 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1219,7 +1219,7 @@ cpu33: cpu at 33 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1255,7 +1255,7 @@ cpu34: cpu at 34 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1291,7 +1291,7 @@ cpu35: cpu at 35 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1327,7 +1327,7 @@ cpu36: cpu at 36 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1363,7 +1363,7 @@ cpu37: cpu at 37 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1399,7 +1399,7 @@ cpu38: cpu at 38 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1435,7 +1435,7 @@ cpu39: cpu at 39 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1471,7 +1471,7 @@ cpu40: cpu at 40 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1507,7 +1507,7 @@ cpu41: cpu at 41 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1543,7 +1543,7 @@ cpu42: cpu at 42 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1579,7 +1579,7 @@ cpu43: cpu at 43 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1615,7 +1615,7 @@ cpu44: cpu at 44 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1651,7 +1651,7 @@ cpu45: cpu at 45 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1687,7 +1687,7 @@ cpu46: cpu at 46 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1723,7 +1723,7 @@ cpu47: cpu at 47 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1759,7 +1759,7 @@ cpu48: cpu at 48 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1795,7 +1795,7 @@ cpu49: cpu at 49 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1831,7 +1831,7 @@ cpu50: cpu at 50 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1867,7 +1867,7 @@ cpu51: cpu at 51 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1903,7 +1903,7 @@ cpu52: cpu at 52 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1939,7 +1939,7 @@ cpu53: cpu at 53 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1975,7 +1975,7 @@ cpu54: cpu at 54 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2011,7 +2011,7 @@ cpu55: cpu at 55 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2047,7 +2047,7 @@ cpu56: cpu at 56 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2083,7 +2083,7 @@ cpu57: cpu at 57 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2119,7 +2119,7 @@ cpu58: cpu at 58 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2155,7 +2155,7 @@ cpu59: cpu at 59 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2191,7 +2191,7 @@ cpu60: cpu at 60 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2227,7 +2227,7 @@ cpu61: cpu at 61 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2263,7 +2263,7 @@ cpu62: cpu at 62 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2299,7 +2299,7 @@ cpu63: cpu at 63 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:07 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:07 -0400
Subject: [PATCH v3 12/15] riscv: Add a getter for user PMLEN support
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-12-5529a7b28384@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

Querying whether a given user PMLEN is supported is needed for
RVA23U64 base detection from outside arch/riscv/kernel/process.c.
Add riscv_have_user_pmlen() to expose this.

Link: https://lore.kernel.org/linux-riscv/rfuwa7a3ebe76udmnwyrssjy7shkkgxntvhwzn6oquysj4tuyp at xzvpylcfhz53/
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
[Guodong: replace exported booleans with getter per Andrew's suggestion]
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: No change.
v2: Add a getter for user PMLEN.
---
 arch/riscv/include/asm/processor.h |  4 ++++
 arch/riscv/kernel/process.c        | 12 ++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 812517b2cec13..febf51e127f70 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -214,6 +214,10 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg);
 long get_tagged_addr_ctrl(struct task_struct *task);
 #define SET_TAGGED_ADDR_CTRL(arg)	set_tagged_addr_ctrl(current, arg)
 #define GET_TAGGED_ADDR_CTRL()		get_tagged_addr_ctrl(current)
+
+bool riscv_have_user_pmlen(u8 len);
+#else
+static inline bool riscv_have_user_pmlen(u8 len) { return false; }
 #endif
 
 #endif /* __ASSEMBLER__ */
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index b2df7f72241a5..5d9cb108a6232 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -302,6 +302,18 @@ enum {
 static bool have_user_pmlen_7;
 static bool have_user_pmlen_16;
 
+bool riscv_have_user_pmlen(u8 len)
+{
+	switch (len) {
+	case PMLEN_7:
+		return have_user_pmlen_7;
+	case PMLEN_16:
+		return have_user_pmlen_16;
+	default:
+		return false;
+	}
+}
+
 /*
  * Control the relaxed ABI allowing tagged user addresses into the kernel.
  */

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:08 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:08 -0400
Subject: [PATCH v3 13/15] riscv: cpufeature: Introduce ISA bases bitmap and
 rva23u64 detection
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-13-5529a7b28384@gmail.com>

Introduce a per-hart and host-wide bitmap of conformant ISA "bases"
(named profile-class sets such as IMA and RVA23U64), computed at init
time by riscv_init_isa_bases().

Register riscv_init_isa_bases() as a subsys_initcall so it executes
after core_initcall(tagged_addr_init), which probes senvcfg.PMM and
populates have_user_pmlen_*.  Without that ordering,
riscv_have_user_pmlen(7) would still return its default false and the
RVA23U64 detection path would always bail.

Consider this as the cache that subsequent consumers (hwprobe's
RVA23U64 base behavior bit, /proc/cpuinfo's "isa bases" lines, etc.)
can read without recomputing. System-wide consistency are ensured.

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3:
- Add a blank line before the subsys_initcall() registration (Andrew).
- Set the local ext_mask with __set_bit() and test the mandate set with
  !bitmap_subset() (Sashiko).
- Require the Zic64b ISA extension in the RVA23U64 mask,
  instead of open-coded cache block-size check. (New, thoughts from Andrew)
v2:
- Implement riscv_init_isa_bases() that runs at system init time,
  after tagged_addr_init() populates have_user_pmlen_*.
- Split RVA23S64 placeholder into a future patch.
---
 arch/riscv/include/asm/cpufeature.h | 14 ++++++
 arch/riscv/kernel/cpufeature.c      | 90 +++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 739fcc84bf7b2..facc31b2960c6 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -25,10 +25,24 @@ struct riscv_cpuinfo {
 	unsigned long mimpid;
 };
 
+enum {
+	RISCV_ISA_BASE_IMA,
+	RISCV_ISA_BASE_RVA23U64,
+	RISCV_NR_ISA_BASES,
+};
+
+/**
+ * struct riscv_isainfo - per-hart ISA state
+ * @isa: bitmap of ISA extensions this hart implements
+ * @isa_bases: bitmap of profile bases this hart conforms to
+ */
 struct riscv_isainfo {
 	DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX);
+	DECLARE_BITMAP(isa_bases, RISCV_NR_ISA_BASES);
 };
 
+extern unsigned long riscv_isa_bases[BITS_TO_LONGS(RISCV_NR_ISA_BASES)];
+
 DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
 
 extern const struct seq_operations cpuinfo_op;
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 79ff431768139..15b708da98a1c 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -41,6 +41,9 @@ unsigned long elf_hwcap __read_mostly;
 /* Host ISA bitmap */
 static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 
+/* Host ISA bases bitmap */
+DECLARE_BITMAP(riscv_isa_bases, RISCV_NR_ISA_BASES) __read_mostly;
+
 /* Per-cpu ISA extensions. */
 struct riscv_isainfo hart_isa[NR_CPUS];
 
@@ -1321,3 +1324,90 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
 	}
 }
 #endif
+
+/*
+ * Compute the set of profile bases (IMA, RVA23U64, ...) a hart
+ * conforms to, given its resolved ISA bitmap.
+ *
+ * If @isa_bitmap is NULL, the host ISA bitmap (the AND across all harts) is
+ * used.
+ */
+static void riscv_set_isa_bases(unsigned long *bases, const unsigned long *isa_bitmap)
+{
+	const unsigned long *isa = isa_bitmap ? isa_bitmap : riscv_isa;
+	DECLARE_BITMAP(ext_mask, RISCV_ISA_EXT_MAX) = { 0 };
+
+	/* IMA */
+	__set_bit(RISCV_ISA_EXT_I, ext_mask);
+	__set_bit(RISCV_ISA_EXT_M, ext_mask);
+	__set_bit(RISCV_ISA_EXT_A, ext_mask);
+
+	if (!bitmap_subset(ext_mask, isa, RISCV_ISA_EXT_MAX))
+		return;
+
+	set_bit(RISCV_ISA_BASE_IMA, bases);
+
+	/* RVA23U64 */
+
+	/* Supm with PMLEN=7 */
+	if (!riscv_have_user_pmlen(7))
+		return;
+
+	__set_bit(RISCV_ISA_EXT_F, ext_mask);
+	__set_bit(RISCV_ISA_EXT_D, ext_mask);
+	__set_bit(RISCV_ISA_EXT_C, ext_mask);
+	__set_bit(RISCV_ISA_EXT_B, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICSR, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICNTR, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIHPM, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICCIF, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICCRSE, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICCAMOA, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICCLSM, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZA64RS, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIHINTPAUSE, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICBOM, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICBOP, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICBOZ, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIC64B, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZFHMIN, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZKT, ext_mask);
+	__set_bit(RISCV_ISA_EXT_V, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZVFHMIN, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZVBB, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZVKT, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIHINTNTL, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICOND, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIMOP, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZCMOP, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZCB, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZFA, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZAWRS, ext_mask);
+	__set_bit(RISCV_ISA_EXT_SUPM, ext_mask);
+
+	if (!bitmap_subset(ext_mask, isa, RISCV_ISA_EXT_MAX))
+		return;
+
+	set_bit(RISCV_ISA_BASE_RVA23U64, bases);
+}
+
+/*
+ * Populate the host ISA bases bitmap (riscv_isa_bases) and each
+ * hart's per-cpu isa_bases.
+ */
+static int __init riscv_init_isa_bases(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		riscv_set_isa_bases(hart_isa[cpu].isa_bases, hart_isa[cpu].isa);
+
+	riscv_set_isa_bases(riscv_isa_bases, NULL);
+	return 0;
+}
+
+/*
+ * Registered as subsys_initcall so it runs after
+ * core_initcall(tagged_addr_init) populates have_user_pmlen_*.
+ */
+subsys_initcall(riscv_init_isa_bases);

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:07 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:07 -0400
Subject: [PATCH v3 12/15] riscv: Add a getter for user PMLEN support
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-12-5529a7b28384@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

Querying whether a given user PMLEN is supported is needed for
RVA23U64 base detection from outside arch/riscv/kernel/process.c.
Add riscv_have_user_pmlen() to expose this.

Link: https://lore.kernel.org/linux-riscv/rfuwa7a3ebe76udmnwyrssjy7shkkgxntvhwzn6oquysj4tuyp at xzvpylcfhz53/
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
[Guodong: replace exported booleans with getter per Andrew's suggestion]
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: No change.
v2: Add a getter for user PMLEN.
---
 arch/riscv/include/asm/processor.h |  4 ++++
 arch/riscv/kernel/process.c        | 12 ++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 812517b2cec13..febf51e127f70 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -214,6 +214,10 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg);
 long get_tagged_addr_ctrl(struct task_struct *task);
 #define SET_TAGGED_ADDR_CTRL(arg)	set_tagged_addr_ctrl(current, arg)
 #define GET_TAGGED_ADDR_CTRL()		get_tagged_addr_ctrl(current)
+
+bool riscv_have_user_pmlen(u8 len);
+#else
+static inline bool riscv_have_user_pmlen(u8 len) { return false; }
 #endif
 
 #endif /* __ASSEMBLER__ */
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index b2df7f72241a5..5d9cb108a6232 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -302,6 +302,18 @@ enum {
 static bool have_user_pmlen_7;
 static bool have_user_pmlen_16;
 
+bool riscv_have_user_pmlen(u8 len)
+{
+	switch (len) {
+	case PMLEN_7:
+		return have_user_pmlen_7;
+	case PMLEN_16:
+		return have_user_pmlen_16;
+	default:
+		return false;
+	}
+}
+
 /*
  * Control the relaxed ABI allowing tagged user addresses into the kernel.
  */

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:09 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:09 -0400
Subject: [PATCH v3 14/15] riscv: cpu: Output isa bases lines in cpuinfo
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-14-5529a7b28384@gmail.com>

Output two new lines per processor in /proc/cpuinfo:

  isa bases       : <bases that all harts conform to>
  hart isa bases  : <bases that this specific hart conforms to>

These read directly from the cached riscv_isa_bases and
hart_isa[cpu].isa_bases bitmaps populated at boot by
riscv_init_isa_bases().

Example output on qemu booted with -cpu rva23s64,sv39=on,pmp=on
(showing only the new lines plus their neighbors for context):

  processor       : 0
  hart            : 4
  isa bases       : rv64ima rva23u64
  isa             : rv64imafdcbvh_zicbom_zicbop_...
  mmu             : sv39
  ...
  mimpid          : 0x0
  hart isa bases  : rv64ima rva23u64
  hart isa        : rv64imafdcbvh_zicbom_zicbop_...

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: No change.
v2:
- Read from the cached riscv_isa_bases and hart_isa[cpu_id].isa_bases
  bitmaps populated by riscv_init_isa_bases() at init time.
---
 arch/riscv/kernel/cpu.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index 3dbc8cc557dd1..31e2857dcdcf1 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -305,6 +305,26 @@ static void print_mmu(struct seq_file *f)
 	seq_printf(f, "mmu\t\t: %s\n", sv_type);
 }
 
+static const char * const riscv_isa_base_names[] = {
+#ifdef CONFIG_32BIT
+	[RISCV_ISA_BASE_IMA] = "rv32ima",
+#else
+	[RISCV_ISA_BASE_IMA] = "rv64ima",
+#endif
+	[RISCV_ISA_BASE_RVA23U64] = "rva23u64",
+};
+
+static void print_isa_bases(struct seq_file *m, const unsigned long *isa_bases)
+{
+	unsigned int i;
+
+	for (i = 0; i < RISCV_NR_ISA_BASES; i++) {
+		if (test_bit(i, isa_bases))
+			seq_printf(m, " %s", riscv_isa_base_names[i]);
+	}
+	seq_puts(m, "\n");
+}
+
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
 	if (*pos == nr_cpu_ids)
@@ -336,6 +356,9 @@ static int c_show(struct seq_file *m, void *v)
 	seq_printf(m, "processor\t: %lu\n", cpu_id);
 	seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id));
 
+	seq_puts(m, "isa bases\t:");
+	print_isa_bases(m, riscv_isa_bases);
+
 	/*
 	 * For historical raisins, the isa: line is limited to the lowest common
 	 * denominator of extensions supported across all harts. A true list of
@@ -360,6 +383,9 @@ static int c_show(struct seq_file *m, void *v)
 	seq_printf(m, "marchid\t\t: 0x%lx\n", ci->marchid);
 	seq_printf(m, "mimpid\t\t: 0x%lx\n", ci->mimpid);
 
+	seq_puts(m, "hart isa bases\t:");
+	print_isa_bases(m, hart_isa[cpu_id].isa_bases);
+
 	/*
 	 * Print the ISA extensions specific to this hart, which may show
 	 * additional extensions not present across all harts.

-- 
2.43.0



From docular.xu at gmail.com  Wed Jun  3 04:12:10 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Wed, 03 Jun 2026 07:12:10 -0400
Subject: [PATCH v3 15/15] riscv: hwprobe: Introduce rva23u64 base behavior
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <20260603-rva23u64-hwprobe-v2-v3-15-5529a7b28384@gmail.com>

Provide a hwprobe base-behavior bit so userspace can check RVA23U64
support in one call.  Without it, a consumer needs five hwprobe
calls and four prctl calls, which is error-prone to require of every
caller.  Most software treats RVA23U64 as a new base anyway, so
expose it directly.

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v3: No change.
v2:
- Detect RVA23U64 by reading from the cached hart_isa[].isa_bases
  bitmap populated by riscv_init_isa_bases() at init time, sharing
  one source of truth with /proc/cpuinfo.
---
 Documentation/arch/riscv/hwprobe.rst               |  8 ++++++++
 arch/riscv/include/uapi/asm/hwprobe.h              |  3 ++-
 arch/riscv/kernel/sys_hwprobe.c                    | 23 +++++++++++++++-------
 tools/testing/selftests/riscv/hwprobe/which-cpus.c |  2 +-
 4 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index 601e81f561421..d6712259946e9 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -67,6 +67,14 @@ The following keys are defined:
       programs (it may still be executed in userspace via a
       kernel-controlled mechanism such as the vDSO).
 
+  * :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64`: Support for all mandatory
+    extensions of RVA23U64, as defined in the RISC-V Profiles specification
+    starting from commit 0273f3c921b6 ("rva23/rvb23 ratified").
+
+    The RVA23U64 base is based upon the IMA base and therefore IMA extension
+    keys (e.g. :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`:) may be used to probe
+    optional extensions.
+
 * :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`: A bitmask containing extensions
   that are compatible with the :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`:
   base system behavior.
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 36ec8ab470423..50733d3db7633 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -21,7 +21,8 @@ struct riscv_hwprobe {
 #define RISCV_HWPROBE_KEY_MARCHID	1
 #define RISCV_HWPROBE_KEY_MIMPID	2
 #define RISCV_HWPROBE_KEY_BASE_BEHAVIOR	3
-#define		RISCV_HWPROBE_BASE_BEHAVIOR_IMA	(1 << 0)
+#define		RISCV_HWPROBE_BASE_BEHAVIOR_IMA		(1 << 0)
+#define		RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64	(1 << 1)
 #define RISCV_HWPROBE_KEY_IMA_EXT_0	4
 #define		RISCV_HWPROBE_IMA_FD		(1 << 0)
 #define		RISCV_HWPROBE_IMA_C		(1 << 1)
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 3e80e5551ae0d..3f66f2e99d41a 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -226,6 +226,17 @@ static bool hwprobe_ext0_has(const struct cpumask *cpus, u64 ext)
 	return (pair.value & ext);
 }
 
+static bool hwprobe_has_isa_base(const struct cpumask *cpus, unsigned int base)
+{
+	int cpu;
+
+	for_each_cpu(cpu, cpus) {
+		if (!test_bit(base, hart_isa[cpu].isa_bases))
+			return false;
+	}
+	return true;
+}
+
 #if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)
 static u64 hwprobe_misaligned(const struct cpumask *cpus)
 {
@@ -308,14 +319,12 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
 	case RISCV_HWPROBE_KEY_MIMPID:
 		hwprobe_arch_id(pair, cpus);
 		break;
-	/*
-	 * The kernel already assumes that the base single-letter ISA
-	 * extensions are supported on all harts, and only supports the
-	 * IMA base, so just cheat a bit here and tell that to
-	 * userspace.
-	 */
 	case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
-		pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
+		pair->value = 0;
+		if (hwprobe_has_isa_base(cpus, RISCV_ISA_BASE_IMA))
+			pair->value |= RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
+		if (hwprobe_has_isa_base(cpus, RISCV_ISA_BASE_RVA23U64))
+			pair->value |= RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64;
 		break;
 
 	case RISCV_HWPROBE_KEY_IMA_EXT_0:
diff --git a/tools/testing/selftests/riscv/hwprobe/which-cpus.c b/tools/testing/selftests/riscv/hwprobe/which-cpus.c
index 587feb198c049..f8c797b1d0fd9 100644
--- a/tools/testing/selftests/riscv/hwprobe/which-cpus.c
+++ b/tools/testing/selftests/riscv/hwprobe/which-cpus.c
@@ -105,7 +105,7 @@ int main(int argc, char **argv)
 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, };
 	rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
 	assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_BASE_BEHAVIOR &&
-	       pairs[0].value == RISCV_HWPROBE_BASE_BEHAVIOR_IMA);
+	       (pairs[0].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA));
 
 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, };
 	rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);

-- 
2.43.0



From xueshuai at linux.alibaba.com  Tue Jun  2 18:23:08 2026
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Wed, 3 Jun 2026 09:23:08 +0800
Subject: [PATCH v2 5/8] riscv: stacktrace: introduce stack-bound tracking
 helpers
In-Reply-To: <20260528082310.1994388-6-wanghan@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
 <20260528082310.1994388-6-wanghan@linux.alibaba.com>
Message-ID: <461a727f-e2cd-4192-9e19-16172500053c@linux.alibaba.com>



On 5/28/26 4:23 PM, Wang Han wrote:
> A reliable unwinder needs to validate that every frame record it reads
> is fully contained in a known kernel stack, and it needs to refuse to
> walk back into a stack it has already left. Add the building blocks
> for that:
> 
>    * struct stack_info / struct unwind_state in a new
>      asm/stacktrace/common.h, modelled on the arm64 reference
>      implementation.
>    * stackinfo_get_irq() / stackinfo_get_task() / stackinfo_get_overflow()
>      plus the corresponding on_*_stack() predicates in asm/stacktrace.h,
>      so callers can ask "is this object on stack X?" by stack kind
>      rather than open-coded address arithmetic.
>    * unwind_init_common(), unwind_find_stack() and
>      unwind_consume_stack() helpers that enforce the
>      forward-progress-only invariant required for reliability.
> 
> No existing user is wired up to these helpers in this commit; the
> unwinder switch comes in a follow-up. The header changes leave
> on_thread_stack() with the same semantics as before, just expressed in
> terms of the new helpers.
> 
> Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
> ---
>   arch/riscv/include/asm/stacktrace.h        |  65 ++++++++-
>   arch/riscv/include/asm/stacktrace/common.h | 159 +++++++++++++++++++++
>   2 files changed, 222 insertions(+), 2 deletions(-)
>   create mode 100644 arch/riscv/include/asm/stacktrace/common.h
> 
> diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h
> index b1495a7e06ce..bc87c4940379 100644
> --- a/arch/riscv/include/asm/stacktrace.h
> +++ b/arch/riscv/include/asm/stacktrace.h
> @@ -3,8 +3,13 @@
>   #ifndef _ASM_RISCV_STACKTRACE_H
>   #define _ASM_RISCV_STACKTRACE_H
>   
> +#include <linux/percpu.h>
>   #include <linux/sched.h>
> +#include <linux/sched/task_stack.h>
> +
> +#include <asm/irq_stack.h>
>   #include <asm/ptrace.h>
> +#include <asm/stacktrace/common.h>
>   
>   struct stackframe {
>   	unsigned long fp;
> @@ -16,14 +21,70 @@ extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *re
>   extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
>   			   const char *loglvl);
>   
> -static inline bool on_thread_stack(void)
> +/*
> + * IRQ stack accessors
> + */
> +static inline struct stack_info stackinfo_get_irq(void)
> +{
> +	unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
> +	unsigned long high = low + IRQ_STACK_SIZE;
> +
> +	return (struct stack_info) {
> +		.low = low,
> +		.high = high,
> +	};
> +}
> +
> +static inline bool on_irq_stack(unsigned long sp, unsigned long size)
> +{
> +	struct stack_info info = stackinfo_get_irq();
> +
> +	return stackinfo_on_stack(&info, sp, size);
> +}
> +
> +/*
> + * Task stack accessors
> + */
> +static inline struct stack_info stackinfo_get_task(const struct task_struct *tsk)
>   {
> -	return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1));
> +	unsigned long low = (unsigned long)task_stack_page(tsk);
> +	unsigned long high = low + THREAD_SIZE;
> +
> +	return (struct stack_info) {
> +		.low = low,
> +		.high = high,
> +	};
> +}
> +
> +static inline bool on_task_stack(const struct task_struct *tsk,
> +				 unsigned long sp, unsigned long size)
> +{
> +	struct stack_info info = stackinfo_get_task(tsk);
> +
> +	return stackinfo_on_stack(&info, sp, size);
>   }
>   
> +/*
> + * Cast is necessary since current->stack is an opaque ptr.
> + */
> +#define on_thread_stack()	(on_task_stack(current, current_stack_pointer, 1))
>   
> +/*
> + * Overflow stack accessors
> + */
>   #ifdef CONFIG_VMAP_STACK
>   DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
> +
> +static inline struct stack_info stackinfo_get_overflow(void)
> +{
> +	unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack);
> +	unsigned long high = low + OVERFLOW_STACK_SIZE;
> +
> +	return (struct stack_info) {
> +		.low = low,
> +		.high = high,
> +	};
> +}
>   #endif /* CONFIG_VMAP_STACK */
>   
>   #endif /* _ASM_RISCV_STACKTRACE_H */
> diff --git a/arch/riscv/include/asm/stacktrace/common.h b/arch/riscv/include/asm/stacktrace/common.h
> new file mode 100644
> index 000000000000..87d6d40672f3
> --- /dev/null
> +++ b/arch/riscv/include/asm/stacktrace/common.h
> @@ -0,0 +1,159 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +/*
> + * RISC-V common stack unwinder types and helpers.
> + *
> + * See: arch/arm64/include/asm/stacktrace/common.h for the reference
> + * implementation.
> + *
> + * Copyright (C) 2024

Nit: The new common.h carries "Copyright (C) 2024", but this is a 2026
submission.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai



From xueshuai at linux.alibaba.com  Tue Jun  2 18:35:55 2026
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Wed, 3 Jun 2026 09:35:55 +0800
Subject: [PATCH v2 6/8] riscv: stacktrace: switch to frame-pointer based
 unwinder
In-Reply-To: <20260528082310.1994388-7-wanghan@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
 <20260528082310.1994388-7-wanghan@linux.alibaba.com>
Message-ID: <2f539ada-505e-477b-a554-6b81cf5542d4@linux.alibaba.com>



On 5/28/26 4:23 PM, Wang Han wrote:
> Replace the open-coded frame-pointer walker in arch_stack_walk() with a
> robust kunwind state machine, modelled on arch/arm64/kernel/stacktrace.c
> and retargeted to the RISC-V {fp, ra} frame record convention. The new
> walker tracks stack bounds, consumes frame records monotonically,
> understands the metadata pt_regs records added in the previous frame
> record metadata patch, and recovers return addresses replaced by
> function graph tracing and kretprobes.
> 
> This commit introduces arch_stack_walk_reliable() but does not yet
> select HAVE_RELIABLE_STACKTRACE; that is done in a follow-up Kconfig
> patch so this commit can be reviewed and bisected as a pure unwinder
> replacement. Until that Kconfig change lands, livepatch is not yet
> enabled and arch_stack_walk_reliable() has no in-tree caller.
> 
> Three related callers are updated to keep the same frame-record
> assumptions everywhere:
> 
>    * Function graph tracing: the old RISC-V unwinder matched function
>      graph return-stack entries by the saved return-address slot. That
>      was consistent with the static mcount path, but not with the dynamic
>      ftrace path where the parent slot is ftrace_regs::ra. Use the
>      architectural frame pointer as the function graph return-address
>      cookie, matching the kunwind walker.
> 
>    * Perf callchains: route kernel callchain collection through
>      arch_stack_walk() so perf sees the same frame-pointer unwind
>      behaviour as dump_stack() and the upcoming livepatch path.
> 
>    * dump_backtrace() / __get_wchan() / show_stack(): these now go
>      through arch_stack_walk(); the explicit "Call Trace:" header is
>      moved into dump_backtrace() to preserve the original output.
> 
> The non-frame-pointer fallback walker is kept untouched for
> !CONFIG_FRAME_POINTER builds.
> 
> Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
> ---
>   arch/riscv/kernel/ftrace.c         |   6 +-
>   arch/riscv/kernel/perf_callchain.c |   2 +-
>   arch/riscv/kernel/stacktrace.c     | 560 ++++++++++++++++++++++++-----
>   3 files changed, 472 insertions(+), 96 deletions(-)
> 
> diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c
> index b430edfb83f4..5d55199a9230 100644
> --- a/arch/riscv/kernel/ftrace.c
> +++ b/arch/riscv/kernel/ftrace.c
> @@ -242,7 +242,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
>   	 */
>   	old = *parent;
>   
> -	if (!function_graph_enter(old, self_addr, frame_pointer, parent))
> +	if (!function_graph_enter(old, self_addr, frame_pointer,
> +				  (void *)frame_pointer))
>   		*parent = return_hooker;
>   }
>   
> @@ -264,7 +265,8 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
>   	 */
>   	old = *parent;
>   
> -	if (!function_graph_enter_regs(old, ip, frame_pointer, parent, fregs))
> +	if (!function_graph_enter_regs(old, ip, frame_pointer,
> +				       (void *)frame_pointer, fregs))
>   		*parent = return_hooker;
>   }
>   #endif /* CONFIG_DYNAMIC_FTRACE */
> diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c
> index b465bc9eb870..436af96ea59c 100644
> --- a/arch/riscv/kernel/perf_callchain.c
> +++ b/arch/riscv/kernel/perf_callchain.c
> @@ -44,5 +44,5 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
>   		return;
>   	}
>   
> -	walk_stackframe(NULL, regs, fill_callchain, entry);
> +	arch_stack_walk(fill_callchain, entry, NULL, regs);
>   }
> diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
> index 2692d3a06afa..0d76320b3a29 100644
> --- a/arch/riscv/kernel/stacktrace.c
> +++ b/arch/riscv/kernel/stacktrace.c
> @@ -11,98 +11,16 @@
>   #include <linux/sched/task_stack.h>
>   #include <linux/stacktrace.h>
>   #include <linux/ftrace.h>
> +#include <linux/kprobes.h>
> +#include <linux/llist.h>
>   
>   #include <asm/stacktrace.h>
>   
> -#ifdef CONFIG_FRAME_POINTER
> -
>   /*
> - * This disables KASAN checking when reading a value from another task's stack,
> - * since the other task could be running on another CPU and could have poisoned
> - * the stack in the meantime.
> + * Non-frame-pointer fallback unwinder.
> + * Only compiled when CONFIG_FRAME_POINTER is not enabled.
>    */
> -#define READ_ONCE_TASK_STACK(task, x)			\
> -({							\
> -	unsigned long val;				\
> -	unsigned long addr = x;				\
> -	if ((task) == current)				\
> -		val = READ_ONCE(addr);			\
> -	else						\
> -		val = READ_ONCE_NOCHECK(addr);		\
> -	val;						\
> -})
> -
> -extern asmlinkage void handle_exception(void);
> -extern unsigned long ret_from_exception_end;
> -
> -static inline int fp_is_valid(unsigned long fp, unsigned long sp)
> -{
> -	unsigned long low, high;
> -
> -	low = sp + sizeof(struct stackframe);
> -	high = ALIGN(sp, THREAD_SIZE);
> -
> -	return !(fp < low || fp > high || fp & 0x07);
> -}
> -
> -void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
> -			     bool (*fn)(void *, unsigned long), void *arg)
> -{
> -	unsigned long fp, sp, pc;
> -	int graph_idx = 0;
> -	int level = 0;
> -
> -	if (regs) {
> -		fp = frame_pointer(regs);
> -		sp = user_stack_pointer(regs);
> -		pc = instruction_pointer(regs);
> -	} else if (task == NULL || task == current) {
> -		fp = (unsigned long)__builtin_frame_address(0);
> -		sp = current_stack_pointer;
> -		pc = (unsigned long)walk_stackframe;
> -		level = -1;
> -	} else {
> -		/* task blocked in __switch_to */
> -		fp = task->thread.s[0];
> -		sp = task->thread.sp;
> -		pc = task->thread.ra;
> -	}
> -
> -	for (;;) {
> -		struct stackframe *frame;
> -
> -		if (unlikely(!__kernel_text_address(pc) || (level++ >= 0 && !fn(arg, pc))))
> -			break;
> -
> -		if (unlikely(!fp_is_valid(fp, sp)))
> -			break;
> -
> -		/* Unwind stack frame */
> -		frame = (struct stackframe *)fp - 1;
> -		sp = fp;
> -		if (regs && (regs->epc == pc) && fp_is_valid(frame->ra, sp)) {
> -			/* We hit function where ra is not saved on the stack */
> -			fp = frame->ra;
> -			pc = regs->ra;
> -		} else {
> -			fp = READ_ONCE_TASK_STACK(task, frame->fp);
> -			pc = READ_ONCE_TASK_STACK(task, frame->ra);
> -			pc = ftrace_graph_ret_addr(task, &graph_idx, pc,
> -						   &frame->ra);
> -			if (pc >= (unsigned long)handle_exception &&
> -			    pc < (unsigned long)&ret_from_exception_end) {
> -				if (unlikely(!fn(arg, pc)))
> -					break;
> -
> -				pc = ((struct pt_regs *)sp)->epc;
> -				fp = ((struct pt_regs *)sp)->s0;
> -			}
> -		}
> -
> -	}
> -}
> -
> -#else /* !CONFIG_FRAME_POINTER */
> +#ifndef CONFIG_FRAME_POINTER
>   
>   void notrace walk_stackframe(struct task_struct *task,
>   	struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *arg)
> @@ -133,7 +51,12 @@ void notrace walk_stackframe(struct task_struct *task,
>   	}
>   }
>   
> -#endif /* CONFIG_FRAME_POINTER */
> +#endif /* !CONFIG_FRAME_POINTER */
> +
> +/*
> + * Common trace helpers.
> + * These are used by both the FP (kunwind) and non-FP (walk_stackframe) paths.
> + */
>   
>   static bool print_trace_address(void *arg, unsigned long pc)
>   {
> @@ -146,12 +69,12 @@ static bool print_trace_address(void *arg, unsigned long pc)
>   noinline void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
>   		    const char *loglvl)
>   {
> -	walk_stackframe(task, regs, print_trace_address, (void *)loglvl);
> +	printk("%sCall Trace:\n", loglvl);
> +	arch_stack_walk(print_trace_address, (void *)loglvl, task, regs);
>   }
>   
>   void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
>   {
> -	pr_cont("%sCall Trace:\n", loglvl);
>   	dump_backtrace(NULL, task, loglvl);
>   }
>   
> @@ -171,17 +94,468 @@ unsigned long __get_wchan(struct task_struct *task)
>   
>   	if (!try_get_task_stack(task))
>   		return 0;
> -	walk_stackframe(task, NULL, save_wchan, &pc);
> +	arch_stack_walk(save_wchan, &pc, task, NULL);
>   	put_task_stack(task);
>   	return pc;
>   }
>   
> -noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
> -		     struct task_struct *task, struct pt_regs *regs)
> +/*
> + * Frame-pointer-based kernel unwind infrastructure.
> + * Only compiled when CONFIG_FRAME_POINTER is enabled.
> + *
> + * See: arch/arm64/kernel/stacktrace.c for the reference implementation.
> + */
> +#ifdef CONFIG_FRAME_POINTER
> +
> +/*
> + * Per-cpu stacks are only accessible when unwinding the current task in a
> + * non-preemptible context.
> + */
> +#define STACKINFO_CPU(task, name)				\
> +	({							\
> +		(((task) == current) && !preemptible())		\
> +			? stackinfo_get_##name()		\
> +			: stackinfo_get_unknown();		\
> +	})
> +
> +enum kunwind_source {
> +	KUNWIND_SOURCE_UNKNOWN,
> +	KUNWIND_SOURCE_FRAME,
> +	KUNWIND_SOURCE_CALLER,
> +	KUNWIND_SOURCE_TASK,
> +	KUNWIND_SOURCE_REGS_PC,
> +};
> +
> +union unwind_flags {
> +	unsigned long	all;
> +	struct {
> +		unsigned long	fgraph : 1,
> +				kretprobe : 1;
> +	};
> +};
> +
> +/*
> + * Kernel unwind state
> + *
> + * @common:    Common unwind state.
> + * @task:      The task being unwound.
> + * @graph_idx: Used by ftrace_graph_ret_addr() for optimized stack unwinding.
> + * @kr_cur:    When KRETPROBES is selected, holds the kretprobe instance
> + *             associated with the most recently encountered replacement ra
> + *             value.
> + */
> +struct kunwind_state {
> +	struct unwind_state common;
> +	struct task_struct *task;
> +	int graph_idx;
> +#ifdef CONFIG_KRETPROBES
> +	struct llist_node *kr_cur;
> +#endif
> +	enum kunwind_source source;
> +	union unwind_flags flags;
> +	struct pt_regs *regs;
> +};
> +
> +static __always_inline void
> +kunwind_init(struct kunwind_state *state,
> +	     struct task_struct *task)
> +{
> +	unwind_init_common(&state->common);
> +	state->task = task;
> +	state->source = KUNWIND_SOURCE_UNKNOWN;
> +	state->flags.all = 0;
> +	state->regs = NULL;
> +}
> +
> +/*
> + * Start an unwind from a pt_regs.
> + *
> + * The unwind will begin at the PC within the regs.
> + *
> + * The regs must be on a stack currently owned by the calling task.
> + */
> +static __always_inline void
> +kunwind_init_from_regs(struct kunwind_state *state,
> +		       struct pt_regs *regs)
> +{
> +	kunwind_init(state, current);
> +
> +	state->regs = regs;
> +	state->common.fp = frame_pointer(regs);
> +	state->common.pc = instruction_pointer(regs);
> +	state->source = KUNWIND_SOURCE_REGS_PC;
> +}
> +
> +/*
> + * Start an unwind from a caller.
> + *
> + * The unwind will begin at the caller of whichever function this is inlined
> + * into.
> + *
> + * The function which invokes this must be noinline.
> + */
> +static __always_inline void
> +kunwind_init_from_caller(struct kunwind_state *state)
> +{
> +	unsigned long fp = (unsigned long)__builtin_frame_address(0);
> +	struct frame_record *record = (struct frame_record *)fp - 1;
> +
> +	kunwind_init(state, current);
> +
> +	state->common.fp = READ_ONCE(record->fp);
> +	state->common.pc = READ_ONCE(record->ra);
> +	state->source = KUNWIND_SOURCE_CALLER;
> +}
> +
> +/*
> + * Start an unwind from a blocked task.
> + *
> + * The unwind will begin at the blocked task's saved PC (i.e. the caller of
> + * __switch_to).
> + *
> + * The caller should ensure the task is blocked in __switch_to for the
> + * duration of the unwind, or the unwind will be bogus. It is never valid to
> + * call this for the current task.
> + */
> +static __always_inline void
> +kunwind_init_from_task(struct kunwind_state *state,
> +		       struct task_struct *task)
> +{
> +	kunwind_init(state, task);
> +
> +	state->common.fp = task->thread.s[0];
> +	state->common.pc = task->thread.ra;
> +	state->source = KUNWIND_SOURCE_TASK;
> +}
> +
> +static __always_inline int
> +kunwind_recover_return_address(struct kunwind_state *state)
> +{
> +#ifdef CONFIG_FUNCTION_GRAPH_TRACER
> +	if (state->task->ret_stack &&
> +	    state->common.pc == (unsigned long)return_to_handler) {
> +		unsigned long orig_pc;
> +
> +		orig_pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
> +						state->common.pc,
> +						(void *)state->common.fp);
> +		if (state->common.pc == orig_pc) {
> +			WARN_ON_ONCE(state->task == current);
> +			return -EINVAL;
> +		}
> +		state->common.pc = orig_pc;
> +		state->flags.fgraph = 1;
> +	}
> +#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
> +
> +#ifdef CONFIG_KRETPROBES
> +	if (is_kretprobe_trampoline(state->common.pc)) {
> +		unsigned long orig_pc;
> +
> +		orig_pc = kretprobe_find_ret_addr(state->task,
> +						  (void *)state->common.fp,
> +						  &state->kr_cur);
> +		if (!orig_pc)
> +			return -EINVAL;
> +		state->common.pc = orig_pc;
> +		state->flags.kretprobe = 1;
> +	}
> +#endif /* CONFIG_KRETPROBES */
> +
> +	return 0;
> +}
> +
> +/*
> + * When we reach an exception boundary marked by a metadata frame record,
> + * extract pt_regs from the stack and continue unwinding from the saved
> + * context (epc and s0/fp).
> + *
> + * On RISC-V, fp points above the metadata record, so the record's
> + * frame_record portion is at fp - sizeof(struct frame_record).
> + */
> +static __always_inline int
> +kunwind_next_regs_pc(struct kunwind_state *state)
> +{
> +	struct stack_info *info;
> +	unsigned long fp = state->common.fp;
> +	struct pt_regs *regs;
> +
> +	regs = container_of((unsigned long *)(fp - sizeof(struct frame_record)),
> +			    struct pt_regs, stackframe.record.fp);
> +
> +	info = unwind_find_stack(&state->common, (unsigned long)regs,
> +				 sizeof(*regs));
> +	if (!info)
> +		return -EINVAL;
> +
> +	unwind_consume_stack(&state->common, info, (unsigned long)regs,
> +			     sizeof(*regs));
> +
> +	state->regs = regs;
> +	state->common.pc = regs->epc;
> +	state->common.fp = frame_pointer(regs);
> +	state->regs = NULL;

state->regs is a dead field, and kunwind_next_regs_pc() clears
         it in a way that contradicts both arm64 and your own
         init_from_regs.

struct kunwind_state has a `struct pt_regs *regs`, but I can't find any
reader of it anywhere in the file ? arch_kunwind_consume_entry() and
arch_reliable_kunwind_consume_entry() only ever read common.pc and
source. It is written in three places:

     kunwind_init():           state->regs = NULL;
     kunwind_init_from_regs():  state->regs = regs;     /* not cleared */
     kunwind_next_regs_pc():    state->regs = regs;
                                state->common.pc = regs->epc;
                                state->common.fp = frame_pointer(regs);
                                state->regs = NULL;      /* cleared! */

Two things:

   (a) The field has no consumer, so it's currently dead.

   (b) In kunwind_next_regs_pc() you set state->regs = regs and then
       immediately reset it to NULL two lines later. The arm64 reference
       does *not* clear it there, and your own kunwind_init_from_regs()
       leaves it set. So the three REGS_PC producers disagree on whether
       ->regs is valid.

It's harmless today only because nothing reads ->regs. But the moment
someone adds a consumer (e.g. to expose the pt_regs at an exception
boundary for a reliable dump), the stray `state->regs = NULL;` in
kunwind_next_regs_pc() becomes a silent bug.

Please either:
   - drop the field and all three writes, if it's genuinely unused, or
   - keep it and remove the `state->regs = NULL;` in
     kunwind_next_regs_pc() so it matches arm64 and init_from_regs.

> +	state->source = KUNWIND_SOURCE_REGS_PC;
> +	return 0;
> +}
> +
> +/*
> + * Handle a metadata frame record embedded in pt_regs.
> + *
> + * On RISC-V, fp points above the record (fp = metadata + 16), so the
> + * frame_record_meta starts at fp - sizeof(struct frame_record).
> + *
> + * FRAME_META_TYPE_FINAL: This is the outermost exception entry
> + *   (user -> kernel). Unwinding terminates successfully.
> + * FRAME_META_TYPE_PT_REGS: This is a nested exception entry
> + *   (kernel -> kernel). Continue unwinding from the saved context.
> + */
> +static __always_inline int
> +kunwind_next_frame_record_meta(struct kunwind_state *state)
> +{
> +	struct task_struct *tsk = state->task;
> +	unsigned long fp = state->common.fp;
> +	unsigned long meta_base = fp - sizeof(struct frame_record);
> +	struct frame_record_meta *meta;
> +	struct stack_info *info;
> +
> +	info = unwind_find_stack(&state->common, meta_base, sizeof(*meta));
> +	if (!info)
> +		return -EINVAL;
> +
> +	meta = (struct frame_record_meta *)meta_base;
> +	switch (READ_ONCE(meta->type)) {
> +	case FRAME_META_TYPE_FINAL:
> +		if (meta == &task_pt_regs(tsk)->stackframe)
> +			return -ENOENT;
> +		WARN_ON_ONCE(tsk == current);
> +		return -EINVAL;
> +	case FRAME_META_TYPE_PT_REGS:
> +		return kunwind_next_regs_pc(state);
> +	default:
> +		WARN_ON_ONCE(tsk == current);
> +		return -EINVAL;
> +	}
> +}
> +
> +/*
> + * Unwind from one frame record to the next.
> + *
> + * On RISC-V, the frame record sits at fp - sizeof(struct frame_record),
> + * immediately below the address pointed to by fp/s0. This applies to both
> + * normal frame records and metadata frame records (embedded in pt_regs).
> + *
> + * A metadata record is identified by both fp and ra being zero in the
> + * frame_record portion, with a type value following at fp + 16.
> + */
> +static __always_inline int
> +kunwind_next_frame_record(struct kunwind_state *state)
> +{
> +	unsigned long fp = state->common.fp;
> +	struct frame_record *record;
> +	struct stack_info *info;
> +	unsigned long new_fp, new_pc;
> +	unsigned long record_base;
> +
> +	if (fp & 0x7)
> +		return -EINVAL;
> +
> +	record_base = fp - sizeof(*record);
> +
> +	info = unwind_find_stack(&state->common, record_base, sizeof(*record));
> +	if (!info)
> +		return -EINVAL;
> +
> +	record = (struct frame_record *)record_base;
> +	new_fp = READ_ONCE(record->fp);
> +	new_pc = READ_ONCE(record->ra);
> +
> +	if (!new_fp && !new_pc)
> +		return kunwind_next_frame_record_meta(state);
> +
> +	unwind_consume_stack(&state->common, info, record_base,
> +			     sizeof(*record));
> +
> +	state->common.fp = new_fp;
> +	state->common.pc = new_pc;
> +	state->source = KUNWIND_SOURCE_FRAME;
> +
> +	return 0;
> +}
> +
> +/*
> + * Unwind from one frame record (A) to the next frame record (B).
> + *
> + * We terminate early if the location of B indicates a malformed chain of frame
> + * records (e.g. a cycle), determined based on the location and fp value of A
> + * and the location (but not the fp value) of B.
> + */
> +static __always_inline int
> +kunwind_next(struct kunwind_state *state)
> +{
> +	int err;
> +
> +	state->flags.all = 0;
> +
> +	switch (state->source) {
> +	case KUNWIND_SOURCE_FRAME:
> +	case KUNWIND_SOURCE_CALLER:
> +	case KUNWIND_SOURCE_TASK:
> +	case KUNWIND_SOURCE_REGS_PC:
> +		err = kunwind_next_frame_record(state);
> +		break;
> +	default:
> +		err = -EINVAL;
> +	}
> +
> +	if (err)
> +		return err;
> +
> +	return kunwind_recover_return_address(state);
> +}
> +
> +typedef bool (*kunwind_consume_fn)(const struct kunwind_state *state, void *cookie);
> +
> +static __always_inline int
> +do_kunwind(struct kunwind_state *state, kunwind_consume_fn consume_state,
> +	   void *cookie)
> +{
> +	int ret;
> +
> +	ret = kunwind_recover_return_address(state);
> +	if (ret)
> +		return ret;
> +
> +	while (1) {
> +		if (!consume_state(state, cookie))
> +			return -EINVAL;
> +		ret = kunwind_next(state);
> +		if (ret == -ENOENT)
> +			return 0;
> +		if (ret < 0)
> +			return ret;
> +	}
> +}
> +
> +static __always_inline int
> +kunwind_stack_walk(kunwind_consume_fn consume_state,
> +		   void *cookie, struct task_struct *task,
> +		   struct pt_regs *regs)
> +{
> +	struct task_struct *tsk = task ?: current;
> +	struct stack_info stacks[] = {
> +		stackinfo_get_task(tsk),
> +		STACKINFO_CPU(tsk, irq),
> +#ifdef CONFIG_VMAP_STACK
> +		STACKINFO_CPU(tsk, overflow),
> +#endif
> +	};
> +	struct kunwind_state state = {
> +		.common = {
> +			.stacks = stacks,
> +			.nr_stacks = ARRAY_SIZE(stacks),
> +		},
> +	};
> +
> +	if (regs) {
> +		if (tsk != current)
> +			return -EINVAL;
> +		kunwind_init_from_regs(&state, regs);
> +	} else if (tsk == current) {
> +		kunwind_init_from_caller(&state);
> +	} else {
> +		kunwind_init_from_task(&state, tsk);
> +	}
> +
> +	return do_kunwind(&state, consume_state, cookie);
> +}
> +
> +struct kunwind_consume_entry_data {
> +	stack_trace_consume_fn consume_entry;
> +	void *cookie;
> +};
> +
> +static __always_inline bool
> +arch_kunwind_consume_entry(const struct kunwind_state *state, void *cookie)
> +{
> +	struct kunwind_consume_entry_data *data = cookie;
> +
> +	return data->consume_entry(data->cookie, state->common.pc);
> +}
> +
> +static __always_inline bool
> +arch_reliable_kunwind_consume_entry(const struct kunwind_state *state, void *cookie)
> +{
> +	/*
> +	 * At an exception boundary we can reliably consume the saved PC. We do
> +	 * not know whether the LR was live when the exception was taken, and

Nit: s/LR/ra/ here. RISC-V has no link register; the equivalent is the
return-address register ra (x1). You already localized this correctly in
the kr_cur docstring ("replacement ra value"), so this comment is just an
oversight.

Thanks.
Shuai



From xueshuai at linux.alibaba.com  Tue Jun  2 18:49:26 2026
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Wed, 3 Jun 2026 09:49:26 +0800
Subject: [PATCH v2 7/8] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE
 and HAVE_LIVEPATCH
In-Reply-To: <20260528082310.1994388-8-wanghan@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
 <20260528082310.1994388-8-wanghan@linux.alibaba.com>
Message-ID: <a88b8245-04d1-41db-9507-aaddfbd8e042@linux.alibaba.com>



On 5/28/26 4:23 PM, Wang Han wrote:
> Now that the metadata frame records, the kunwind state machine and
> arch_stack_walk_reliable() are all in place, advertise the capability
> to the rest of the kernel:
> 
>    * select HAVE_RELIABLE_STACKTRACE under FRAME_POINTER && 64BIT, so
>      only the configurations that actually have the metadata records
>      and the FP-based reliable walker enable it.


The 64BIT gate is conservative scoping rather than a hard technical
requirement: the metadata frame record, kunwind state machine and
arch_stack_walk_reliable() all build on RV32 too (and the
call_on_irq_stack change in patch 2/8 actually fixes a latent RV32
issue). However, the syscall livepatch selftest and module relocation
path have only been exercised on RV64 (QEMU virt SMP=2/4/8). The
64BIT gate can be dropped in a follow-up once RV32 has equivalent
coverage.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai


From xueshuai at linux.alibaba.com  Tue Jun  2 18:54:25 2026
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Wed, 3 Jun 2026 09:54:25 +0800
Subject: [PATCH v2 8/8] selftests/livepatch: Add RISC-V syscall wrapper
 prefix
In-Reply-To: <20260528082310.1994388-9-wanghan@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
 <20260528082310.1994388-9-wanghan@linux.alibaba.com>
Message-ID: <1bb1f3e3-1cba-426c-aa70-d50df8114636@linux.alibaba.com>



On 5/28/26 4:23 PM, Wang Han wrote:
> The syscall livepatch selftest resolves and patches a syscall wrapper
> symbol. To use that test for RISC-V livepatch validation, add the
> RISC-V FN_PREFIX definition for ARCH_HAS_SYSCALL_WRAPPER.
> 
> Without this macro, the syscall livepatch selftest cannot resolve the
> RISC-V target symbol, and the syscall-related livepatch test fails on
> RISC-V.
> 
> Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
> ---
>   .../testing/selftests/livepatch/test_modules/test_klp_syscall.c | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c b/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c
> index dd802783ea84..275e4b10cf59 100644
> --- a/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c
> +++ b/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c
> @@ -18,6 +18,8 @@
>   #define FN_PREFIX __s390x_
>   #elif defined(__aarch64__)
>   #define FN_PREFIX __arm64_
> +#elif defined(__riscv)
> +#define FN_PREFIX __riscv_
>   #else
>   /* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER */
>   #define FN_PREFIX

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>

Thanks.
Shuai


From inochiama at gmail.com  Tue Jun  2 19:06:35 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Wed,  3 Jun 2026 10:06:35 +0800
Subject: [PATCH v2 0/2] riscv: dts: sophgo: Fix CPU unit address for SG2042/SG2044
In-Reply-To: <20260426013449.694435-1-inochiama@gmail.com>
References: <20260426013449.694435-1-inochiama@gmail.com>
Message-ID: <178045237640.222315.13582367282574161417.b4-ty@b4>

On Sun, 26 Apr 2026 09:34:47 +0800, Inochi Amaoto wrote:
> The CPU unit addres for SG2042/SG2044 misused the decimal number for the
> unit address, Refer to this discussion in the Link, it should be in the
> hex format.
> 
> Link: https://lore.kernel.org/devicetree-spec/00ddad5a-02f5-474e-af9c-11ce7716ddfc at iscas.ac.cn/
> 
> Change from v1:
> - https://lore.kernel.org/all/20260406232655.144043-1-inochiama at gmail.com
> 1. Apply Guo, Conor and Chen's tags.
> 2. Remove Link tag for all patches.
> 3. Fix comment for clarification about node name change for all patches.
> 
> [...]

Applied to for-next, thanks!

[1/2] riscv: dts: sophgo: sg2044: use hex for CPU unit address
      https://github.com/sophgo/linux/commit/207cbc477406a72952e27ace2eadbae55164f129
[2/2] riscv: dts: sophgo: sg2042: use hex for CPU unit address
      https://github.com/sophgo/linux/commit/a7e658907686528fe06a11828b04a3e42df9ef18

Thanks,
Inochi



From xueshuai at linux.alibaba.com  Tue Jun  2 19:10:44 2026
From: xueshuai at linux.alibaba.com (Shuai Xue)
Date: Wed, 3 Jun 2026 10:10:44 +0800
Subject: [PATCH v2 1/8] scripts/sorttable: Handle RISC-V patchable ftrace
 entries
In-Reply-To: <20260601095746.70c01d24@fedora>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
 <20260528082310.1994388-2-wanghan@linux.alibaba.com>
 <0a913398-3d0c-472e-89c4-062052eae04d@linux.alibaba.com>
 <20260601095746.70c01d24@fedora>
Message-ID: <6753385b-c2ab-4ed0-9400-78ce967450ba@linux.alibaba.com>



On 6/1/26 9:57 PM, Steven Rostedt wrote:
> On Mon, 1 Jun 2026 14:17:08 +0800
> Shuai Xue <xueshuai at linux.alibaba.com> wrote:
> 
>>> diff --git a/scripts/sorttable.c b/scripts/sorttable.c
>>> index e8ed11c680c6..4c10e85bb5af 100644
>>> --- a/scripts/sorttable.c
>>> +++ b/scripts/sorttable.c
>>> @@ -891,17 +891,21 @@ static int do_file(char const *const fname, void *addr)
>>>    	table_sort_t custom_sort = NULL;
>>>    
>>>    	switch (elf_map_machine(ehdr)) {
>>> -	case EM_AARCH64:
>>>    #ifdef MCOUNT_SORT_ENABLED
>>> +	case EM_AARCH64:
>>>    		sort_reloc = true;
>>>    		rela_type = 0x403;
>>> -		/* arm64 uses patchable function entry placing before function */
>>> +		/* fallthrough */
>>> +	case EM_RISCV:
>>> +		/* arm64 and RISC-V place patchable entries before the function */
>>>    		before_func = 8;
>>
>> Nit: The shared comment now sits under `case EM_RISCV:` but the two
>> lines above it (sort_reloc / rela_type = 0x403) are strictly
>> arm64-only ? they configure the RELA-based weak-function fixup that
>> RISC-V does not need. On a quick read it is easy to wonder if RISC-V
>> is implicitly inheriting that path. Splitting the comments would
>> help, e.g.:
>>
>>          case EM_AARCH64:
>>              /* arm64 needs RELA-based weak-function fixup */
>>              sort_reloc = true;
>>              rela_type = 0x403;
>>              /* fallthrough */
>>          case EM_RISCV:
>>              /* arm64 and RISC-V place patchable entries before the function */
>>              before_func = 8;
> 
> Makes sense.
> 
> Care to send a v3?
> 
> -- Steve

Hi, Steve,

It's a pure comment cosmetic, not worth a respin on its own. But for the
rest of the feedback on this series (the frame-record metadata contract
in patch 2 and the dead state->regs field / Call Trace output change in
patch 6) are the ones actually worth a new version.

Just to get the routing straight: are you planning to pick this one up
through the tracing tree on its own?

It feels like a good candidate for that -- it's an independent
regression fix (Fixes: 0ca1724b56af) that breaks *all* RISC-V dynamic
ftrace, not just livepatch, so it shouldn't have to wait on the rest of
the livepatch series.

Thanks.
Shuai




From inochiama at gmail.com  Tue Jun  2 19:10:49 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Wed,  3 Jun 2026 10:10:49 +0800
Subject: [PATCH] riscv: dts: sophgo: reduce SG2042 MSI count to 16
In-Reply-To: <20260407160143.1182430-1-zhengxingda@iscas.ac.cn>
References: <20260407160143.1182430-1-zhengxingda@iscas.ac.cn>
Message-ID: <178045263171.227355.8295224665627411486.b4-ty@b4>

On Wed, 08 Apr 2026 00:01:43 +0800, Icenowy Zheng wrote:
> The SG2042 MSI controller has one 32-bit doorbell register, and each bit
> corresponds to an interrupt. At a glance, it seems that the MSI
> controller can support 32 interrupts; however the PCI MSI capability
> only supports 16-bit messages, which makes the high 16 interrupts
> unusable in such way.
> 
> Reduce the MSI count to 16 to prevent producing MSI message values that
> cannot fit 16-bit integers.
> 
> [...]

Applied to for-next, thanks!

[1/1] riscv: dts: sophgo: reduce SG2042 MSI count to 16
      https://github.com/sophgo/linux/commit/903a9364e40563faf4730dc63ad7446246f494ff

Thanks,
Inochi



From zong.li at sifive.com  Tue Jun  2 19:34:23 2026
From: zong.li at sifive.com (Zong Li)
Date: Wed, 3 Jun 2026 10:34:23 +0800
Subject: [PATCH] riscv: cfi: reduce shadow stack size limit from 2GB to 512MB
In-Reply-To: <CANXhq0pfU1+Qv-SdJRzwvSDQw010+QovUH-OuG4tcwwsjf90MQ@mail.gmail.com>
References: <20260522093634.3530233-1-zong.li@sifive.com> <CANXhq0pfU1+Qv-SdJRzwvSDQw010+QovUH-OuG4tcwwsjf90MQ@mail.gmail.com>
Message-ID: <CANXhq0rwnhd0tOeOw+HG+F0YRfGDuoS0ek3ce1PP+nLN4M8Stw@mail.gmail.com>

> On Thu, May 28, 2026 at 9:07?AM Zong Li <zong.li at sifive.com> wrote:
> >
> > On Fri, May 22, 2026 at 5:36?PM Zong Li <zong.li at sifive.com> wrote:
> > >
> > > Change the shadow stack size calculation from RLIMIT_STACK/2 (capped at
> > > 2GB) to RLIMIT_STACK/8 (capped at 512MB), following David Laight's
> > > analysis and recommendation.
> > >
> > > Rationale:
> > >
> > > David Laight pointed out that the focus should be on the ratio between
> > > shadow stack size and the normal stack size, rather than just the
> > > absolute upper limit. His analysis showed that while there are many
> > > functions with small stack frames, the majority have stack deltas of
> > > over 64 bytes due to saved registers and local variables.
> > >
> > > Shadow stacks only store return addresses (8 bytes per entry on 64-bit
> > > systems), whereas normal stack frames typically consume 64+ bytes. This
> > > 8:64 byte ratio means that programs using a lot of stack space are
> > > dominated by large buffer allocations and local variables, not extreme
> > > recursion depths with minimal local data.
> > >
> > > For example, with the default RLIMIT_STACK of 8MB:
> > > - RLIMIT_STACK/2 gives a 4MB shadow stack supporting 512K nested calls
> > > - RLIMIT_STACK/8 gives a 1MB shadow stack supporting 128K nested calls
> > >
> > > Given typical stack frame sizes of 64+ bytes, RLIMIT_STACK/8 is still
> > > conservative and provides adequate depth for practical applications.
> > > David noted that this could even be safely halved again.
> > >
> > > This reduction also better accommodates memory-constrained platforms.
> > > On systems with limited physical memory, allocating large shadow stacks
> > > can cause virtual memory allocation failures when overcommit mode is set
> > > to OVERCOMMIT_GUESS or OVERCOMMIT_NEVER.
> > >
> >
> > Adding Mark, Szabolcs and Catalin to this thread.
> >
> > I noticed your previous discussions about the shadow stack size in the
> > ARM64 GCS patch series. I see that the GCS size was eventually reduced
> > from 4G to 2G.
> >
> > Because the RISC-V shadow stack stores very similar data to GCS, I
> > also reduced the RISC-V shadow stack size to 2G in my recent patch.
> > You can find the reasons for this change here:
> > https://lists.infradead.org/pipermail/linux-riscv/2026-May/091308.html
> >
> > In the same thread, we discussed if we could make the size even
> > smaller. Thank David for his helpful analysis on this topic.
> >
> > Since GCS has been merged for a few years now, we'd like to learn from
> > your experience. We want to make sure we are not missing any important
> > impacts or issues. Therefore, we would really appreciate it if you
> > could share your thoughts with us. This will give us the confidence to
> > move forward with the patch
> >
> > Thanks
> >
> >
> Nobody has reported it causing them a problem, but there's not really
> much practical use yet due to hardware availability so that might change
> and I'm not sure how much inference you can draw there - there is much
> more test use than production use at this stage.  I would be astonished
> if anyone wanted the shadow stack to be bigger, the more likely problem
> is excessive VA usage but we felt it was better to err on the side of
> using too much memory.  The general feedback from userspace people was
> that they weren't too concerned about issues.

Hi Mark,
Sorry for the delayed response; for some reason, your previous email
didn't show up in my inbox. I pasted your message above.

Thank you very much for sharing your valuable experience with GCS.
Based on your insights and our current considerations, Perhaps it is
possible for us to try changing it to 512MB first.This will allow us
to successfully enable the shadow stack on a memory-constrained
platform.

Thanks again for your help!

> >
> > > Suggested-by: David Laight <david.laight.linux at gmail.com>
> > > Link: https://lore.kernel.org/all/20260518105725.7afe7a4c at pumpkin/
> > > Signed-off-by: Zong Li <zong.li at sifive.com>
> > > ---
> > >  arch/riscv/kernel/usercfi.c | 4 ++--
> > >  1 file changed, 2 insertions(+), 2 deletions(-)
> > >
> > > diff --git a/arch/riscv/kernel/usercfi.c b/arch/riscv/kernel/usercfi.c
> > > index cbfb4e495e9f..adf97426a906 100644
> > > --- a/arch/riscv/kernel/usercfi.c
> > > +++ b/arch/riscv/kernel/usercfi.c
> > > @@ -110,7 +110,7 @@ void set_indir_lp_lock(struct task_struct *task, bool lock)
> > >  }
> > >  /*
> > >   * The shadow stack only stores the return address and not any variables
> > > - * this should be more than sufficient for most applications.
> > > + * 512M should be more than sufficient for most applications.
> > >   * Else PAGE_ALIGN it and return back
> > >   */
> > >  static unsigned long calc_shstk_size(unsigned long size)
> > > @@ -118,7 +118,7 @@ static unsigned long calc_shstk_size(unsigned long size)
> > >         if (size)
> > >                 return PAGE_ALIGN(size);
> > >
> > > -       return PAGE_ALIGN(min(rlimit(RLIMIT_STACK) / 2, SZ_2G));
> > > +       return PAGE_ALIGN(min(rlimit(RLIMIT_STACK) / 8, SZ_512M));
> > >  }
> > >
> > >  /*
> > > --
> > > 2.43.7
> > >


From qirui.001 at bytedance.com  Tue Jun  2 20:53:05 2026
From: qirui.001 at bytedance.com (Rui Qi)
Date: Wed,  3 Jun 2026 11:53:05 +0800
Subject: [PATCH] riscv: fix frame pointer in call_on_irq_stack for RV32
Message-ID: <20260603035305.564823-1-qirui.001@bytedance.com>

The frame pointer (s0/fp) in call_on_irq_stack is set using
STACKFRAME_SIZE_ON_STACK, which equals ALIGN(sizeof(struct stackframe),
STACK_ALIGN). On RV64, sizeof(struct stackframe) is 16 and the aligned
size is also 16, so there is no difference. However, on RV32,
sizeof(struct stackframe) is 8 while STACKFRAME_SIZE_ON_STACK is 16 due
to 8 bytes of alignment padding.

The stack unwinder does 'frame = (struct stackframe *)fp - 1', which
reads from 'fp - sizeof(struct stackframe)'. On RV32, with fp set to
sp + STACKFRAME_SIZE_ON_STACK (sp + 16), the unwinder reads from
sp + 8, which falls in the alignment padding rather than where the
saved fp/ra are actually stored (sp + 0 and sp + 4).

Fix this by introducing STACKFRAME_SIZE (the unaligned sizeof) and using
it for frame pointer setup and restoration, while keeping
STACKFRAME_SIZE_ON_STACK for the stack pointer allocation/deallocation
which must remain 16-byte aligned.

Signed-off-by: Rui Qi <qirui.001 at bytedance.com>
---
 arch/riscv/kernel/asm-offsets.c | 1 +
 arch/riscv/kernel/entry.S       | 4 ++--
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index af827448a609..c1b5f7eb03fd 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -500,6 +500,7 @@ void asm_offsets(void)
 	OFFSET(SBI_HART_BOOT_TASK_PTR_OFFSET, sbi_hart_boot_data, task_ptr);
 	OFFSET(SBI_HART_BOOT_STACK_PTR_OFFSET, sbi_hart_boot_data, stack_ptr);
 
+	DEFINE(STACKFRAME_SIZE, sizeof(struct stackframe));
 	DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe), STACK_ALIGN));
 	OFFSET(STACKFRAME_FP, stackframe, fp);
 	OFFSET(STACKFRAME_RA, stackframe, ra);
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index d011fb51c59a..e8b654e2b7b5 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -383,7 +383,7 @@ SYM_FUNC_START(call_on_irq_stack)
 	addi	sp, sp, -STACKFRAME_SIZE_ON_STACK
 	REG_S	ra, STACKFRAME_RA(sp)
 	REG_S	s0, STACKFRAME_FP(sp)
-	addi	s0, sp, STACKFRAME_SIZE_ON_STACK
+	addi	s0, sp, STACKFRAME_SIZE
 
 	/* Switch to the per-CPU shadow call stack */
 	scs_save_current
@@ -399,7 +399,7 @@ SYM_FUNC_START(call_on_irq_stack)
 	scs_load_current
 
 	/* Switch back to the thread stack and restore ra and s0 */
-	addi	sp, s0, -STACKFRAME_SIZE_ON_STACK
+	addi	sp, s0, -STACKFRAME_SIZE
 	REG_L	ra, STACKFRAME_RA(sp)
 	REG_L	s0, STACKFRAME_FP(sp)
 	addi	sp, sp, STACKFRAME_SIZE_ON_STACK
-- 
2.20.1


From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:27 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:27 -0700
Subject: [PATCH v3 01/21] dt-bindings: pincfg-node: Add property 'input-debounce-ns'
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-2-changhuang.liang@starfivetech.com>

Add the property 'input-debounce-ns' to specify debounce time in
nanoseconds as an alternative to the existing 'input-debounce' which
uses microseconds. Make the new property unavailable when the existing
property 'input-debounce' is selected to prevent conflicting definitions.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../devicetree/bindings/pinctrl/pincfg-node.yaml      | 11 +++++++++++
 1 file changed, 11 insertions(+)

diff --git a/Documentation/devicetree/bindings/pinctrl/pincfg-node.yaml b/Documentation/devicetree/bindings/pinctrl/pincfg-node.yaml
index 97dbce8a261f..17a6270dce31 100644
--- a/Documentation/devicetree/bindings/pinctrl/pincfg-node.yaml
+++ b/Documentation/devicetree/bindings/pinctrl/pincfg-node.yaml
@@ -104,6 +104,10 @@ properties:
     description: Takes the debounce time in usec as argument or 0 to disable
       debouncing
 
+  input-debounce-ns:
+    description: Takes the debounce time in nsec as argument or 0 to disable
+      debouncing
+
   power-source:
     $ref: /schemas/types.yaml#/definitions/uint32
     description: select between different power supplies
@@ -214,6 +218,13 @@ allOf:
         input-schmitt-enable: false
         input-schmitt-microvolt: false
 
+  - if:
+      required:
+        - input-debounce
+    then:
+      properties:
+        input-debounce-ns: false
+
   - if:
       required:
         - drive-strength
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:29 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:29 -0700
Subject: [PATCH v3 03/21] dt-bindings: pinctrl: Add starfive,jhb100-sys0-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-4-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC System-0(sys0) pinctrl
controller.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../pinctrl/starfive,jhb100-sys0-pinctrl.yaml | 161 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  17 ++
 2 files changed, 178 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0-pinctrl.yaml
 create mode 100644 include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0-pinctrl.yaml
new file mode 100644
index 000000000000..1baaeefdd090
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0-pinctrl.yaml
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-sys0-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 System-0 Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "sys0" pinctrl domain.
+
+  The "sys0" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO pad configuration.
+  - GPIO interrupt handling.
+
+  In the SYS0 Pin Controller, there are 4 multi-function GPIO_PADs. Each of
+  them can be multiplexed to different hardware blocks through function
+  selection and each iopad has a maximum of up to 2 functions - 0 and 1.
+  Function 0 is the default function which is generally the GPIO function
+  (or occasionally, it can be a peripheral signal).
+  Function 1 is the alternate function or peripheral signal that can be
+  routed to the iopad. The function selection is carried out by writing
+  the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds.
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-sys0-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce and
+          drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ auxpwrgood, gpio, hbled, pe2rst_out ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            type: boolean
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+
+required:
+  - compatible
+  - reg
+  - resets
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_sys0: pinctrl at 13080000 {
+            compatible = "starfive,jhb100-sys0-pinctrl";
+            reg = <0x0 0x13080000 0x0 0x800>;
+            resets = <&sys0crg 2>;
+            interrupts = <56>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_sys0 0 0 0 4>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
new file mode 100644
index 000000000000..6d8f5516a178
--- /dev/null
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 OR MIT */
+/*
+ * Copyright (C) 2022 StarFive Technology Co., Ltd.
+ *
+ * Author: Changhuang Liang <changhuang.liang at starfivetech.com>
+ */
+
+#ifndef __DT_BINDINGS_PINCTRL_STARFIVE_JHB100_H__
+#define __DT_BINDINGS_PINCTRL_STARFIVE_JHB100_H__
+
+/* sys0 pad numbers */
+#define PADNUM_SYS0_GPIO_A0				0
+#define PADNUM_SYS0_GPIO_A1				1
+#define PADNUM_SYS0_GPIO_A2				2
+#define PADNUM_SYS0_GPIO_A3				3
+
+#endif
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:26 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:26 -0700
Subject: [PATCH v3 00/21] Add basic pinctrl drivers for JHB100 SoC
Message-ID: <20260603055347.66845-1-changhuang.liang@starfivetech.com>

The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
per2, per2pok, per3, adc0, adc1, emmc, and vga.

In the current series, we will only add the following pinctrl:
 - sys0, sys0h, sys1, sys2
 - per0, per1, per2, per2pok, per3

The remaining pinctrl will be implemented in future series.

This series depends on the series:
https://lore.kernel.org/all/20260508053632.818548-1-changhuang.liang at starfivetech.com/

Change since v2:
- Remove v2 PATCH 3

PATCH 1/2:
- Replace input-debounce-nanoseconds with input-debounce-ns.

PATCH 4/6/8/10/12/14/16/18/20:
- Replace unevaluatedProperties with additionalProperties.
- Add the description for power-source.

PATCH 5:
- `jhb100_pinconf_group_set()` invokes `jhb100_pinconf_set()` to
  reduce redundant code.
- Add `jhb100_pincfg_pin_vref_set()` to handle pin voltage configuration.

PATCH 7/9/11/13/15/17/19/21:
- Add `numpv` to record the number of elements in the `struct pinvref_desc` array.
- Remove the `name` member of `struct pinvref_desc`.

PATCH 22:
- Replace the pin group voltage configuration with individual
  pin power-source configurations.

v2: https://lore.kernel.org/all/20260514111218.94519-1-changhuang.liang at starfivetech.com/
v1: https://lore.kernel.org/all/20260424111330.702272-1-changhuang.liang at starfivetech.com/

Changhuang Liang (21):
  dt-bindings: pincfg-node: Add property 'input-debounce-ns'
  pinctrl: pinconf-generic: Add property 'input-debounce-ns'
  dt-bindings: pinctrl: Add starfive,jhb100-sys0-pinctrl
  pinctrl: starfive: Add StarFive JHB100 sys0 controller driver
  dt-bindings: pinctrl: Add starfive,jhb100-sys0h-pinctrl
  pinctrl: starfive: Add StarFive JHB100 sys0h controller driver
  dt-bindings: pinctrl: Add starfive,jhb100-sys1-pinctrl
  pinctrl: starfive: Add StarFive JHB100 sys1 controller driver
  dt-bindings: pinctrl: Add starfive,jhb100-sys2-pinctrl
  pinctrl: starfive: Add StarFive JHB100 sys2 controller driver
  dt-bindings: pinctrl: Add starfive,jhb100-per0-pinctrl
  pinctrl: starfive: Add StarFive JHB100 per0 controller driver
  dt-bindings: pinctrl: Add starfive,jhb100-per1-pinctrl
  pinctrl: starfive: Add StarFive JHB100 per1 controller driver
  dt-bindings: pinctrl: Add starfive,jhb100-per2-pinctrl
  pinctrl: starfive: Add StarFive JHB100 per2 controller driver
  dt-bindings: pinctrl: Add starfive,jhb100-per2pok-pinctrl
  pinctrl: starfive: Add StarFive JHB100 per2pok controller driver
  dt-bindings: pinctrl: Add starfive,jhb100-per3-pinctrl
  pinctrl: starfive: Add StarFive JHB100 per3 controller driver
  riscv: dts: starfive: jhb100: Add pinctrl nodes

 .../bindings/pinctrl/pincfg-node.yaml         |   11 +
 .../pinctrl/starfive,jhb100-per0-pinctrl.yaml |  179 ++
 .../pinctrl/starfive,jhb100-per1-pinctrl.yaml |  178 ++
 .../pinctrl/starfive,jhb100-per2-pinctrl.yaml |  168 ++
 .../starfive,jhb100-per2pok-pinctrl.yaml      |  159 ++
 .../pinctrl/starfive,jhb100-per3-pinctrl.yaml |  165 ++
 .../pinctrl/starfive,jhb100-sys0-pinctrl.yaml |  161 ++
 .../starfive,jhb100-sys0h-pinctrl.yaml        |  160 ++
 .../pinctrl/starfive,jhb100-sys1-pinctrl.yaml |  161 ++
 .../pinctrl/starfive,jhb100-sys2-pinctrl.yaml |  169 ++
 MAINTAINERS                                   |    9 +
 arch/riscv/boot/dts/starfive/jhb100-evb1.dts  |    3 +
 .../boot/dts/starfive/jhb100-pinctrl.dtsi     |   23 +
 arch/riscv/boot/dts/starfive/jhb100.dtsi      |  110 ++
 drivers/pinctrl/pinconf-generic.c             |    2 +
 drivers/pinctrl/starfive/Kconfig              |  115 ++
 drivers/pinctrl/starfive/Makefile             |   11 +
 .../starfive/pinctrl-starfive-jhb100-per0.c   |  154 ++
 .../starfive/pinctrl-starfive-jhb100-per1.c   |  165 ++
 .../starfive/pinctrl-starfive-jhb100-per2.c   |  126 ++
 .../pinctrl-starfive-jhb100-per2pok.c         |   97 +
 .../starfive/pinctrl-starfive-jhb100-per3.c   |  119 ++
 .../starfive/pinctrl-starfive-jhb100-sys0.c   |  123 ++
 .../starfive/pinctrl-starfive-jhb100-sys0h.c  |   97 +
 .../starfive/pinctrl-starfive-jhb100-sys1.c   |   93 +
 .../starfive/pinctrl-starfive-jhb100-sys2.c   |  134 ++
 .../starfive/pinctrl-starfive-jhb100.c        | 1607 +++++++++++++++++
 .../starfive/pinctrl-starfive-jhb100.h        |  152 ++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  252 +++
 include/linux/pinctrl/pinconf-generic.h       |    5 +
 30 files changed, 4908 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per0-pinctrl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per1-pinctrl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2-pinctrl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2pok-pinctrl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per3-pinctrl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0-pinctrl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0h-pinctrl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys1-pinctrl.yaml
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys2-pinctrl.yaml
 create mode 100644 arch/riscv/boot/dts/starfive/jhb100-pinctrl.dtsi
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per0.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per1.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2pok.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per3.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0h.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys1.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys2.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h
 create mode 100644 include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h

--
2.25.1


From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:43 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:43 -0700
Subject: [PATCH v3 17/21] dt-bindings: pinctrl: Add starfive,jhb100-per2pok-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-18-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC Peripheral-2 Power OK
(per2pok) pinctrl controller.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../starfive,jhb100-per2pok-pinctrl.yaml      | 159 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  20 +++
 2 files changed, 179 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2pok-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2pok-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2pok-pinctrl.yaml
new file mode 100644
index 000000000000..0a6cd9b7fb5e
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2pok-pinctrl.yaml
@@ -0,0 +1,159 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-per2pok-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 Peripheral-2 Power OK Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "bper2pok" pinctrl domain.
+
+  The "per2pok" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO interrupt handling.
+
+  In the Peripheral-2 Power OK Pin Controller, there are 18 multi-function
+  GPIO_PADs. Each can be multiplexed to several peripherals through function
+  selection. Each iopad has a maximum of up to 4 functions - 0, 1, 2, and 3.
+  Function 0 is the default function or generally the GPIO function.
+  Function 1, 2, and 3 are alternate functions or peripheral signals that can
+  routed to an iopad. The function selection can be carried out by writing
+  the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds.
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-per2pok-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce nanoseconds
+          and drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ can, gpio, host0_port80, host1_port80, passthru, pwm ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            type: boolean
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+
+required:
+  - compatible
+  - reg
+  - resets
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_per2pok: pinctrl at 11bc2400 {
+            compatible = "starfive,jhb100-per2pok-pinctrl";
+            reg = <0x0 0x11bc2400 0x0 0x400>;
+            resets = <&per2crg 1>;
+            interrupts = <63>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_per2pok 0 0 0 18>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
index 7aeebcf72b8f..3ceaf9ceeecb 100644
--- a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -210,6 +210,26 @@
 #define PADNUM_PER2_GPIO_D29				29
 #define PADNUM_PER2_GPIO_D30				30
 
+/* per2pok pad numbers */
+#define PADNUM_PER2POK_GPIO_D31				0
+#define PADNUM_PER2POK_GPIO_D32				1
+#define PADNUM_PER2POK_GPIO_D33				2
+#define PADNUM_PER2POK_GPIO_D34				3
+#define PADNUM_PER2POK_GPIO_D35				4
+#define PADNUM_PER2POK_GPIO_D36				5
+#define PADNUM_PER2POK_GPIO_D37				6
+#define PADNUM_PER2POK_GPIO_D38				7
+#define PADNUM_PER2POK_GPIO_D39				8
+#define PADNUM_PER2POK_GPIO_D40				9
+#define PADNUM_PER2POK_GPIO_D41				10
+#define PADNUM_PER2POK_GPIO_D42				11
+#define PADNUM_PER2POK_GPIO_D43				12
+#define PADNUM_PER2POK_GPIO_D44				13
+#define PADNUM_PER2POK_GPIO_D45				14
+#define PADNUM_PER2POK_GPIO_D46				15
+#define PADNUM_PER2POK_GPIO_D47				16
+#define PADNUM_PER2POK_GPIO_D48				17
+
 /* power-source value */
 #define JHB100_PINVREF_3_3V				0
 #define JHB100_PINVREF_2_5V				1
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:34 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:34 -0700
Subject: [PATCH v3 08/21] pinctrl: starfive: Add StarFive JHB100 sys1 controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-9-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC System-1(sys1) pinctrl
controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/starfive/Kconfig              | 12 +++
 drivers/pinctrl/starfive/Makefile             |  1 +
 .../starfive/pinctrl-starfive-jhb100-sys1.c   | 93 +++++++++++++++++++
 3 files changed, 106 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys1.c

diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index 1c87f64830ed..882d621eaf57 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -78,3 +78,15 @@ config PINCTRL_STARFIVE_JHB100_SYS0H
           This also provides an interface to the GPIO pins not used by other
           peripherals supporting inputs, outputs, configuring pull-up/pull-down
           and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JHB100_SYS1
+	tristate "StarFive JHB100 SoC System-1 pinctrl and GPIO driver"
+	depends on ARCH_STARFIVE  || COMPILE_TEST
+	depends on OF
+	select PINCTRL_STARFIVE_JHB100
+	default ARCH_STARFIVE
+	help
+	  Say yes here to support System-1 pin control on the StarFive JHB100 SoC.
+	  This also provides an interface to the GPIO pins not used by other
+	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
+	  and interrupts on input changes.
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index b26156a6d0eb..8d96cf80d377 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -9,3 +9,4 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON)	+= pinctrl-starfive-jh7110-aon.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)		+= pinctrl-starfive-jhb100.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0H)	+= pinctrl-starfive-jhb100-sys0h.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS1)	+= pinctrl-starfive-jhb100-sys1.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys1.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys1.c
new file mode 100644
index 000000000000..84ca7b33a5a4
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys1.c
@@ -0,0 +1,93 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC System-1 domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_sys1_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 7, .name = "gpio", .gpio_func_sel = 0 },
+	{ .pin_start = 7, .pin_cnt = 1, .name = "espi1_reset", .gpio_func_sel = 1 },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_sys1_pinctrl_rl_desc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 8,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 8 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{ 0xff },
+};
+
+struct starfive_pinctrl_regs jhb100_sys1_pinctrl_regs = {
+	.func_sel		= { .reg = 0x30, .width_per_pin = 2 },
+	.config			= 0x04,
+	.output			= 0x24,
+	.output_en		= 0x28,
+	.gpio_status		= 0x2c,
+	.irq_en			= 0x34,
+	.irq_status		= 0x38,
+	.irq_clr		= 0x3c,
+	.irq_trigger		= 0x40,
+	.irq_level		= 0x44,
+	.irq_both_edge		= 0x48,
+	.irq_edge		= 0x4c,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_sys1[] = {
+	{ .func = "espi",		.val = 1 },
+	{ .func = "espi_reset",		.val = 0 },
+	{ .func = "gpio",		.val = 0,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_SYS1_GPIO_A22) },
+	{ .func = "gpio",		.val = 1,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_SYS1_GPIO_A23) },
+	{ .func = "host0_port80",	.val = 2 },
+	{ .func = "host1_port80",	.val = 3 },
+};
+
+static const struct jhb100_pinctrl_domain_info jhb100_sys1_pinctrl_info = {
+	.name			= "jhb100-sys1",
+	.pl_desc		= jhb100_sys1_pl_desc,
+	.crl_desc		= jhb100_sys1_pinctrl_rl_desc,
+	.regs			= &jhb100_sys1_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_sys1,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_sys1),
+};
+
+static const struct of_device_id jhb100_sys1_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-sys1-pinctrl",
+		.data = &jhb100_sys1_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_sys1_pinctrl_of_match);
+
+static struct platform_driver jhb100_sys1_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-sys1-pinctrl",
+		.of_match_table = jhb100_sys1_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_sys1_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC System-1 domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:31 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:31 -0700
Subject: [PATCH v3 05/21] dt-bindings: pinctrl: Add starfive,jhb100-sys0h-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-6-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC System-0 host(sys0h) pinctrl
controller.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../starfive,jhb100-sys0h-pinctrl.yaml        | 160 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  14 ++
 2 files changed, 174 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0h-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0h-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0h-pinctrl.yaml
new file mode 100644
index 000000000000..7e704401dbeb
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys0h-pinctrl.yaml
@@ -0,0 +1,160 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-sys0h-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 System-0 Host Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "sys0h" pinctrl domain.
+
+  The "sys0h" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO pad configuration.
+  - GPIO interrupt handling.
+
+  In the SYS0H Pin Controller, there are 12 multi-function GPIO_PADs. Each of
+  them can be multiplexed to different hardware blocks through function
+  selection. Each iopad has a maximum of up to 3 functions - 0, 1, 2, and 3.
+  Function 0 is the default function which is generally the GPIO function
+  (or occasionally, it can be a peripheral signal).
+  Functions 1, 2, and 3 are the alternate functions or peripheral signals that
+  can be routed to the iopad. The function selection can be carried out by
+  writing the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds.
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-sys0h-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce nanoseconds and
+          drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ espi, espi_reset, espi0_vw, espi1_vw, gpio, scap_trigger ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            type: boolean
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+required:
+  - compatible
+  - reg
+  - resets
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_sys0h: pinctrl at 13080800 {
+            compatible = "starfive,jhb100-sys0h-pinctrl";
+            reg = <0x0 0x13080800 0x0 0x800>;
+            resets = <&sys0crg 3>;
+            interrupts = <57>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_sys0h 0 0 0 12>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
index 6d8f5516a178..38d5a94e92e3 100644
--- a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -14,4 +14,18 @@
 #define PADNUM_SYS0_GPIO_A2				2
 #define PADNUM_SYS0_GPIO_A3				3
 
+/* sys0h pad numbers */
+#define PADNUM_SYS0H_GPIO_A4				0
+#define PADNUM_SYS0H_GPIO_A5				1
+#define PADNUM_SYS0H_GPIO_A6				2
+#define PADNUM_SYS0H_GPIO_A7				3
+#define PADNUM_SYS0H_GPIO_A8				4
+#define PADNUM_SYS0H_GPIO_A9				5
+#define PADNUM_SYS0H_GPIO_A10				6
+#define PADNUM_SYS0H_GPIO_A11				7
+#define PADNUM_SYS0H_GPIO_A12				8
+#define PADNUM_SYS0H_GPIO_A13				9
+#define PADNUM_SYS0H_GPIO_A14				10
+#define PADNUM_SYS0H_GPIO_A15				11
+
 #endif
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:30 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:30 -0700
Subject: [PATCH v3 04/21] pinctrl: starfive: Add StarFive JHB100 sys0 controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-5-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC System-0(sys0) pinctrl
controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 MAINTAINERS                                   |    9 +
 drivers/pinctrl/starfive/Kconfig              |   19 +
 drivers/pinctrl/starfive/Makefile             |    3 +
 .../starfive/pinctrl-starfive-jhb100-sys0.c   |  123 ++
 .../starfive/pinctrl-starfive-jhb100.c        | 1607 +++++++++++++++++
 .../starfive/pinctrl-starfive-jhb100.h        |  152 ++
 6 files changed, 1913 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 47e4b368347f..f56721b4cbd1 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -25607,6 +25607,15 @@ S:	Supported
 F:	Documentation/devicetree/bindings/interrupt-controller/starfive,jhb100-intc.yaml
 F:	drivers/irqchip/irq-starfive-jhb100-intc.c
 
+STARFIVE JHB100 PINCTRL DRIVERS
+M:	Changhuang Liang <changhuang.liang at starfivetech.com>
+M:	Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
+L:	linux-gpio at vger.kernel.org
+S:	Maintained
+F:	Documentation/devicetree/bindings/pinctrl/starfive,jhb1*.yaml
+F:	drivers/pinctrl/starfive/pinctrl-starfive-jhb1*
+F:	include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+
 STARFIVE JHB100 RESET CONTROLLER DRIVERS
 M:	Changhuang Liang <changhuang.liang at starfivetech.com>
 S:	Maintained
diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index a9a7cb101684..548a1b133f81 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -47,3 +47,22 @@ config PINCTRL_STARFIVE_JH7110_AON
 	  This also provides an interface to the GPIO pins not used by other
 	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
 	  and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JHB100
+	bool
+	select GENERIC_PINCTRL
+	select GPIOLIB
+	select GPIOLIB_IRQCHIP
+	select OF_GPIO
+
+config PINCTRL_STARFIVE_JHB100_SYS0
+	tristate "StarFive JHB100 SoC System-0 pinctrl and GPIO driver"
+	depends on ARCH_STARFIVE || COMPILE_TEST
+	depends on OF
+	select PINCTRL_STARFIVE_JHB100
+	default ARCH_STARFIVE
+	help
+	  Say yes here to support system-0 pin control on the StarFive JHB100 SoC.
+	  This also provides an interface to the GPIO pins not used by other
+	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
+	  and interrupts on input changes.
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index ee0d32d085cb..c0d368f413bc 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -5,3 +5,6 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7100)	+= pinctrl-starfive-jh7100.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JH7110)		+= pinctrl-starfive-jh7110.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_SYS)	+= pinctrl-starfive-jh7110-sys.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON)	+= pinctrl-starfive-jh7110-aon.o
+
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)		+= pinctrl-starfive-jhb100.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c
new file mode 100644
index 000000000000..d86a82eb5e05
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC System-0 domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_sys0_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 3, .name = "gpio", .gpio_func_sel = 0, },
+	{ .pin_start = 3, .pin_cnt = 1, .name = "bmcpcierp_pe2rst_out", .gpio_func_sel = 1, },
+	{ .pin_start = 4, .pin_cnt = 1, .name = "testen", .gpio_func_sel = -1, },
+	{ .pin_start = 5, .pin_cnt = 1, .name = "syspok_in", .gpio_func_sel = -1, },
+	{ .pin_start = 6, .pin_cnt = 1, .name = "sysrstn_in", .gpio_func_sel = -1, },
+	{ .pin_start = 7, .pin_cnt = 1, .name = "perstn0_in", .gpio_func_sel = -1, },
+	{ .pin_start = 8, .pin_cnt = 1, .name = "perstn1_in", .gpio_func_sel = -1, },
+	{ .pin_start = 9, .pin_cnt = 1, .name = "aprstn_out", .gpio_func_sel = -1, },
+	{ .pin_start = 10, .pin_cnt = 1, .name = "pcierp_wake", .gpio_func_sel = -1, },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_sys0_pinctrl_crl_desc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 4,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 8 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{
+		.pin_start			= 4,
+		.pin_cnt			= 5,
+		.schmitt_trigger_select		= { .shift = 0, .width = 1 },
+		.reserved			= { .shift = 1, .width = 31 },
+	},
+	{
+		.pin_start			= 9,
+		.pin_cnt			= 1,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.slew_rate			= { .shift = 2, .width = 1 },
+		.reserved			= { .shift = 3, .width = 29 },
+	},
+	{
+		.pin_start			= 10,
+		.pin_cnt			= 1,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 25 },
+	},
+	{ 0xff },
+};
+
+struct starfive_pinctrl_regs jhb100_sys0_pinctrl_regs = {
+	.func_sel		= { .reg = 0x44, .width_per_pin = 2 },
+	.config			= 0x0c,
+	.output			= 0x38,
+	.output_en		= 0x3c,
+	.gpio_status		= 0x40,
+	.irq_en			= 0x48,
+	.irq_status		= 0x4c,
+	.irq_clr		= 0x50,
+	.irq_trigger		= 0x54,
+	.irq_level		= 0x58,
+	.irq_both_edge		= 0x5c,
+	.irq_edge		= 0x60,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_sys0[] = {
+	{ .func = "auxpwrgood",		.val = 1 },
+	{ .func = "gpio",		.val = 0,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER3_GPIO_E2) },
+	{ .func = "gpio",		.val = 1,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER3_GPIO_E3) },
+	{ .func = "hbled",		.val = 1 },
+	{ .func = "pe2rst_out",		.val = 0 },
+};
+
+static const struct jhb100_pinctrl_domain_info jhb100_sys0_pinctrl_info = {
+	.name			= "jhb100-sys0",
+	.pl_desc		= jhb100_sys0_pl_desc,
+	.crl_desc		= jhb100_sys0_pinctrl_crl_desc,
+	.regs			= &jhb100_sys0_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_sys0,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_sys0),
+};
+
+static const struct of_device_id jhb100_sys0_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-sys0-pinctrl",
+		.data = &jhb100_sys0_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_sys0_pinctrl_of_match);
+
+static struct platform_driver jhb100_sys0_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-sys0-pinctrl",
+		.of_match_table = jhb100_sys0_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_sys0_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC System-0 domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
new file mode 100644
index 000000000000..52b97870b991
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
@@ -0,0 +1,1607 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/gpio/driver.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/minmax.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/seq_file.h>
+#include <linux/spinlock.h>
+#include <linux/string.h>
+#include <linux/sort.h>
+
+#include <linux/pinctrl/consumer.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+
+#include "../core.h"
+#include "../pinconf.h"
+#include "../pinctrl-utils.h"
+#include "../pinmux.h"
+#include "pinctrl-starfive-jhb100.h"
+
+#define GPOUT_LOW				0
+#define GPOUT_HIGH				1
+
+#define GPOEN_ENABLE				0
+#define GPOEN_DISABLE				1
+
+#define JHB100_DEBOUNCE_WIDTH_STAGES_MAX	0x1FFFFU
+#define JHB100_DEBOUNCE_WIDTH_STAGE_NS		80
+
+/* mode select */
+#define JHB100_PUSH_PULL			0
+#define JHB100_OPEN_DRAIN			1
+#define JHB100_LEGACY_FAST_MODE_PLUS		2
+#define JHB100_LEGACY_FAST_MODE			3
+
+/* i2c open-drain pull-up select */
+#define JHB100_I2C_OPEN_DRAIN_PU_600_OHMS	0
+#define JHB100_I2C_OPEN_DRAIN_PU_900_OHMS	1
+#define JHB100_I2C_OPEN_DRAIN_PU_1200_OHMS	2
+#define JHB100_I2C_OPEN_DRAIN_PU_2000_OHMS	3
+
+#define JHB100_NR_GPIOS_PER_BANK		32
+
+struct field_info {
+	const char *name;
+	unsigned int shift;
+	unsigned int width;
+	unsigned int end;
+};
+
+static int jhb100_map_get_func_val(struct jhb100_pinctrl *sfp, const char *function,
+				   unsigned int pin)
+{
+	const struct jhb100_pinctrl_func_maps *fmaps = sfp->info->fmaps;
+	size_t num = sfp->info->num_maps;
+
+	for (int i = 0; i < num; i++) {
+		if (!strcmp(function, fmaps[i].func)) {
+			if (!fmaps[i].max_pin)
+				return fmaps[i].val;
+
+			if (pin < fmaps[i].max_pin)
+				return fmaps[i].val;
+
+			continue;
+		}
+	}
+
+	return -EINVAL;
+}
+
+static struct config_reg_layout_desc *get_crl_desc_by_pin(struct jhb100_pinctrl *sfp,
+							  unsigned int pin)
+{
+	struct config_reg_layout_desc *crl_desc = sfp->info->crl_desc;
+	unsigned int i = 0;
+
+	do {
+		if (pin >= crl_desc[i].pin_start &&
+		    pin < crl_desc[i].pin_start + crl_desc[i].pin_cnt)
+			return &crl_desc[i];
+	} while (crl_desc[i++].pin_start != 0xff);
+
+	return NULL;
+}
+
+static inline struct jhb100_gpio_bank *jhb100_gc_to_bank(struct gpio_chip *gc)
+{
+	return container_of(gc, struct jhb100_gpio_bank, gc);
+}
+
+static unsigned int jhb100_gpio_to_pin(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+
+	return bank->id * JHB100_NR_GPIOS_PER_BANK + gpio;
+}
+
+static const struct pinctrl_ops jhb100_pinctrl_ops = {
+	.get_groups_count = pinctrl_generic_get_group_count,
+	.get_group_name	  = pinctrl_generic_get_group_name,
+	.get_group_pins   = pinctrl_generic_get_group_pins,
+	.dt_node_to_map	  = pinctrl_generic_pins_function_dt_node_to_map,
+	.dt_free_map	  = pinctrl_utils_free_map,
+};
+
+static void jhb100_set_gpioval(struct jhb100_pinctrl *sfp, unsigned int pin,
+			       unsigned int val)
+{
+	const struct jhb100_pinctrl_domain_info *info = sfp->info;
+	unsigned int offset = 4 * (pin / 32);
+	unsigned int shift = 1 * (pin % 32);
+	unsigned int fs_offset = 4 * (pin / 16);
+	unsigned int fs_shift = 2 * (pin % 16);
+	u32 func_sel_mask;
+	u32 dout, doen, fs;
+	void __iomem *reg_gpio_o;
+	void __iomem *reg_gpio_oen;
+	void __iomem *reg_gpio_func_sel;
+	unsigned long flags;
+
+	reg_gpio_o = sfp->base + info->regs->output + offset;
+	reg_gpio_oen = sfp->base + info->regs->output_en + offset;
+	reg_gpio_func_sel = sfp->base + info->regs->func_sel.reg + fs_offset;
+
+	func_sel_mask = GENMASK(info->regs->func_sel.width_per_pin - 1, 0) << fs_shift;
+	dout = val << shift;
+	doen = 0;
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	fs = readl_relaxed(reg_gpio_func_sel);
+	if (fs & func_sel_mask) {
+		fs &= ~func_sel_mask;
+		writel_relaxed(fs, reg_gpio_func_sel);
+	}
+	dout |= readl_relaxed(reg_gpio_o) & ~BIT(shift);
+	writel_relaxed(dout, reg_gpio_o);
+	doen |= readl_relaxed(reg_gpio_oen) & ~BIT(shift);
+	writel_relaxed(doen, reg_gpio_oen);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jhb100_set_function(struct jhb100_pinctrl *sfp,
+				unsigned int pin, u8 func)
+{
+	struct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;
+	void __iomem *func_sel_reg;
+	unsigned long flags;
+	u32 func_sel_mask;
+	u32 func_sel_val;
+	unsigned int offset = 4 * (pin / (32 / pinctrl_regs->func_sel.width_per_pin));
+	unsigned int shift = pinctrl_regs->func_sel.width_per_pin *
+			     (pin % (32 / pinctrl_regs->func_sel.width_per_pin));
+
+	if (!pinctrl_regs->func_sel.reg || !pinctrl_regs->func_sel.width_per_pin)
+		return;
+
+	func_sel_reg = sfp->base + pinctrl_regs->func_sel.reg + offset;
+	func_sel_mask = GENMASK(pinctrl_regs->func_sel.width_per_pin - 1, 0) << shift;
+	func_sel_val = func << shift;
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	func_sel_val |= readl_relaxed(func_sel_reg) & ~func_sel_mask;
+	writel_relaxed(func_sel_val, func_sel_reg);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jhb100_set_one_pin_mux(struct jhb100_pinctrl *sfp,
+				  unsigned int pin,
+				  u8 func,
+				  int val)
+{
+	const struct pinctrl_pin_desc *desc = &sfp->pins[pin];
+	struct device *dev = sfp->dev;
+	s8 gpio_func_sel =  sfp->gpio_func_sel_arr[pin];
+
+	jhb100_set_function(sfp, pin, func);
+
+	if (pin < sfp->ngpios && (val == 0 || val == 1)) {
+		if (func == gpio_func_sel)
+			jhb100_set_gpioval(sfp, pin, val);
+		else
+			dev_err(dev, "pin (%s) is not a GPIO. func=%d/%d\n",
+				desc->name, func, gpio_func_sel);
+	}
+
+	return 0;
+}
+
+static int jhb100_set_mux(struct pinctrl_dev *pctldev,
+			  unsigned int fsel, unsigned int gsel)
+{
+	struct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+	const struct group_desc *group;
+	unsigned int i;
+	const char **functions;
+
+	group = pinctrl_generic_get_group(pctldev, gsel);
+	if (!group)
+		return -EINVAL;
+
+	functions = group->data;
+
+	for (i = 0; i < group->grp.npins; i++) {
+		int function;
+
+		function = jhb100_map_get_func_val(sfp, functions[i], group->grp.pins[i]);
+		if (function < 0) {
+			dev_err(pctldev->dev, "invalid function %s\n", functions[i]);
+			return function;
+		}
+
+		jhb100_set_one_pin_mux(sfp, group->grp.pins[i], function, -1);
+	}
+
+	return 0;
+}
+
+static const struct pinmux_ops jhb100_pinmux_ops = {
+	.get_functions_count = pinmux_generic_get_function_count,
+	.get_function_name   = pinmux_generic_get_function_name,
+	.get_function_groups = pinmux_generic_get_function_groups,
+	.set_mux             = jhb100_set_mux,
+};
+
+static const u8 jhb100_drive_strength_ma[4] = { 2, 4, 8, 12 };
+
+static const u8 jhb100_drive_strength_ma_3bit[8] = { 2, 5, 8, 10, 14, 16, 18, 20 };
+
+static u32 jhb100_padcfg_ds_to_mA(u32 padcfg)
+{
+	return jhb100_drive_strength_ma[padcfg];
+}
+
+static u32 jhb100_padcfg_ds_to_mA_3bit(u32 padcfg)
+{
+	return jhb100_drive_strength_ma_3bit[padcfg];
+}
+
+static u32 jhb100_padcfg_ds_to_uA(u32 padcfg)
+{
+	return (jhb100_drive_strength_ma[padcfg] * 1000);
+}
+
+static u32 jhb100_padcfg_ds_to_uA_3bit(u32 padcfg)
+{
+	return (jhb100_drive_strength_ma_3bit[padcfg] * 1000);
+}
+
+static u32 jhb100_padcfg_ds_from_mA(u32 v)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(jhb100_drive_strength_ma); i++) {
+		if (v <= jhb100_drive_strength_ma[i])
+			break;
+	}
+	return i;
+}
+
+static u32 jhb100_padcfg_ds_from_mA_3bit(u32 v)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(jhb100_drive_strength_ma_3bit); i++) {
+		if (v <= jhb100_drive_strength_ma_3bit[i])
+			break;
+	}
+	return i;
+}
+
+static u32 jhb100_padcfg_ds_from_uA(u32 v)
+{
+	/* Convert from uA to mA */
+	v /= 1000;
+
+	return jhb100_padcfg_ds_from_mA(v);
+}
+
+static u32 jhb100_padcfg_ds_from_uA_3bit(u32 v)
+{
+	/* Convert from uA to mA */
+	v /= 1000;
+
+	return jhb100_padcfg_ds_from_mA_3bit(v);
+}
+
+static void jhb100_padcfg_rmw(struct jhb100_pinctrl *sfp,
+			      unsigned int pin, u32 mask, u32 value)
+{
+	void __iomem *reg;
+	unsigned int offset;
+	unsigned long flags;
+	int padcfg_base;
+
+	padcfg_base = sfp->info->regs->config;
+
+	offset = 4 * pin;
+
+	reg = sfp->base + padcfg_base + offset;
+
+	value &= mask;
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	value |= readl_relaxed(reg) & ~mask;
+	writel_relaxed(value, reg);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jhb100_pincfg_pin_vref_get(struct jhb100_pinctrl *sfp, unsigned int pin)
+{
+	struct pinvref_reg *vref = &sfp->info->regs->vref;
+	u32 grp = 0, i;
+
+	while (grp < vref->num_pv) {
+		for (i = 0; i < vref->pv_desc[grp].num_pins; i++) {
+			if (pin != vref->pv_desc[grp].pin_grp[i])
+				continue;
+
+			return readl(sfp->base + vref->reg + grp * 4);
+		}
+
+		grp++;
+	}
+
+	return -ENOTSUPP;
+}
+
+static void jhb100_pincfg_pin_vref_set(struct jhb100_pinctrl *sfp, unsigned int pin,
+				       u32 arg)
+{
+	struct pinvref_reg *vref = &sfp->info->regs->vref;
+	u32 grp = 0, i;
+
+	while (grp < vref->num_pv) {
+		for (i = 0; i < vref->pv_desc[grp].num_pins; i++) {
+			if (pin != vref->pv_desc[grp].pin_grp[i])
+				continue;
+
+			if (!(vref->pv_desc[grp].range & BIT(arg)))
+				return;
+
+			writel(arg, sfp->base + vref->reg + grp * 4);
+			return;
+		}
+
+		grp++;
+	}
+}
+
+static int jhb100_pinconf_get(struct pinctrl_dev *pctldev,
+			      unsigned int pin, unsigned long *config)
+{
+	struct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+	int param = pinconf_to_config_param(*config);
+	struct device *dev = sfp->dev;
+	struct config_reg_layout_desc *crl_desc;
+	unsigned int offset;
+	u32 padcfg, arg;
+	bool enabled;
+	int padcfg_base;
+
+	padcfg_base = sfp->info->regs->config;
+	offset = 4 * pin;
+
+	if (pin >= sfp->npins)
+		return -EINVAL;
+
+	padcfg = readl_relaxed(sfp->base + padcfg_base + offset);
+
+	crl_desc = get_crl_desc_by_pin(sfp, pin);
+	if (!crl_desc) {
+		dev_err(dev, "pin %d can't not found reg layout descriptor\n", pin);
+		return -EINVAL;
+	}
+
+	switch (param) {
+	case PIN_CONFIG_BIAS_DISABLE:
+		arg = 0;
+
+		if (!RL_DESC_SUPPORTED(crl_desc, pull_down) ||
+		    !RL_DESC_SUPPORTED(crl_desc, pull_up))
+			return -ENOTSUPP;
+
+		enabled = !(padcfg & (RL_DESC_GENMASK(crl_desc, pull_down) |
+				      RL_DESC_GENMASK(crl_desc, pull_up)));
+		break;
+	case PIN_CONFIG_BIAS_PULL_DOWN:
+		arg = 1;
+
+		if (!RL_DESC_SUPPORTED(crl_desc, pull_down))
+			return -ENOTSUPP;
+
+		enabled = (padcfg & RL_DESC_GENMASK(crl_desc, pull_down))
+			  >> RL_DESC_SHIFT(crl_desc, pull_down);
+		break;
+	case PIN_CONFIG_BIAS_PULL_UP:
+		enabled = false;
+
+		if (!RL_DESC_SUPPORTED(crl_desc, pull_up) ||
+		    !RL_DESC_SUPPORTED(crl_desc, open_drain_pull_up_sel))
+			return -ENOTSUPP;
+
+		if (RL_DESC_SUPPORTED(crl_desc, pull_up)) {
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, pull_up)) >>
+			      RL_DESC_SHIFT(crl_desc, pull_up);
+
+			enabled = arg ? true : false;
+		}
+
+		if (!enabled && RL_DESC_SUPPORTED(crl_desc, open_drain_pull_up_sel)) {
+			enabled = true;
+
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, open_drain_pull_up_sel)) >>
+			      RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);
+
+			if (arg == JHB100_I2C_OPEN_DRAIN_PU_600_OHMS)
+				arg = 600;
+			else if (arg == JHB100_I2C_OPEN_DRAIN_PU_900_OHMS)
+				arg = 900;
+			else if (arg == JHB100_I2C_OPEN_DRAIN_PU_1200_OHMS)
+				arg = 1200;
+			else if (arg == JHB100_I2C_OPEN_DRAIN_PU_2000_OHMS)
+				arg = 2000;
+			else
+				return -ENOTSUPP;
+		}
+
+		break;
+	case PIN_CONFIG_DRIVE_STRENGTH:
+		enabled = true;
+
+		if (RL_DESC_SUPPORTED(crl_desc, drive_strength_2bit)) {
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, drive_strength_2bit)) >>
+			      RL_DESC_SHIFT(crl_desc, drive_strength_2bit);
+			arg = jhb100_padcfg_ds_to_mA(arg);
+		} else if (RL_DESC_SUPPORTED(crl_desc, drive_strength_3bit)) {
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, drive_strength_3bit)) >>
+			      RL_DESC_SHIFT(crl_desc, drive_strength_3bit);
+			arg = jhb100_padcfg_ds_to_mA_3bit(arg);
+		} else {
+			return -ENOTSUPP;
+		}
+		break;
+	case PIN_CONFIG_DRIVE_STRENGTH_UA:
+		enabled = true;
+
+		if (RL_DESC_SUPPORTED(crl_desc, drive_strength_2bit)) {
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, drive_strength_2bit)) >>
+			      RL_DESC_SHIFT(crl_desc, drive_strength_2bit);
+			arg = jhb100_padcfg_ds_to_uA(arg);
+		} else if (RL_DESC_SUPPORTED(crl_desc, drive_strength_3bit)) {
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, drive_strength_3bit)) >>
+			      RL_DESC_SHIFT(crl_desc, drive_strength_3bit);
+			arg = jhb100_padcfg_ds_to_uA_3bit(arg);
+		} else {
+			return -ENOTSUPP;
+		}
+		break;
+	case PIN_CONFIG_INPUT_ENABLE:
+		if (!RL_DESC_SUPPORTED(crl_desc, input_enable))
+			return -ENOTSUPP;
+
+		enabled = (padcfg & RL_DESC_GENMASK(crl_desc, input_enable))
+			   >> RL_DESC_SHIFT(crl_desc, input_enable);
+		arg = enabled;
+		break;
+	case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+		if (!RL_DESC_SUPPORTED(crl_desc, schmitt_trigger_select))
+			return -ENOTSUPP;
+
+		enabled = (padcfg & RL_DESC_GENMASK(crl_desc, schmitt_trigger_select))
+			   >> RL_DESC_SHIFT(crl_desc, schmitt_trigger_select);
+		arg = enabled;
+		break;
+	case PIN_CONFIG_SLEW_RATE:
+		enabled = true;
+
+		if (RL_DESC_SUPPORTED(crl_desc, slew_rate)) {
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, slew_rate)) >>
+			      RL_DESC_SHIFT(crl_desc, slew_rate);
+		} else if (RL_DESC_SUPPORTED(crl_desc, mode_select)) {
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, mode_select)) >>
+			      RL_DESC_SHIFT(crl_desc, mode_select);
+
+			if (arg == JHB100_LEGACY_FAST_MODE_PLUS)
+				arg = 1;
+			else if (arg == JHB100_LEGACY_FAST_MODE)
+				arg = 0;
+			else
+				return -ENOTSUPP;
+		} else {
+			return -ENOTSUPP;
+		}
+		break;
+	case PIN_CONFIG_DRIVE_PUSH_PULL:
+		if (!RL_DESC_SUPPORTED(crl_desc, mode_select))
+			return -ENOTSUPP;
+
+		arg = (padcfg & RL_DESC_GENMASK(crl_desc, mode_select)) >>
+		      RL_DESC_SHIFT(crl_desc, mode_select);
+
+		if (arg == JHB100_PUSH_PULL)
+			enabled = true;
+
+		break;
+	case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+		if (!RL_DESC_SUPPORTED(crl_desc, mode_select))
+			return -ENOTSUPP;
+
+		arg = (padcfg & RL_DESC_GENMASK(crl_desc, mode_select)) >>
+		      RL_DESC_SHIFT(crl_desc, mode_select);
+
+		if (arg == JHB100_OPEN_DRAIN)
+			enabled = true;
+
+		break;
+	case PIN_CONFIG_INPUT_DEBOUNCE_NS:
+		enabled = true;
+
+		if (!RL_DESC_SUPPORTED(crl_desc, debounce_width))
+			return -ENOTSUPP;
+
+		arg = (padcfg & RL_DESC_GENMASK(crl_desc, debounce_width)) >>
+		      RL_DESC_SHIFT(crl_desc, debounce_width);
+
+		arg *= JHB100_DEBOUNCE_WIDTH_STAGE_NS;
+
+		break;
+	case PIN_CONFIG_POWER_SOURCE:
+		if (!sfp->info->regs->vref.num_pv && !RL_DESC_SUPPORTED(crl_desc, vsel))
+			return -ENOTSUPP;
+
+		enabled = true;
+
+		if (sfp->info->regs->vref.num_pv) {
+			int ret;
+
+			ret = jhb100_pincfg_pin_vref_get(sfp, pin);
+			if (ret < 0)
+				return ret;
+
+			arg = ret;
+		} else if (RL_DESC_SUPPORTED(crl_desc, vsel)) {
+			arg = (padcfg & RL_DESC_GENMASK(crl_desc, vsel)) >>
+			      RL_DESC_SHIFT(crl_desc, vsel);
+		} else {
+			return -ENOTSUPP;
+		}
+		break;
+	default:
+		return -ENOTSUPP;
+	}
+
+	*config = pinconf_to_config_packed(param, arg);
+	return enabled ? 0 : -EINVAL;
+}
+
+static int jhb100_pinconf_set(struct pinctrl_dev *pctldev,
+			      unsigned int pin, unsigned long *configs,
+			      unsigned int num_configs)
+{
+	struct jhb100_pinctrl *sfp = pinctrl_dev_get_drvdata(pctldev);
+	struct device *dev = sfp->dev;
+	struct config_reg_layout_desc *crl_desc;
+	bool vref_set = false;
+	u32 value = 0;
+	u32 mask = 0;
+	u32 vref = 0;
+	int i;
+
+	crl_desc = get_crl_desc_by_pin(sfp, pin);
+	if (!crl_desc) {
+		dev_err(dev, "pin %d can't not found reg layout descriptor\n", pin);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < num_configs; i++) {
+		int param = pinconf_to_config_param(configs[i]);
+		u32 arg = pinconf_to_config_argument(configs[i]);
+
+		switch (param) {
+		case PIN_CONFIG_BIAS_DISABLE:
+			if (!RL_DESC_SUPPORTED(crl_desc, pull_down) ||
+			    !RL_DESC_SUPPORTED(crl_desc, pull_up))
+				return -ENOTSUPP;
+
+			mask |= RL_DESC_GENMASK(crl_desc, pull_down) |
+				RL_DESC_GENMASK(crl_desc, pull_up);
+			value &= ~(RL_DESC_GENMASK(crl_desc, pull_down) |
+				   RL_DESC_GENMASK(crl_desc, pull_up));
+			break;
+		case PIN_CONFIG_BIAS_PULL_DOWN:
+			if (!arg || !RL_DESC_SUPPORTED(crl_desc, pull_down) ||
+			    !RL_DESC_SUPPORTED(crl_desc, pull_up))
+				return -ENOTSUPP;
+
+			mask |= RL_DESC_GENMASK(crl_desc, pull_down) |
+				RL_DESC_GENMASK(crl_desc, pull_up);
+			value &= ~(RL_DESC_GENMASK(crl_desc, pull_down) |
+				   RL_DESC_GENMASK(crl_desc, pull_up));
+			value |= RL_DESC_GENMASK(crl_desc, pull_down);
+			break;
+		case PIN_CONFIG_BIAS_PULL_UP:
+			if ((!arg || arg == 1) && RL_DESC_SUPPORTED(crl_desc, pull_up)) {
+				mask |= RL_DESC_GENMASK(crl_desc, pull_down) |
+					RL_DESC_GENMASK(crl_desc, pull_up);
+				value &= ~(RL_DESC_GENMASK(crl_desc, pull_down) |
+					RL_DESC_GENMASK(crl_desc, pull_up));
+				value |= RL_DESC_GENMASK(crl_desc, pull_up);
+			} else if (arg && RL_DESC_SUPPORTED(crl_desc, open_drain_pull_up_sel)) {
+				mask |= RL_DESC_GENMASK(crl_desc, open_drain_pull_up_sel);
+				value &= ~RL_DESC_GENMASK(crl_desc, open_drain_pull_up_sel);
+				switch (arg) {
+				case 600:
+					value |= JHB100_I2C_OPEN_DRAIN_PU_600_OHMS <<
+						RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);
+					break;
+				case 900:
+					value |= JHB100_I2C_OPEN_DRAIN_PU_900_OHMS <<
+						RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);
+					break;
+				case 1200:
+					value |= JHB100_I2C_OPEN_DRAIN_PU_1200_OHMS <<
+						RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);
+					break;
+				case 2000:
+					value |= JHB100_I2C_OPEN_DRAIN_PU_2000_OHMS <<
+						RL_DESC_SHIFT(crl_desc, open_drain_pull_up_sel);
+					break;
+				default:
+					return -ENOTSUPP;
+				}
+			} else {
+				return -ENOTSUPP;
+			}
+			break;
+		case PIN_CONFIG_DRIVE_STRENGTH:
+			if (RL_DESC_SUPPORTED(crl_desc, drive_strength_2bit)) {
+				mask |= RL_DESC_GENMASK(crl_desc, drive_strength_2bit);
+				value &= ~RL_DESC_GENMASK(crl_desc, drive_strength_2bit);
+				value |= jhb100_padcfg_ds_from_mA(arg) <<
+					 RL_DESC_SHIFT(crl_desc, drive_strength_2bit);
+			} else if (RL_DESC_SUPPORTED(crl_desc, drive_strength_3bit)) {
+				mask |= RL_DESC_GENMASK(crl_desc, drive_strength_3bit);
+				value &= ~RL_DESC_GENMASK(crl_desc, drive_strength_3bit);
+				value |= jhb100_padcfg_ds_from_mA_3bit(arg) <<
+					 RL_DESC_SHIFT(crl_desc, drive_strength_3bit);
+			} else {
+				return -ENOTSUPP;
+			}
+			break;
+		case PIN_CONFIG_DRIVE_STRENGTH_UA:
+			if (RL_DESC_SUPPORTED(crl_desc, drive_strength_2bit)) {
+				mask |= RL_DESC_GENMASK(crl_desc, drive_strength_2bit);
+				value &= ~RL_DESC_GENMASK(crl_desc, drive_strength_2bit);
+				value |= jhb100_padcfg_ds_from_uA(arg) <<
+					 RL_DESC_SHIFT(crl_desc, drive_strength_2bit);
+			} else if (RL_DESC_SUPPORTED(crl_desc, drive_strength_3bit)) {
+				mask |= RL_DESC_GENMASK(crl_desc, drive_strength_3bit);
+				value &= ~RL_DESC_GENMASK(crl_desc, drive_strength_3bit);
+				value |= jhb100_padcfg_ds_from_uA_3bit(arg) <<
+					 RL_DESC_SHIFT(crl_desc, drive_strength_3bit);
+			} else {
+				return -ENOTSUPP;
+			}
+			break;
+		case PIN_CONFIG_INPUT_ENABLE:
+			if (!RL_DESC_SUPPORTED(crl_desc, input_enable))
+				return -ENOTSUPP;
+
+			mask |= RL_DESC_GENMASK(crl_desc, input_enable);
+			value = arg ? (value | RL_DESC_GENMASK(crl_desc, input_enable))
+				: value;
+			break;
+		case PIN_CONFIG_INPUT_SCHMITT_ENABLE:
+			if (!RL_DESC_SUPPORTED(crl_desc, schmitt_trigger_select))
+				return -ENOTSUPP;
+
+			mask |= RL_DESC_GENMASK(crl_desc, schmitt_trigger_select);
+			value = arg
+				? (value | RL_DESC_GENMASK(crl_desc, schmitt_trigger_select))
+				: value;
+			break;
+		case PIN_CONFIG_SLEW_RATE:
+			if (RL_DESC_SUPPORTED(crl_desc, slew_rate)) {
+				mask |= RL_DESC_GENMASK(crl_desc, slew_rate);
+				value = arg ?
+					(value | RL_DESC_GENMASK(crl_desc, slew_rate)) :
+					value;
+			} else if (RL_DESC_SUPPORTED(crl_desc, mode_select)) {
+				mask |= RL_DESC_GENMASK(crl_desc, mode_select);
+				value &= ~RL_DESC_GENMASK(crl_desc, mode_select);
+				value |= arg ?
+					 JHB100_LEGACY_FAST_MODE_PLUS <<
+					 RL_DESC_SHIFT(crl_desc, mode_select) :
+					 JHB100_LEGACY_FAST_MODE <<
+					 RL_DESC_SHIFT(crl_desc, mode_select);
+			} else {
+				return -ENOTSUPP;
+			}
+			break;
+		case PIN_CONFIG_DRIVE_PUSH_PULL:
+			if (!RL_DESC_SUPPORTED(crl_desc, mode_select))
+				return -ENOTSUPP;
+
+			mask |= RL_DESC_GENMASK(crl_desc, mode_select);
+			value &= ~RL_DESC_GENMASK(crl_desc, mode_select);
+			value |= JHB100_PUSH_PULL <<
+				 RL_DESC_SHIFT(crl_desc, mode_select);
+			break;
+		case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+			if (!RL_DESC_SUPPORTED(crl_desc, mode_select))
+				return -ENOTSUPP;
+
+			mask |= RL_DESC_GENMASK(crl_desc, mode_select);
+			value &= ~RL_DESC_GENMASK(crl_desc, mode_select);
+			value |= JHB100_OPEN_DRAIN <<
+				 RL_DESC_SHIFT(crl_desc, mode_select);
+			break;
+		case PIN_CONFIG_INPUT_DEBOUNCE_NS:
+			u32 debounce_stage;
+
+			if (!RL_DESC_SUPPORTED(crl_desc, debounce_width))
+				return -ENOTSUPP;
+
+			mask |= RL_DESC_GENMASK(crl_desc, debounce_width);
+			value &= ~RL_DESC_GENMASK(crl_desc, debounce_width);
+
+			debounce_stage = arg ? arg / JHB100_DEBOUNCE_WIDTH_STAGE_NS : 0;
+			debounce_stage = umin(debounce_stage, JHB100_DEBOUNCE_WIDTH_STAGES_MAX);
+
+			value |= (debounce_stage << RL_DESC_SHIFT(crl_desc, debounce_width));
+
+			break;
+		case PIN_CONFIG_POWER_SOURCE:
+			if (!sfp->info->regs->vref.num_pv && !RL_DESC_SUPPORTED(crl_desc, vsel))
+				return -ENOTSUPP;
+
+			if (sfp->info->regs->vref.num_pv) {
+				vref_set = true;
+				vref = arg;
+			}
+
+			if (RL_DESC_SUPPORTED(crl_desc, vsel)) {
+				mask |= RL_DESC_GENMASK(crl_desc, vsel);
+				value &= ~RL_DESC_GENMASK(crl_desc, vsel);
+
+				value |= arg & BIT(0) ?
+					 1 << RL_DESC_SHIFT(crl_desc, vsel) :
+					 0;
+			}
+			break;
+		default:
+			return -ENOTSUPP;
+		}
+	}
+
+	jhb100_padcfg_rmw(sfp, pin, mask, value);
+
+	if (vref_set)
+		jhb100_pincfg_pin_vref_set(sfp, pin, vref);
+
+	return 0;
+}
+
+static int jhb100_pinconf_group_get(struct pinctrl_dev *pctldev,
+				    unsigned int gsel,
+				    unsigned long *config)
+{
+	const struct group_desc *group;
+
+	group = pinctrl_generic_get_group(pctldev, gsel);
+	if (!group)
+		return -EINVAL;
+
+	return jhb100_pinconf_get(pctldev, group->grp.pins[0], config);
+}
+
+static int jhb100_pinconf_group_set(struct pinctrl_dev *pctldev,
+				    unsigned int gsel,
+				    unsigned long *configs,
+				    unsigned int num_configs)
+{
+	const struct group_desc *group;
+	int ret;
+	u32 i;
+
+	group = pinctrl_generic_get_group(pctldev, gsel);
+	if (!group)
+		return -EINVAL;
+
+	for (i = 0; i < group->grp.npins; i++) {
+		ret = jhb100_pinconf_set(pctldev, group->grp.pins[i], configs, num_configs);
+		if (ret) {
+			dev_err(pctldev->dev, "failed to set config for pin %d\n",
+				group->grp.pins[i]);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
+static const struct pinconf_ops jhb100_pinconf_ops = {
+	.pin_config_get		= jhb100_pinconf_get,
+	.pin_config_set		= jhb100_pinconf_set,
+	.pin_config_group_get	= jhb100_pinconf_group_get,
+	.pin_config_group_set	= jhb100_pinconf_group_set,
+	.is_generic		= true,
+};
+
+static int jhb100_gpio_get_direction(struct gpio_chip *gc,
+				     unsigned int gpio)
+{
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	const struct jhb100_pinctrl_domain_info *info = sfp->info;
+	unsigned int offset = 4 * bank->id;
+	u32 doen;
+	void __iomem *reg_gpio_oen;
+
+	reg_gpio_oen = sfp->base + info->regs->output_en + offset;
+
+	doen = (readl_relaxed(reg_gpio_oen) & BIT(gpio)) >> gpio;
+
+	return doen == GPOEN_ENABLE ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
+}
+
+static int jhb100_gpio_direction_input(struct gpio_chip *gc,
+				       unsigned int gpio)
+{
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	struct device *dev = sfp->dev;
+	struct config_reg_layout_desc *crl_desc;
+	unsigned int pin = jhb100_gpio_to_pin(gc, gpio);
+
+	crl_desc = get_crl_desc_by_pin(sfp, pin);
+	if (!crl_desc) {
+		dev_err(dev, "pin %d can't not found reg layout descriptor\n",
+			pin);
+		return -EINVAL;
+	}
+
+	jhb100_padcfg_rmw(sfp, pin,
+			  RL_DESC_GENMASK(crl_desc, input_enable) |
+			  RL_DESC_GENMASK(crl_desc, schmitt_trigger_select),
+			  RL_DESC_GENMASK(crl_desc, input_enable) |
+			  RL_DESC_GENMASK(crl_desc, schmitt_trigger_select));
+
+	jhb100_set_one_pin_mux(sfp, pin, 0, -1);
+
+	return 0;
+}
+
+static int jhb100_gpio_direction_output(struct gpio_chip *gc,
+					unsigned int gpio, int value)
+{
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	struct device *dev = sfp->dev;
+	struct config_reg_layout_desc *crl_desc;
+	unsigned int pin = jhb100_gpio_to_pin(gc, gpio);
+
+	jhb100_set_one_pin_mux(sfp, pin, 0,
+			       value ? GPOUT_HIGH : GPOUT_LOW);
+
+	crl_desc = get_crl_desc_by_pin(sfp, pin);
+	if (!crl_desc) {
+		dev_err(dev, "pin %d can't not found reg layout descriptor\n",
+			pin);
+		return -EINVAL;
+	}
+
+	jhb100_padcfg_rmw(sfp, pin,
+			  RL_DESC_GENMASK(crl_desc, input_enable) |
+			  RL_DESC_GENMASK(crl_desc, schmitt_trigger_select) |
+			  RL_DESC_GENMASK(crl_desc, pull_down) |
+			  RL_DESC_GENMASK(crl_desc, pull_up),
+			  0);
+
+	return 0;
+}
+
+static int jhb100_gpio_get(struct gpio_chip *gc, unsigned int gpio)
+{
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	const struct jhb100_pinctrl_domain_info *info = sfp->info;
+	unsigned int offset = 4 * bank->id;
+	u32 doen = 0;
+	void __iomem *reg_gpio_oen;
+	void __iomem *reg;
+	unsigned long flags;
+
+	reg_gpio_oen = sfp->base + info->regs->output_en + offset;
+	reg = sfp->base + info->regs->gpio_status + offset;
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	doen = readl_relaxed(reg_gpio_oen) | BIT(gpio);
+	writel_relaxed(doen, reg_gpio_oen);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+
+	return !!(readl_relaxed(reg) & BIT(gpio % 32));
+}
+
+static int jhb100_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
+{
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	const struct jhb100_pinctrl_domain_info *info = sfp->info;
+	unsigned int offset = 4 * bank->id;
+	void __iomem *reg_dout;
+	u32 dout;
+	unsigned long flags;
+
+	reg_dout = sfp->base + info->regs->output + offset;
+	dout = (value ? GPOUT_HIGH : GPOUT_LOW) << gpio;
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	dout |= readl_relaxed(reg_dout) & ~BIT(gpio);
+	writel_relaxed(dout, reg_dout);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+
+	return 0;
+}
+
+static void jhb100_irq_ack(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	struct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;
+	irq_hw_number_t gpio = irqd_to_hwirq(d);
+	unsigned int offset = 4 * bank->id;
+	void __iomem *ic;
+	unsigned long flags;
+	u32 value;
+	u32 mask;
+
+	ic = sfp->base + pinctrl_regs->irq_clr + offset;
+	mask = BIT(gpio);
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	value = readl_relaxed(ic) & ~mask;
+	writel_relaxed(value | mask, ic);
+	value = readl_relaxed(ic) & ~mask;
+	writel_relaxed(value, ic);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jhb100_irq_mask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	struct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;
+	irq_hw_number_t gpio = irqd_to_hwirq(d);
+	unsigned int offset = 4 * bank->id;
+	void __iomem *ien;
+	unsigned long flags;
+	u32 value;
+	u32 mask;
+
+	ien = sfp->base + pinctrl_regs->irq_en + offset;
+	mask = BIT(gpio);
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	value = readl_relaxed(ien) & ~mask;
+	writel_relaxed(value, ien);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+
+	gpiochip_disable_irq(gc, d->hwirq);
+}
+
+static void jhb100_irq_mask_ack(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	struct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;
+	irq_hw_number_t gpio = irqd_to_hwirq(d);
+	unsigned int offset = 4 * bank->id;
+	void __iomem *ien;
+	void __iomem *ic;
+	unsigned long flags;
+	u32 value;
+	u32 mask;
+
+	ien = sfp->base + pinctrl_regs->irq_en + offset;
+	ic = sfp->base + pinctrl_regs->irq_clr + offset;
+	mask = BIT(gpio);
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	value = readl_relaxed(ien) & ~mask;
+	writel_relaxed(value, ien);
+
+	value = readl_relaxed(ic) & ~mask;
+	writel_relaxed(value | mask, ic);
+	value = readl_relaxed(ic) & ~mask;
+	writel_relaxed(value, ic);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static void jhb100_irq_unmask(struct irq_data *d)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	struct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;
+	irq_hw_number_t gpio = irqd_to_hwirq(d);
+	unsigned int offset = 4 * bank->id;
+	void __iomem *ien;
+	unsigned long flags;
+	u32 value;
+	u32 mask;
+
+	ien = sfp->base + pinctrl_regs->irq_en + offset;
+	mask = BIT(gpio);
+
+	gpiochip_enable_irq(gc, d->hwirq);
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	value = readl_relaxed(ien) | mask;
+	writel_relaxed(value, ien);
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+}
+
+static int jhb100_irq_set_type(struct irq_data *d, unsigned int trigger)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	struct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;
+	irq_hw_number_t gpio = irqd_to_hwirq(d);
+	unsigned int offset = 4 * bank->id;
+	void __iomem *base;
+	u32 irq_type, edge_both, polarity, mask;
+	unsigned long flags;
+
+	base = sfp->base + offset;
+	mask = BIT(gpio);
+
+	switch (trigger) {
+	case IRQ_TYPE_EDGE_RISING:
+		irq_type  = mask; /* 1: edge triggered */
+		edge_both = 0;    /* 0: single edge */
+		polarity  = mask; /* 1: rising edge */
+		break;
+	case IRQ_TYPE_EDGE_FALLING:
+		irq_type  = mask; /* 1: edge triggered */
+		edge_both = 0;    /* 0: single edge */
+		polarity  = 0;    /* 0: falling edge */
+		break;
+	case IRQ_TYPE_EDGE_BOTH:
+		irq_type  = mask; /* 1: edge triggered */
+		edge_both = mask; /* 1: both edges */
+		polarity  = 0;    /* 0: ignored */
+		break;
+	case IRQ_TYPE_LEVEL_HIGH:
+		irq_type  = 0;    /* 0: level triggered */
+		edge_both = 0;    /* 0: ignored */
+		polarity  = mask; /* 1: high level */
+		break;
+	case IRQ_TYPE_LEVEL_LOW:
+		irq_type  = 0;    /* 0: level triggered */
+		edge_both = 0;    /* 0: ignored */
+		polarity  = 0;    /* 0: low level */
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	if (trigger & IRQ_TYPE_EDGE_BOTH)
+		irq_set_handler_locked(d, handle_edge_irq);
+	else
+		irq_set_handler_locked(d, handle_level_irq);
+
+	raw_spin_lock_irqsave(&sfp->lock, flags);
+	irq_type |= readl_relaxed(base + pinctrl_regs->irq_trigger) & ~mask;
+	writel_relaxed(irq_type, base + pinctrl_regs->irq_trigger);
+
+	edge_both |= readl_relaxed(base + pinctrl_regs->irq_both_edge) & ~mask;
+	writel_relaxed(edge_both, base + pinctrl_regs->irq_both_edge);
+
+	if (irq_type & mask) { /* edge polarity */
+		polarity |= readl_relaxed(base + pinctrl_regs->irq_edge) & ~mask;
+		writel_relaxed(polarity, base + pinctrl_regs->irq_edge);
+	} else if (irq_type == 0) { /* level polarity */
+		polarity |= readl_relaxed(base + pinctrl_regs->irq_level) & ~mask;
+		writel_relaxed(polarity, base + pinctrl_regs->irq_level);
+	}
+	raw_spin_unlock_irqrestore(&sfp->lock, flags);
+	return 0;
+}
+
+static int jhb100_irq_set_wake(struct irq_data *d, unsigned int enable)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	int ret = 0;
+
+	if (enable)
+		ret = enable_irq_wake(sfp->wakeup_irq);
+	else
+		ret = disable_irq_wake(sfp->wakeup_irq);
+	if (ret)
+		dev_err(sfp->dev, "failed to %s wake-up interrupt\n",
+			enable ? "enable" : "disable");
+
+	return ret;
+}
+
+static void jhb100_irq_print_chip(struct irq_data *d, struct seq_file *p)
+{
+	struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+	struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
+
+	seq_printf(p, "%s-%d", gc->label, bank->id);
+}
+
+static const struct irq_chip jhb100_irq_chip = {
+	.irq_ack        = jhb100_irq_ack,
+	.irq_mask       = jhb100_irq_mask,
+	.irq_mask_ack   = jhb100_irq_mask_ack,
+	.irq_unmask     = jhb100_irq_unmask,
+	.irq_set_type   = jhb100_irq_set_type,
+	.irq_set_wake   = jhb100_irq_set_wake,
+	.irq_print_chip = jhb100_irq_print_chip,
+	.flags          = IRQCHIP_SET_TYPE_MASKED |
+			  IRQCHIP_IMMUTABLE |
+			  IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND |
+			  IRQCHIP_MASK_ON_SUSPEND |
+			  IRQCHIP_SKIP_SET_WAKE,
+	GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
+
+static irqreturn_t jhb100_gpio_irq_handler(int irq, void *dev_id)
+{
+	struct jhb100_gpio_bank *bank = dev_id;
+	struct gpio_chip *gc = &bank->gc;
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+	struct gpio_irq_chip *girq = &gc->irq;
+	struct starfive_pinctrl_regs *pinctrl_regs = sfp->info->regs;
+	unsigned int irq_status = pinctrl_regs->irq_status + bank->id * 4;
+	unsigned long is;
+	unsigned int gpio;
+
+	is = readl_relaxed(sfp->base + irq_status);
+	if (!is)
+		return IRQ_NONE;
+
+	for_each_set_bit(gpio, &is, gc->ngpio)
+		generic_handle_domain_irq(girq->domain, gpio);
+
+	return IRQ_HANDLED;
+}
+
+static int field_compare(const void *a, const void *b)
+{
+	const struct field_info *fa = (const struct field_info *)a;
+	const struct field_info *fb = (const struct field_info *)b;
+
+	if (fa->shift < fb->shift)
+		return -1;
+
+	if (fa->shift > fb->shift)
+		return 1;
+
+	return 0;
+}
+
+static int check_crl_desc(struct jhb100_pinctrl *sfp, unsigned int index,
+			  const struct config_reg_layout_desc *desc)
+{
+	struct device *dev = sfp->dev;
+	struct field_info *fields;
+	int field_cnt = 0;
+	int num, i;
+
+	num = sizeof(struct config_reg_layout_desc) / sizeof(struct reg_layout_field);
+
+	fields = kcalloc(num, sizeof(struct field_info), GFP_KERNEL);
+	if (!fields)
+		return -ENOMEM;
+
+	#define COLLECT_FIELD(field) \
+		do { \
+			if (desc->field.width > 0) { \
+				fields[field_cnt].name = #field; \
+				fields[field_cnt].shift = desc->field.shift; \
+				fields[field_cnt].width = desc->field.width; \
+				fields[field_cnt].end = desc->field.shift + desc->field.width; \
+				field_cnt++; \
+			} \
+		} while (0)
+
+	/* same as struct config_reg_layout_desc filed except for pin_start and pin_cnt */
+	COLLECT_FIELD(debounce_width);
+	COLLECT_FIELD(drive_strength_2bit);
+	COLLECT_FIELD(drive_strength_3bit);
+	COLLECT_FIELD(function);
+	COLLECT_FIELD(input_enable);
+	COLLECT_FIELD(vsel);
+	COLLECT_FIELD(mode_select);
+	COLLECT_FIELD(open_drain_pull_up_sel);
+	COLLECT_FIELD(pull_down);
+	COLLECT_FIELD(pull_up);
+	COLLECT_FIELD(reserved);
+	COLLECT_FIELD(retention_signal_bus);
+	COLLECT_FIELD(schmitt_trigger_select);
+	COLLECT_FIELD(slew_rate);
+
+	#undef COLLECT_FIELD
+
+	sort(fields, field_cnt, sizeof(struct field_info), field_compare, NULL);
+
+	for (i = 0; i < field_cnt; i++) {
+		if (fields[i].end > 32) {
+			dev_err(dev,
+				"layout %d: field %s exceeds 32bit [shift=%u, width=%u, end=%u]\n",
+				index, fields[i].name,
+				fields[i].shift, fields[i].width, fields[i].end);
+			goto failed;
+		}
+
+		if (i < field_cnt - 1) {
+			if (fields[i].end > fields[i + 1].shift) {
+				dev_err(dev,
+					"layout %d: field overlap: %s[%u:%u] with %s[%u:%u]\n",
+					index, fields[i].name, fields[i].end - 1,
+					fields[i].shift, fields[i + 1].name,
+					fields[i + 1].end - 1, fields[i + 1].shift);
+				goto failed;
+			}
+		}
+	}
+
+	if (desc->reserved.width > 0) {
+		unsigned int used_mask = 0;
+		unsigned int reserved_mask = 0;
+
+		for (i = 0; i < field_cnt; i++) {
+			if (strcmp(fields[i].name, "reserved"))
+				used_mask |= GENMASK(fields[i].end - 1, fields[i].shift);
+			else
+				reserved_mask |= GENMASK(fields[i].end - 1, fields[i].shift);
+		}
+
+		if ((used_mask | reserved_mask) != 0xFFFFFFFF) {
+			dev_err(dev,
+				"layout %d: reserved field not cover all unused bits\n",
+				index);
+			dev_err(dev,
+				"used mask: 0x%08X, reserved mask: 0x%08X, combined: 0x%08X\n",
+				used_mask, reserved_mask, used_mask | reserved_mask);
+		}
+	}
+
+	kfree(fields);
+	return 0;
+
+failed:
+	kfree(fields);
+	return -EINVAL;
+}
+
+static int check_layout_pin_range(struct jhb100_pinctrl *sfp,
+				  const struct config_reg_layout_desc *descs,
+				  unsigned int num_desc)
+{
+	struct device *dev = sfp->dev;
+
+	if (descs[num_desc - 1].pin_start + descs[num_desc - 1].pin_cnt > sfp->npins) {
+		dev_err(dev, "layout %u pin_start[%u] + pin_cnt[%u] exceeds pin number[%u]\n",
+			num_desc - 1, descs[num_desc - 1].pin_start,
+			descs[num_desc - 1].pin_cnt, sfp->npins);
+		return -EINVAL;
+	}
+
+	for (int i = 0; i < num_desc; i++) {
+		if (descs[i].pin_start == 0xff)
+			break;
+
+		if (i < num_desc - 1) {
+			if (descs[i].pin_start + descs[i].pin_cnt > descs[i + 1].pin_start) {
+				dev_err(dev, "pin range: [%u-%u] overlaps with [%u-%u]\n",
+					descs[i].pin_start, descs[i].pin_cnt,
+					descs[i + 1].pin_start, descs[i + 1].pin_cnt);
+				return -EINVAL;
+			}
+
+			if (descs[i].pin_start + descs[i].pin_cnt < descs[i + 1].pin_start) {
+				dev_err(dev, "pin range: [%u-%u] -> [%u-%u] has gap\n",
+					descs[i].pin_start, descs[i].pin_cnt,
+					descs[i + 1].pin_start, descs[i + 1].pin_cnt);
+				return -EINVAL;
+			}
+		}
+	}
+
+	return 0;
+}
+
+static int check_pinctrl_layouts(struct jhb100_pinctrl *sfp,
+				 const struct config_reg_layout_desc *layouts)
+{
+	struct device *dev = sfp->dev;
+	int i = 0, err_cnt = 0, ret;
+
+	if (!layouts) {
+		dev_err(dev, "layout pointer is NULL\n");
+		return -EINVAL;
+	}
+
+	while (layouts[i].pin_start != 0xff) {
+		ret = check_crl_desc(sfp, i, &layouts[i]);
+		if (ret) {
+			dev_err(dev, "layout %d check failed\n", i);
+			err_cnt++;
+		}
+
+		if (++i > 100) {
+			dev_err(dev, "too many layouts or missing 0xff for end\n");
+			return -EINVAL;
+		}
+	}
+
+	if (!err_cnt) {
+		ret = check_layout_pin_range(sfp, layouts, i);
+		if (ret)
+			err_cnt++;
+	}
+
+	if (err_cnt) {
+		dev_err(dev, "pinctrl layout check finish with %d error(s)\n", err_cnt);
+		return -EINVAL;
+	}
+
+	dev_info(dev, "pinctrl layout check completed!\n");
+	return 0;
+}
+
+static
+struct pinctrl_pin_desc *devm_create_pins_from_pld(struct device *dev,
+						   const struct jhb100_pin_layout_desc *desc,
+						   const char *prefix,
+						   unsigned int *total_pins,
+						   unsigned int *total_gpios,
+						   s8 **gpio_func_sel_arr)
+{
+	struct pinctrl_pin_desc *pins = NULL;
+	unsigned int i, j, ngpios = 0, npins = 0, pin_index = 0;
+	unsigned int same_name_found = 0;
+	s8 *arr;
+
+	if (!dev || !desc || !prefix) {
+		dev_err(dev, "Invalid parameters: desc=%p, prefix=%s\n",
+			desc, prefix);
+		return ERR_PTR(-EINVAL);
+	}
+
+	for (i = 0; desc[i].pin_start != 0xff; i++) {
+		if (!desc[i].pin_cnt) {
+			dev_err(dev, "Invalid pin cnt\n");
+			return ERR_PTR(-EINVAL);
+		}
+
+		npins += desc[i].pin_cnt;
+	}
+
+	if (npins == 0) {
+		dev_err(dev, "No pins defined\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	dev_dbg(dev, "Total pins to create: %d\n", npins);
+
+	pins = devm_kcalloc(dev, npins, sizeof(*pins), GFP_KERNEL);
+	if (!pins)
+		return ERR_PTR(-ENOMEM);
+
+	arr = devm_kzalloc(dev, npins, GFP_KERNEL);
+	if (!arr)
+		return ERR_PTR(-ENOMEM);
+
+	for (i = 0; desc[i].pin_start != 0xff; i++) {
+		same_name_found = 0;
+
+		for (j = 0; j < i; j++) {
+			if (!strcmp(desc[j].name, desc[i].name)) {
+				same_name_found = 1;
+				break;
+			}
+		}
+
+		for (j = 0; j < desc[i].pin_cnt; j++) {
+			char *name = NULL;
+			int pin_num = desc[i].pin_start + j;
+
+			pins[pin_index].number = pin_num;
+			if (same_name_found) {
+				name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s_%d",
+						      prefix, desc[i].name,
+						      desc[i].pin_start + j);
+			} else {
+				if (desc[i].pin_cnt > 1)
+					name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s_%d",
+							      prefix, desc[i].name, j);
+				else
+					name = devm_kasprintf(dev, GFP_KERNEL, "%s_%s",
+							      prefix, desc[i].name);
+			}
+
+			if (!name) {
+				dev_err(dev, "Failed to allocate pin name for pin %d\n",
+					pin_num);
+				return ERR_PTR(-ENOMEM);
+			}
+
+			if (!strcmp(desc[i].name, "gpio") || desc[i].gpio_func_sel != -1)
+				ngpios++;
+
+			pins[pin_index].name = name;
+			arr[pin_index] = desc[i].gpio_func_sel;
+			pin_index++;
+		}
+	}
+
+	*total_pins = npins;
+	*total_gpios = ngpios;
+	*gpio_func_sel_arr = arr;
+
+	return pins;
+}
+
+static bool starfive_of_node_instance_match(struct gpio_chip *gc, unsigned int i)
+{
+	struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
+
+	if (i >= sfp->num_banks)
+		return false;
+
+	return (gc == &sfp->banks[i].gc);
+}
+
+int jhb100_pinctrl_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct gpio_irq_chip *girq;
+	const struct jhb100_pinctrl_domain_info *info;
+	struct jhb100_pinctrl *sfp;
+	struct pinctrl_desc *jhb100_pinctrl_desc;
+	struct starfive_pinctrl_regs *pinctrl_regs;
+	struct reset_control *rst;
+	struct clk *clk;
+	int ret;
+	int irq;
+
+	info = of_device_get_match_data(&pdev->dev);
+	if (!info)
+		return -ENODEV;
+
+	pinctrl_regs = info->regs;
+
+	sfp = devm_kzalloc(dev, sizeof(*sfp), GFP_KERNEL);
+	if (!sfp)
+		return -ENOMEM;
+
+	sfp->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(sfp->base))
+		return PTR_ERR(sfp->base);
+
+	clk = devm_clk_get_optional_enabled(dev, NULL);
+	if (IS_ERR(clk))
+		return dev_err_probe(dev, PTR_ERR(clk), "could not get & enable clock\n");
+
+	rst = devm_reset_control_array_get_optional_shared(dev);
+	if (IS_ERR(rst))
+		return dev_err_probe(dev, PTR_ERR(rst), "could not get reset control\n");
+
+	/*
+	 * we don't want to assert reset and risk undoing pin muxing for the
+	 * early boot serial console, but let's make sure the reset line is
+	 * deasserted in case someone runs a really minimal bootloader.
+	 */
+	ret = reset_control_deassert(rst);
+	if (ret)
+		return dev_err_probe(dev, ret, "could not deassert reset\n");
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	sfp->pins = devm_create_pins_from_pld(dev, info->pl_desc, info->name,
+					      &sfp->npins, &sfp->ngpios,
+					      &sfp->gpio_func_sel_arr);
+	if (IS_ERR(sfp->pins))
+		return PTR_ERR(sfp->pins);
+
+	jhb100_pinctrl_desc = devm_kzalloc(&pdev->dev,
+					   sizeof(*jhb100_pinctrl_desc),
+					   GFP_KERNEL);
+	if (!jhb100_pinctrl_desc)
+		return -ENOMEM;
+
+	jhb100_pinctrl_desc->name = dev_name(dev);
+	jhb100_pinctrl_desc->pctlops = &jhb100_pinctrl_ops;
+	jhb100_pinctrl_desc->pmxops = &jhb100_pinmux_ops;
+	jhb100_pinctrl_desc->confops = &jhb100_pinconf_ops;
+	jhb100_pinctrl_desc->owner = THIS_MODULE;
+	jhb100_pinctrl_desc->pins = sfp->pins;
+	jhb100_pinctrl_desc->npins = sfp->npins;
+
+	sfp->info = info;
+	sfp->dev = dev;
+	platform_set_drvdata(pdev, sfp);
+
+	raw_spin_lock_init(&sfp->lock);
+	mutex_init(&sfp->mutex);
+
+	ret = devm_pinctrl_register_and_init(dev, jhb100_pinctrl_desc,
+					     sfp, &sfp->pctl);
+	if (ret)
+		return dev_err_probe(dev, ret,
+				     "could not register pinctrl driver\n");
+
+	ret = pinctrl_enable(sfp->pctl);
+	if (ret)
+		return ret;
+
+	sfp->num_banks = DIV_ROUND_UP(sfp->ngpios, JHB100_NR_GPIOS_PER_BANK);
+
+	for (unsigned int i = 0; i < sfp->num_banks; i++) {
+		if (sfp->ngpios > (i + 1) * JHB100_NR_GPIOS_PER_BANK)
+			sfp->banks[i].gc.ngpio = (i + 1) * JHB100_NR_GPIOS_PER_BANK;
+		else
+			sfp->banks[i].gc.ngpio = sfp->ngpios - i * JHB100_NR_GPIOS_PER_BANK;
+
+		sfp->banks[i].id = i;
+
+		sfp->banks[i].gc.parent = dev;
+		sfp->banks[i].gc.label = dev_name(dev);
+		sfp->banks[i].gc.owner = THIS_MODULE;
+		sfp->banks[i].gc.request = pinctrl_gpio_request;
+		sfp->banks[i].gc.free = pinctrl_gpio_free;
+		sfp->banks[i].gc.get_direction = jhb100_gpio_get_direction;
+		sfp->banks[i].gc.direction_input = jhb100_gpio_direction_input;
+		sfp->banks[i].gc.direction_output = jhb100_gpio_direction_output;
+		sfp->banks[i].gc.get = jhb100_gpio_get;
+		sfp->banks[i].gc.set = jhb100_gpio_set;
+		sfp->banks[i].gc.set_config = gpiochip_generic_config;
+		sfp->banks[i].gc.base = -1;
+		sfp->banks[i].gc.of_gpio_n_cells = 3;
+		sfp->banks[i].gc.of_node_instance_match = starfive_of_node_instance_match;
+
+		girq = &sfp->banks[i].gc.irq;
+		girq->handler = handle_simple_irq;
+
+		gpio_irq_chip_set_chip(girq, &jhb100_irq_chip);
+
+		/* mask all GPIO interrupts */
+		writel_relaxed(0U, sfp->base + pinctrl_regs->irq_en + 4 * i);
+		/* clear all interrupts */
+		writel_relaxed(~0U, sfp->base + pinctrl_regs->irq_clr + 4 * i);
+		writel_relaxed(0U, sfp->base + pinctrl_regs->irq_clr + 4 * i);
+
+		ret = devm_request_irq(dev, irq, jhb100_gpio_irq_handler, IRQF_SHARED,
+				       sfp->banks[i].gc.label, &sfp->banks[i]);
+		if (ret < 0)
+			return dev_err_probe(dev, ret, "failed to register IRQ\n");
+
+		ret = devm_gpiochip_add_data(dev, &sfp->banks[i].gc, sfp);
+		if (ret)
+			return dev_err_probe(dev, ret, "could not register gpiochip\n");
+	}
+
+	dev_info(dev, "StarFive JHB100 GPIO chip registered %d GPIOs\n",
+		 sfp->ngpios);
+
+	ret = check_pinctrl_layouts(sfp, info->crl_desc);
+	if (ret)
+		return ret;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(jhb100_pinctrl_probe);
+
+MODULE_DESCRIPTION("Pinctrl driver for the StarFive JHB100 SoC");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h
new file mode 100644
index 000000000000..529b358abbbe
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.h
@@ -0,0 +1,152 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#ifndef __PINCTRL_STARFIVE_JHB100_H__
+#define __PINCTRL_STARFIVE_JHB100_H__
+
+#include <linux/gpio/driver.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinmux.h>
+
+#define JHB100_MAX_BANKS			2
+
+struct jhb100_pin_layout_desc {
+	unsigned int pin_start;
+	unsigned int pin_cnt;
+	const char *name;
+	s8 gpio_func_sel;
+};
+
+struct jhb100_gpio_bank {
+	struct gpio_chip gc;
+	unsigned int id;
+};
+
+struct jhb100_pinctrl {
+	struct device *dev;
+	struct jhb100_gpio_bank banks[JHB100_MAX_BANKS];
+	unsigned int num_banks;
+	struct pinctrl_gpio_range gpios;
+	raw_spinlock_t lock;
+	const char *iodomain_name;
+	void __iomem *base;
+	struct pinctrl_dev *pctl;
+	/* register read/write mutex */
+	struct mutex mutex;
+	const struct jhb100_pinctrl_domain_info *info;
+	/* wakeup */
+	int wakeup_irq;
+	struct irq_domain *irq_domain;
+	const struct pinctrl_pin_desc *pins;
+	unsigned int npins;
+	unsigned int ngpios;
+	s8 *gpio_func_sel_arr;
+};
+
+struct pinvref_desc {
+	unsigned int range;
+	u32 pin_grp[32];
+	u32 num_pins;
+};
+
+struct pinvref_reg {
+	unsigned int reg;
+	const struct pinvref_desc *pv_desc;
+	u32 num_pv;
+};
+
+struct gpio_irq_reg {
+	unsigned int reg;
+	unsigned int width_per_pin;
+};
+
+struct starfive_pinctrl_regs {
+	struct pinvref_reg vref;
+	struct gpio_irq_reg func_sel;
+	unsigned int config;
+	unsigned int output;
+	unsigned int output_en;
+	unsigned int gpio_status;
+	unsigned int irq_en;
+	unsigned int irq_status;
+	unsigned int irq_clr;
+	unsigned int irq_trigger;
+	unsigned int irq_level;
+	unsigned int irq_both_edge;
+	unsigned int irq_edge;
+};
+
+struct reg_layout_field {
+	unsigned char shift;
+	unsigned char width;
+};
+
+#define RL_DESC_SUPPORTED(crl_desc, field) ({ \
+	typeof(crl_desc) _desc = (crl_desc); \
+	(_desc && _desc->field.width > 0); \
+})
+
+#define RL_DESC_SHIFT(crl_desc, field) ({ \
+	typeof(crl_desc) __desc = (crl_desc); \
+	__desc->field.shift; \
+})
+
+#define RL_DESC_GENMASK(crl_desc, field) ({ \
+	typeof(crl_desc) __desc = (crl_desc); \
+	RL_DESC_SUPPORTED(__desc, field) ? \
+	GENMASK(__desc->field.shift + __desc->field.width - 1, __desc->field.shift) : 0; \
+})
+
+struct config_reg_layout_desc {
+	unsigned int pin_start;
+	unsigned int pin_cnt;
+
+	struct reg_layout_field debounce_width;
+	struct reg_layout_field drive_strength_2bit;
+	struct reg_layout_field drive_strength_3bit;
+	struct reg_layout_field function;
+	struct reg_layout_field input_enable;
+	struct reg_layout_field vsel;
+	struct reg_layout_field mode_select;
+	struct reg_layout_field open_drain_pull_up_sel;
+	struct reg_layout_field pull_down;
+	struct reg_layout_field pull_up;
+	struct reg_layout_field reserved;
+	struct reg_layout_field retention_signal_bus;
+	struct reg_layout_field schmitt_trigger_select;
+	struct reg_layout_field slew_rate;
+};
+
+struct funcsel_reg_layout_desc {
+	unsigned int pin_start;
+	unsigned int pin_cnt;
+	unsigned int width;
+};
+
+#define JHB100_FUNC_MAPS_MAX_PIN(n)	((n) + 1)
+
+struct jhb100_pinctrl_func_maps {
+	char *func;
+	unsigned char val;
+	u32 max_pin;
+};
+
+struct jhb100_pinctrl_domain_info {
+	const char *name;
+	const struct pinctrl_pin_desc *pins;
+	const struct jhb100_pin_layout_desc *pl_desc;
+	const struct jhb100_pinctrl_func_maps *fmaps;
+	u32 num_maps;
+	struct config_reg_layout_desc *crl_desc;
+	struct starfive_pinctrl_regs *regs;
+};
+
+int jhb100_pinctrl_probe(struct platform_device *pdev);
+
+#endif /* __PINCTRL_STARFIVE_JHB100_H__ */
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:44 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:44 -0700
Subject: [PATCH v3 18/21] pinctrl: starfive: Add StarFive JHB100 per2pok controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-19-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC Peripheral-2 Power OK
(per2pok) pinctrl controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/starfive/Kconfig              | 12 +++
 drivers/pinctrl/starfive/Makefile             |  1 +
 .../pinctrl-starfive-jhb100-per2pok.c         | 97 +++++++++++++++++++
 3 files changed, 110 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2pok.c

diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index edc3b6d9c8d7..bf5915e0a5f2 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -91,6 +91,18 @@ config PINCTRL_STARFIVE_JHB100_PER2
 	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
 	  and interrupts on input changes.
 
+config PINCTRL_STARFIVE_JHB100_PER2POK
+	tristate "StarFive JHB100 SoC Peripheral-2 Power OK pinctrl and GPIO driver"
+	depends on ARCH_STARFIVE || COMPILE_TEST
+	depends on OF
+	select PINCTRL_STARFIVE_JHB100
+	default ARCH_STARFIVE
+	help
+	  Say yes here to support Peripheral-2 Power OK pin control on the StarFive JHB100 SoC.
+	  This also provides an interface to the GPIO pins not used by other
+	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
+	  and interrupts on input changes.
+
 config PINCTRL_STARFIVE_JHB100_SYS0
 	tristate "StarFive JHB100 SoC System-0 pinctrl and GPIO driver"
 	depends on ARCH_STARFIVE || COMPILE_TEST
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index 33213bd1919f..213002da9cdd 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)		+= pinctrl-starfive-jhb100.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER0)	+= pinctrl-starfive-jhb100-per0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER1)	+= pinctrl-starfive-jhb100-per1.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER2)	+= pinctrl-starfive-jhb100-per2.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER2POK)	+= pinctrl-starfive-jhb100-per2pok.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0H)	+= pinctrl-starfive-jhb100-sys0h.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS1)	+= pinctrl-starfive-jhb100-sys1.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2pok.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2pok.c
new file mode 100644
index 000000000000..abeeee2e7a00
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2pok.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC Peripheral-2 Power OK domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_per2pok_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 10, .name = "gpio", .gpio_func_sel = 0 },
+	{ .pin_start = 10, .pin_cnt = 8, .name = "pwm_channel", .gpio_func_sel = 1 },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_per2pok_pinctrl_rl_desc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 18,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 8 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{ 0xff },
+};
+
+struct starfive_pinctrl_regs jhb100_per2pok_pinctrl_regs = {
+	.func_sel		= { .reg = 0x58, .width_per_pin = 2 },
+	.config			= 0x04,
+	.output			= 0x4c,
+	.output_en		= 0x50,
+	.gpio_status		= 0x54,
+	.irq_en			= 0x60,
+	.irq_status		= 0x64,
+	.irq_clr		= 0x68,
+	.irq_trigger		= 0x6c,
+	.irq_level		= 0x70,
+	.irq_both_edge		= 0x74,
+	.irq_edge		= 0x78,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_per2pok[] = {
+	{ .func = "can",		.val = 1 },
+	{ .func = "gpio",		.val = 0,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER2POK_GPIO_D40) },
+	{ .func = "gpio",		.val = 1,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER2POK_GPIO_D48) },
+	{ .func = "host0_port80",	.val = 2 },
+	{ .func = "host1_port80",	.val = 3 },
+	{ .func = "passthru",		.val = 2,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER2POK_GPIO_D36) },
+	{ .func = "passthru",		.val = 1,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER2POK_GPIO_D40) },
+	{ .func = "pwm",		.val = 0 },
+};
+
+static const struct jhb100_pinctrl_domain_info jhb100_per2pok_pinctrl_info = {
+	.name			= "jhb100-per2pok",
+	.pl_desc		= jhb100_per2pok_pl_desc,
+	.crl_desc		= jhb100_per2pok_pinctrl_rl_desc,
+	.regs			= &jhb100_per2pok_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_per2pok,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_per2pok),
+};
+
+static const struct of_device_id jhb100_per2pok_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-per2pok-pinctrl",
+		.data = &jhb100_per2pok_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_per2pok_pinctrl_of_match);
+
+static struct platform_driver jhb100_per2pok_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-per2pok-pinctrl",
+		.of_match_table = jhb100_per2pok_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_per2pok_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC Peripheral-2 Power OK domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:28 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:28 -0700
Subject: [PATCH v3 02/21] pinctrl: pinconf-generic: Add property 'input-debounce-ns'
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-3-changhuang.liang@starfivetech.com>

Add 'input-debounce-ns' to the generic parameters used for parsing DT
files, along with the corresponding configuration parameter
PIN_CONFIG_INPUT_DEBOUNCE_NS. This allows debounce time to be specified
in nanoseconds as an alternative to the existing 'input-debounce'
property which uses microseconds

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/pinconf-generic.c       | 2 ++
 include/linux/pinctrl/pinconf-generic.h | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 64ed28309788..9d67e2d26e28 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -43,6 +43,7 @@ static const struct pin_config_item conf_items[] = {
 	PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true),
 	PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true),
 	PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true),
+	PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE_NS, "input debounce", "nsec", true),
 	PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false),
 	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false),
 	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_UV, "input schmitt threshold", "uV", true),
@@ -185,6 +186,7 @@ static const struct pinconf_generic_params dt_params[] = {
 	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
 	{ "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
 	{ "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
+	{ "input-debounce-ns", PIN_CONFIG_INPUT_DEBOUNCE_NS, 0 },
 	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
 	{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
 	{ "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
index a5d4b2d8633a..1df63c732b99 100644
--- a/include/linux/pinctrl/pinconf-generic.h
+++ b/include/linux/pinctrl/pinconf-generic.h
@@ -71,6 +71,10 @@ struct pinctrl_map;
  *	which means it will wait for signals to settle when reading inputs. The
  *	argument gives the debounce time in usecs. Setting the
  *	argument to zero turns debouncing off.
+ * @PIN_CONFIG_INPUT_DEBOUNCE_NS: this will configure the pin to debounce mode,
+ *	which means it will wait for signals to settle when reading inputs. The
+ *	argument gives the debounce time in nsecs. Setting the
+ *	argument to zero turns debouncing off.
  * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input.  Note that this does not
  *	affect the pin's ability to drive output.  1 enables input, 0 disables
  *	input.
@@ -143,6 +147,7 @@ enum pin_config_param {
 	PIN_CONFIG_DRIVE_STRENGTH,
 	PIN_CONFIG_DRIVE_STRENGTH_UA,
 	PIN_CONFIG_INPUT_DEBOUNCE,
+	PIN_CONFIG_INPUT_DEBOUNCE_NS,
 	PIN_CONFIG_INPUT_ENABLE,
 	PIN_CONFIG_INPUT_SCHMITT,
 	PIN_CONFIG_INPUT_SCHMITT_ENABLE,
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:32 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:32 -0700
Subject: [PATCH v3 06/21] pinctrl: starfive: Add StarFive JHB100 sys0h controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-7-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC System-0 Host(sys0h) pinctrl
controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/starfive/Kconfig              | 12 +++
 drivers/pinctrl/starfive/Makefile             |  1 +
 .../starfive/pinctrl-starfive-jhb100-sys0h.c  | 97 +++++++++++++++++++
 3 files changed, 110 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0h.c

diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index 548a1b133f81..1c87f64830ed 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -66,3 +66,15 @@ config PINCTRL_STARFIVE_JHB100_SYS0
 	  This also provides an interface to the GPIO pins not used by other
 	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
 	  and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JHB100_SYS0H
+        tristate "StarFive JHB100 SoC System-0 Host pinctrl and GPIO driver"
+        depends on ARCH_STARFIVE  || COMPILE_TEST
+        depends on OF
+        select PINCTRL_STARFIVE_JHB100
+        default ARCH_STARFIVE
+        help
+          Say yes here to support System-0 Host pin control on the StarFive JHB100 SoC.
+          This also provides an interface to the GPIO pins not used by other
+          peripherals supporting inputs, outputs, configuring pull-up/pull-down
+          and interrupts on input changes.
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index c0d368f413bc..b26156a6d0eb 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON)	+= pinctrl-starfive-jh7110-aon.o
 
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)		+= pinctrl-starfive-jhb100.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0H)	+= pinctrl-starfive-jhb100-sys0h.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0h.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0h.c
new file mode 100644
index 000000000000..80dc35321a95
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0h.c
@@ -0,0 +1,97 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC System-0 host domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_sys0h_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 7, .name = "gpio", .gpio_func_sel = 0 },
+	{ .pin_start = 7, .pin_cnt = 1, .name = "espi0_reset", .gpio_func_sel = 1 },
+	{ .pin_start = 8, .pin_cnt = 4, .name = "gpio", .gpio_func_sel = 0 },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_sys0h_pinctrl_rl_desc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 12,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 8 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{ 0xff },
+};
+
+struct starfive_pinctrl_regs jhb100_sys0h_pinctrl_regs = {
+	.func_sel		= { .reg = 0x40, .width_per_pin = 2 },
+	.config			= 0x04,
+	.output			= 0x34,
+	.output_en		= 0x38,
+	.gpio_status		= 0x3c,
+	.irq_en			= 0x44,
+	.irq_status		= 0x48,
+	.irq_clr		= 0x4c,
+	.irq_trigger		= 0x50,
+	.irq_level		= 0x54,
+	.irq_both_edge		= 0x58,
+	.irq_edge		= 0x5c,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_sys0h[] = {
+	{ .func = "espi",		.val = 1 },
+	{ .func = "espi_reset",		.val = 0 },
+	{ .func = "espi0_vw",		.val = 1 },
+	{ .func = "espi1_vw",		.val = 2 },
+	{ .func = "gpio",		.val = 0,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_SYS0H_GPIO_A10) },
+	{ .func = "gpio",		.val = 1,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_SYS0H_GPIO_A11) },
+	{ .func = "gpio",		.val = 0,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_SYS0H_GPIO_A15) },
+	{ .func = "scap_trigger",	.val = 3 },
+};
+
+static struct jhb100_pinctrl_domain_info jhb100_sys0h_pinctrl_info = {
+	.name			= "jhb100-sys0h",
+	.pl_desc		= jhb100_sys0h_pl_desc,
+	.crl_desc		= jhb100_sys0h_pinctrl_rl_desc,
+	.regs			= &jhb100_sys0h_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_sys0h,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_sys0h),
+};
+
+static const struct of_device_id jhb100_sys0h_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-sys0h-pinctrl",
+		.data = &jhb100_sys0h_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_sys0h_pinctrl_of_match);
+
+static struct platform_driver jhb100_sys0h_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-sys0h-pinctrl",
+		.of_match_table = jhb100_sys0h_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_sys0h_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC System-0 host domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:33 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:33 -0700
Subject: [PATCH v3 07/21] dt-bindings: pinctrl: Add starfive,jhb100-sys1-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-8-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC System-1(sys1) pinctrl
controller.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../pinctrl/starfive,jhb100-sys1-pinctrl.yaml | 161 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  10 ++
 2 files changed, 171 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys1-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys1-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys1-pinctrl.yaml
new file mode 100644
index 000000000000..54e7f4b795bc
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys1-pinctrl.yaml
@@ -0,0 +1,161 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-sys1-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 System-1 Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "sys1" pinctrl domain.
+
+  The "sys1" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO pad configuration.
+  - GPIO interrupt handling.
+
+  In the SYS1 Pin Controller, there are 8 multi-function GPIO_PADs. Each of
+  them can be multiplexed to different hardware blocks through function
+  selection. Each iopad has a maximum of up to 4 functions - 0, 1, 2, and 3.
+  Function 0 is the default function which is generally the GPIO function
+  (or occasionally, it can be a peripheral signal).
+  Function 1, 2, and 3 are the alternate functions or peripheral signals that
+  can be routed to the iopad. The function selection can be carried out by
+  writing the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds.
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-sys1-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce nanoseconds
+          and drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ espi, espi_reset, gpio, host0_port80, host1_port80 ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            type: boolean
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+
+required:
+  - compatible
+  - reg
+  - resets
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_sys1: pinctrl at 13081000 {
+            compatible = "starfive,jhb100-sys1-pinctrl";
+            reg = <0x0 0x13081000 0x0 0x1000>;
+            resets = <&sys1crg 2>;
+            interrupts = <58>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_sys1 0 0 0 8>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
index 38d5a94e92e3..30704a5a3418 100644
--- a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -28,4 +28,14 @@
 #define PADNUM_SYS0H_GPIO_A14				10
 #define PADNUM_SYS0H_GPIO_A15				11
 
+/* sys1 pad numbers */
+#define PADNUM_SYS1_GPIO_A16				0
+#define PADNUM_SYS1_GPIO_A17				1
+#define PADNUM_SYS1_GPIO_A18				2
+#define PADNUM_SYS1_GPIO_A19				3
+#define PADNUM_SYS1_GPIO_A20				4
+#define PADNUM_SYS1_GPIO_A21				5
+#define PADNUM_SYS1_GPIO_A22				6
+#define PADNUM_SYS1_GPIO_A23				7
+
 #endif
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:45 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:45 -0700
Subject: [PATCH v3 19/21] dt-bindings: pinctrl: Add starfive,jhb100-per3-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-20-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC Peripheral-3(per3) pinctrl
controller.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../pinctrl/starfive,jhb100-per3-pinctrl.yaml | 165 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  14 ++
 2 files changed, 179 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per3-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per3-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per3-pinctrl.yaml
new file mode 100644
index 000000000000..26cdc9b48d8a
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per3-pinctrl.yaml
@@ -0,0 +1,165 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-per3-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 Peripheral-3 Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "per3" pinctrl domain.
+
+  The "per3" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO interrupt handling.
+
+  In the Peripheral-3 Pin Controller, there are 11 multi-function GPIO_PADs.
+  Each of them can be multiplexed to several peripherals through function
+  selection. Each iopad has a maximum of up to 2 functions - 0 and 1.
+  Function 0 is the default function which is generally the GPIO function.
+  Function 1 is the alternate function or peripheral signal that can be
+  routed to an iopad. The function selection can be carried out by writing
+  the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds, power source.
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-per3-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce nanoseconds,
+          power-source and drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ gmac_mdio, gmac_rmii, gpio ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            type: boolean
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          power-source:
+            enum: [ 0, 2 ]
+            description: |
+                0: power supply of 3.3V
+                2: power supply of 1.8V
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+
+required:
+  - compatible
+  - reg
+  - resets
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_per3: pinctrl at 11c42000 {
+            compatible = "starfive,jhb100-per3-pinctrl";
+            reg = <0x0 0x11c42000 0x0 0x1000>;
+            resets = <&per3crg 6>;
+            interrupts = <64>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_per3 0 0 0 11>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
index 3ceaf9ceeecb..922b152b737c 100644
--- a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -230,6 +230,20 @@
 #define PADNUM_PER2POK_GPIO_D47				16
 #define PADNUM_PER2POK_GPIO_D48				17
 
+/* per3 pad numbers */
+#define PADNUM_PER3_GPIO_E0				0
+#define PADNUM_PER3_GPIO_E1				1
+#define PADNUM_PER3_GPIO_E2				2
+#define PADNUM_PER3_GPIO_E3				3
+#define PADNUM_PER3_GPIO_E4				4
+#define PADNUM_PER3_GPIO_E5				5
+#define PADNUM_PER3_GPIO_E6				6
+#define PADNUM_PER3_GPIO_E7				7
+#define PADNUM_PER3_GPIO_E8				8
+#define PADNUM_PER3_GPIO_E9				9
+#define PADNUM_PER3_GPIO_E10				10
+#define PADNUM_PER3_GPIO_E11				11
+
 /* power-source value */
 #define JHB100_PINVREF_3_3V				0
 #define JHB100_PINVREF_2_5V				1
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:35 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:35 -0700
Subject: [PATCH v3 09/21] dt-bindings: pinctrl: Add starfive,jhb100-sys2-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-10-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC System-2(sys2) pinctrl
controller.

System-2 domain also supports configuring the pin voltage. Add relevant
definitions for power-source configuration.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../pinctrl/starfive,jhb100-sys2-pinctrl.yaml | 169 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  44 +++++
 2 files changed, 213 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys2-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys2-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys2-pinctrl.yaml
new file mode 100644
index 000000000000..e29d8c01b3c4
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-sys2-pinctrl.yaml
@@ -0,0 +1,169 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-sys2-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 System-2 Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "sys2" pinctrl domain.
+
+  The "sys2" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO pad configuration.
+  - GPIO interrupt handling.
+
+  In the SYS2 Pin Controller, there are 37 multi-function GPIO_PADs. Each of
+  them can be multiplexed to different hardware blocks through function
+  selection. Each iopad has a maximum of up to 4 functions - 0, 1, 2, and 3.
+  Function 0 is the default function which is the GPIO function.
+  Function 1, 2, and 3 are the alternate functions or peripheral signals that
+  can be routed to the iopad. The function selection can be carried out by
+  writing the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds, power source.
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-sys2-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce nanoseconds,
+          power-source and drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ gpio, host0_port80, host1_port80, jtag, smbalert, uart ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            type: boolean
+
+          drive-open-drain: true
+
+          drive-push-pull: true
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          power-source:
+            enum: [ 0, 2 ]
+            description: |
+                0: power supply of 3.3V
+                2: power supply of 1.8V
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_sys2: pinctrl at 13082000 {
+            compatible = "starfive,jhb100-sys2-pinctrl";
+            reg = <0x0 0x13082000 0x0 0x1000>;
+            interrupts = <59>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_sys2 0 0 0 32>,
+                          <&pinctrl_sys2 1 0 32 5>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
index 30704a5a3418..e1c6bc8960b7 100644
--- a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -38,4 +38,48 @@
 #define PADNUM_SYS1_GPIO_A22				6
 #define PADNUM_SYS1_GPIO_A23				7
 
+/* sys2 pad numbers */
+#define PADNUM_SYS2_GPIO_A24				0
+#define PADNUM_SYS2_GPIO_A25				1
+#define PADNUM_SYS2_GPIO_A26				2
+#define PADNUM_SYS2_GPIO_A27				3
+#define PADNUM_SYS2_GPIO_A28				4
+#define PADNUM_SYS2_GPIO_A29				5
+#define PADNUM_SYS2_GPIO_A30				6
+#define PADNUM_SYS2_GPIO_A31				7
+#define PADNUM_SYS2_GPIO_A32				8
+#define PADNUM_SYS2_GPIO_A33				9
+#define PADNUM_SYS2_GPIO_A34				10
+#define PADNUM_SYS2_GPIO_A35				11
+#define PADNUM_SYS2_GPIO_A36				12
+#define PADNUM_SYS2_GPIO_A37				13
+#define PADNUM_SYS2_GPIO_A38				14
+#define PADNUM_SYS2_GPIO_A39				15
+#define PADNUM_SYS2_GPIO_A40				16
+#define PADNUM_SYS2_GPIO_A41				17
+#define PADNUM_SYS2_GPIO_A42				18
+#define PADNUM_SYS2_GPIO_A43				19
+#define PADNUM_SYS2_GPIO_A44				20
+#define PADNUM_SYS2_GPIO_A45				21
+#define PADNUM_SYS2_GPIO_A46				22
+#define PADNUM_SYS2_GPIO_A47				23
+#define PADNUM_SYS2_GPIO_A48				24
+#define PADNUM_SYS2_GPIO_A49				25
+#define PADNUM_SYS2_GPIO_A50				26
+#define PADNUM_SYS2_GPIO_A51				27
+#define PADNUM_SYS2_GPIO_A52				28
+#define PADNUM_SYS2_GPIO_A53				29
+#define PADNUM_SYS2_GPIO_A54				30
+#define PADNUM_SYS2_GPIO_A55				31
+#define PADNUM_SYS2_GPIO_A56				32
+#define PADNUM_SYS2_GPIO_A57				33
+#define PADNUM_SYS2_GPIO_A58				34
+#define PADNUM_SYS2_GPIO_A59				35
+#define PADNUM_SYS2_GPIO_A60				36
+
+/* power-source value */
+#define JHB100_PINVREF_3_3V				0
+#define JHB100_PINVREF_2_5V				1
+#define JHB100_PINVREF_1_8V				2
+
 #endif
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:36 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:36 -0700
Subject: [PATCH v3 10/21] pinctrl: starfive: Add StarFive JHB100 sys2 controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-11-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC System-2(sys2) pinctrl
controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/starfive/Kconfig              |  12 ++
 drivers/pinctrl/starfive/Makefile             |   1 +
 .../starfive/pinctrl-starfive-jhb100-sys2.c   | 134 ++++++++++++++++++
 3 files changed, 147 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys2.c

diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index 882d621eaf57..da11d486779a 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -90,3 +90,15 @@ config PINCTRL_STARFIVE_JHB100_SYS1
 	  This also provides an interface to the GPIO pins not used by other
 	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
 	  and interrupts on input changes.
+
+config PINCTRL_STARFIVE_JHB100_SYS2
+	tristate "StarFive JHB100 SoC System-2 pinctrl and GPIO driver"
+	depends on ARCH_STARFIVE || COMPILE_TEST
+	depends on OF
+	select PINCTRL_STARFIVE_JHB100
+	default ARCH_STARFIVE
+	help
+	  Say yes here to support System-2 pin control on the StarFive JHB100 SoC.
+	  This also provides an interface to the GPIO pins not used by other
+	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
+	  and interrupts on input changes.
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index 8d96cf80d377..b817ad93b91d 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)		+= pinctrl-starfive-jhb100.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0H)	+= pinctrl-starfive-jhb100-sys0h.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS1)	+= pinctrl-starfive-jhb100-sys1.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS2)	+= pinctrl-starfive-jhb100-sys2.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys2.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys2.c
new file mode 100644
index 000000000000..59ea9bdaa078
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys2.c
@@ -0,0 +1,134 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC System-2 domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_sys2_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 37, .name = "gpio", .gpio_func_sel = 0 },
+	{ .pin_start = 37, .pin_cnt = 1, .name = "jtag_tck", .gpio_func_sel = -1 },
+	{ .pin_start = 38, .pin_cnt = 1, .name = "jtag_tresetn", .gpio_func_sel = -1 },
+	{ .pin_start = 39, .pin_cnt = 1, .name = "jtag_tmc", .gpio_func_sel = -1 },
+	{ .pin_start = 40, .pin_cnt = 1, .name = "jtag_tdi", .gpio_func_sel = -1 },
+	{ .pin_start = 41, .pin_cnt = 1, .name = "jtag_tdo", .gpio_func_sel = -1 },
+	{ .pin_start = 42, .pin_cnt = 1, .name = "jtag_hpd", .gpio_func_sel = -1 },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_sys2_pinctrl_rl_desc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 37,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 8 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{
+		.pin_start			= 37,
+		.pin_cnt			= 6,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 25 },
+	},
+	{ 0xff },
+};
+
+static const struct pinvref_desc pinvref_desc_sys2[] = {
+	{
+		/* gpiow */
+		.pin_grp = {
+			PADNUM_SYS2_GPIO_A36,
+			PADNUM_SYS2_GPIO_A37,
+			PADNUM_SYS2_GPIO_A38,
+			PADNUM_SYS2_GPIO_A39
+		},
+		.num_pins = 4,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+	{
+		/* gpiow-inner */
+		.pin_grp = {
+			PADNUM_SYS2_GPIO_A40,
+			PADNUM_SYS2_GPIO_A41,
+			PADNUM_SYS2_GPIO_A42,
+			PADNUM_SYS2_GPIO_A43
+		},
+		.num_pins = 4,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+};
+
+struct starfive_pinctrl_regs jhb100_sys2_pinctrl_regs = {
+	.vref			= { .reg = 0x000, .pv_desc = pinvref_desc_sys2,
+				    .num_pv = ARRAY_SIZE(pinvref_desc_sys2) },
+	.func_sel		= { .reg = 0x0d4, .width_per_pin = 2 },
+	.config			= 0x010,
+	.output			= 0x0bc,
+	.output_en		= 0x0c4,
+	.gpio_status		= 0x0cc,
+	.irq_en			= 0x0e0,
+	.irq_status		= 0x0e8,
+	.irq_clr		= 0x0f0,
+	.irq_trigger		= 0x0f8,
+	.irq_level		= 0x100,
+	.irq_both_edge		= 0x108,
+	.irq_edge		= 0x110,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_sys2[] = {
+	{ .func = "gpio",		.val = 0 },
+	{ .func = "host0_port80",	.val = 2 },
+	{ .func = "host1_port80",	.val = 3 },
+	{ .func = "jtag",		.val = 2 },
+	{ .func = "smbalert",		.val = 2 },
+	{ .func = "uart",		.val = 1 },
+};
+
+static const struct jhb100_pinctrl_domain_info jhb100_sys2_pinctrl_info = {
+	.name			= "jhb100-sys2",
+	.pl_desc		= jhb100_sys2_pl_desc,
+	.crl_desc		= jhb100_sys2_pinctrl_rl_desc,
+	.regs			= &jhb100_sys2_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_sys2,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_sys2),
+};
+
+static const struct of_device_id jhb100_sys2_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-sys2-pinctrl",
+		.data = &jhb100_sys2_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_sys2_pinctrl_of_match);
+
+static struct platform_driver jhb100_sys2_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-sys2-pinctrl",
+		.of_match_table = jhb100_sys2_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_sys2_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC System-2 domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:37 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:37 -0700
Subject: [PATCH v3 11/21] dt-bindings: pinctrl: Add starfive,jhb100-per0-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-12-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC Peripheral-0(per0) pinctrl
controller.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../pinctrl/starfive,jhb100-per0-pinctrl.yaml | 179 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  62 ++++++
 2 files changed, 241 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per0-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per0-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per0-pinctrl.yaml
new file mode 100644
index 000000000000..f83801325348
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per0-pinctrl.yaml
@@ -0,0 +1,179 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-per0-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 Peripheral-0 Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "per0" pinctrl domain.
+
+  The "per0" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO pad configuration.
+  - GPIO interrupt handling.
+
+  In the Peripheral-0  Pin Controller, there are 60 multi-function GPIO_PADs.
+  Each of them can be multiplexed to several hardware blocks through function
+  selection. Each iopad has a maximum of up to 3 functions - 0, 1, and 2.
+  Function 0 is the default function which is generally the GPIO function.
+  Function 1 and 2 are the alternate function or signal of an iopad.  The
+  function 1 and function 2 are other optional functions or peripheral
+  signals that can be routed to an iopad. The function selection can be carried
+  out by writing the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds, power source and drive type (open-drain or push-pull).
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-per0-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce nanoseconds,
+          drive-open-drain, drive-push-pull, power-source and drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ gmac_mdio, gpio, i2c, i3c, smbalert, wdt ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            oneOf:
+              - type: boolean
+              - enum: [ 600, 900, 1200, 2000 ]
+                description: Pull up RSEL type resistance values (in ohms)
+            description:
+              For normal pull up type there is no need to specify a resistance
+              value, hence this can be specified as a boolean property.
+              For RSEL pull up type a resistance value (in ohms) can be added.
+
+          drive-open-drain: true
+
+          drive-push-pull: true
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          power-source:
+            enum: [ 0, 2 ]
+            description: |
+                0: power supply of 3.3V
+                2: power supply of 1.8V
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+
+required:
+  - compatible
+  - reg
+  - resets
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_per0: pinctrl at 11a0a000 {
+            compatible = "starfive,jhb100-per0-pinctrl";
+            reg = <0x0 0x11a0a000 0x0 0x1000>;
+            resets = <&per0crg 0>;
+            interrupts = <60>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_per0 0 0 0 32>,
+                          <&pinctrl_per0 1 0 32 28>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
index e1c6bc8960b7..4fc54b9990d3 100644
--- a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -77,6 +77,68 @@
 #define PADNUM_SYS2_GPIO_A59				35
 #define PADNUM_SYS2_GPIO_A60				36
 
+/* per0 pad numbers */
+#define PADNUM_PER0_GPIO_B0				0
+#define PADNUM_PER0_GPIO_B1				1
+#define PADNUM_PER0_GPIO_B2				2
+#define PADNUM_PER0_GPIO_B3				3
+#define PADNUM_PER0_GPIO_B4				4
+#define PADNUM_PER0_GPIO_B5				5
+#define PADNUM_PER0_GPIO_B6				6
+#define PADNUM_PER0_GPIO_B7				7
+#define PADNUM_PER0_GPIO_B8				8
+#define PADNUM_PER0_GPIO_B9				9
+#define PADNUM_PER0_GPIO_B10				10
+#define PADNUM_PER0_GPIO_B11				11
+#define PADNUM_PER0_GPIO_B12				12
+#define PADNUM_PER0_GPIO_B13				13
+#define PADNUM_PER0_GPIO_B14				14
+#define PADNUM_PER0_GPIO_B15				15
+#define PADNUM_PER0_GPIO_B16				16
+#define PADNUM_PER0_GPIO_B17				17
+#define PADNUM_PER0_GPIO_B18				18
+#define PADNUM_PER0_GPIO_B19				19
+#define PADNUM_PER0_GPIO_B20				20
+#define PADNUM_PER0_GPIO_B21				21
+#define PADNUM_PER0_GPIO_B22				22
+#define PADNUM_PER0_GPIO_B23				23
+#define PADNUM_PER0_GPIO_B24				24
+#define PADNUM_PER0_GPIO_B25				25
+#define PADNUM_PER0_GPIO_B26				26
+#define PADNUM_PER0_GPIO_B27				27
+#define PADNUM_PER0_GPIO_B28				28
+#define PADNUM_PER0_GPIO_B29				29
+#define PADNUM_PER0_GPIO_B30				30
+#define PADNUM_PER0_GPIO_B31				31
+#define PADNUM_PER0_GPIO_B32				32
+#define PADNUM_PER0_GPIO_B33				33
+#define PADNUM_PER0_GPIO_B34				34
+#define PADNUM_PER0_GPIO_B35				35
+#define PADNUM_PER0_GPIO_B36				36
+#define PADNUM_PER0_GPIO_B37				37
+#define PADNUM_PER0_GPIO_B38				38
+#define PADNUM_PER0_GPIO_B39				39
+#define PADNUM_PER0_GPIO_B40				40
+#define PADNUM_PER0_GPIO_B41				41
+#define PADNUM_PER0_GPIO_B42				42
+#define PADNUM_PER0_GPIO_B43				43
+#define PADNUM_PER0_GPIO_B44				44
+#define PADNUM_PER0_GPIO_B45				45
+#define PADNUM_PER0_GPIO_B46				46
+#define PADNUM_PER0_GPIO_B47				47
+#define PADNUM_PER0_GPIO_B48				48
+#define PADNUM_PER0_GPIO_B49				49
+#define PADNUM_PER0_GPIO_B50				50
+#define PADNUM_PER0_GPIO_B51				51
+#define PADNUM_PER0_GPIO_B52				52
+#define PADNUM_PER0_GPIO_B53				53
+#define PADNUM_PER0_GPIO_B54				54
+#define PADNUM_PER0_GPIO_B55				55
+#define PADNUM_PER0_GPIO_B56				56
+#define PADNUM_PER0_GPIO_B57				57
+#define PADNUM_PER0_GPIO_B58				58
+#define PADNUM_PER0_GPIO_B59				59
+
 /* power-source value */
 #define JHB100_PINVREF_3_3V				0
 #define JHB100_PINVREF_2_5V				1
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:46 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:46 -0700
Subject: [PATCH v3 20/21] pinctrl: starfive: Add StarFive JHB100 per3 controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-21-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC Peripheral-3(per3) pinctrl
controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/starfive/Kconfig              |  12 ++
 drivers/pinctrl/starfive/Makefile             |   1 +
 .../starfive/pinctrl-starfive-jhb100-per3.c   | 119 ++++++++++++++++++
 3 files changed, 132 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per3.c

diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index bf5915e0a5f2..da1dcdcc4140 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -103,6 +103,18 @@ config PINCTRL_STARFIVE_JHB100_PER2POK
 	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
 	  and interrupts on input changes.
 
+config PINCTRL_STARFIVE_JHB100_PER3
+	tristate "StarFive JHB100 SoC Peripheral-3 pinctrl and GPIO driver"
+	depends on ARCH_STARFIVE || COMPILE_TEST
+	depends on OF
+	select PINCTRL_STARFIVE_JHB100
+	default ARCH_STARFIVE
+	help
+	  Say yes here to support Peripheral-3 pin control on the StarFive JHB100 SoC.
+	  This also provides an interface to the GPIO pins not used by other
+	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
+	  and interrupts on input changes.
+
 config PINCTRL_STARFIVE_JHB100_SYS0
 	tristate "StarFive JHB100 SoC System-0 pinctrl and GPIO driver"
 	depends on ARCH_STARFIVE || COMPILE_TEST
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index 213002da9cdd..351fce524fec 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER0)	+= pinctrl-starfive-jhb100-per0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER1)	+= pinctrl-starfive-jhb100-per1.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER2)	+= pinctrl-starfive-jhb100-per2.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER2POK)	+= pinctrl-starfive-jhb100-per2pok.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER3)	+= pinctrl-starfive-jhb100-per3.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0H)	+= pinctrl-starfive-jhb100-sys0h.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS1)	+= pinctrl-starfive-jhb100-sys1.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per3.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per3.c
new file mode 100644
index 000000000000..1379599c99a8
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per3.c
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC Peripheral-3 domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_per3_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 11, .name = "gpio", .gpio_func_sel = 0 },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_per3_pinctrl_rl_desc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 2,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 8 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{
+		.pin_start			= 2,
+		.pin_cnt			= 9,
+		.input_enable			= { .shift = 0, .width = 1 },
+		.slew_rate			= { .shift = 1, .width = 1 },
+		.vsel				= { .shift = 2, .width = 2 },
+		.reserved			= { .shift = 4, .width = 11 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{ 0xff },
+};
+
+static const struct pinvref_desc pinvref_desc_per3[] = {
+	{
+		/* gpios */
+		.pin_grp = {
+			PADNUM_PER3_GPIO_E0,
+			PADNUM_PER3_GPIO_E1,
+			PADNUM_PER3_GPIO_E2,
+			PADNUM_PER3_GPIO_E3,
+			PADNUM_PER3_GPIO_E4,
+			PADNUM_PER3_GPIO_E5,
+			PADNUM_PER3_GPIO_E6,
+			PADNUM_PER3_GPIO_E7,
+			PADNUM_PER3_GPIO_E8,
+			PADNUM_PER3_GPIO_E9,
+			PADNUM_PER3_GPIO_E10
+		},
+		.num_pins = 11,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+};
+
+struct starfive_pinctrl_regs jhb100_per3_pinctrl_regs = {
+	.vref			= { .reg = 0x00, .pv_desc = pinvref_desc_per3,
+				    .num_pv = ARRAY_SIZE(pinvref_desc_per3) },
+	.func_sel		= { .reg = 0x3c, .width_per_pin = 2 },
+	.config			= 0x04,
+	.output			= 0x30,
+	.output_en		= 0x34,
+	.gpio_status		= 0x38,
+	.irq_en			= 0x40,
+	.irq_status		= 0x44,
+	.irq_clr		= 0x48,
+	.irq_trigger		= 0x4c,
+	.irq_level		= 0x50,
+	.irq_both_edge		= 0x54,
+	.irq_edge		= 0x58,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_per3[] = {
+	{ .func = "gmac_mdio",		.val = 1 },
+	{ .func = "gmac_rmii",		.val = 1 },
+	{ .func = "gpio",		.val = 0 },
+};
+
+static const struct jhb100_pinctrl_domain_info jhb100_per3_pinctrl_info = {
+	.name			= "jhb100-per3",
+	.pl_desc		= jhb100_per3_pl_desc,
+	.crl_desc		= jhb100_per3_pinctrl_rl_desc,
+	.regs			= &jhb100_per3_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_per3,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_per3),
+};
+
+static const struct of_device_id jhb100_per3_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-per3-pinctrl",
+		.data = &jhb100_per3_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_per3_pinctrl_of_match);
+
+static struct platform_driver jhb100_per3_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-per3-pinctrl",
+		.of_match_table = jhb100_per3_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_per3_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC Peripheral-3 domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:38 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:38 -0700
Subject: [PATCH v3 12/21] pinctrl: starfive: Add StarFive JHB100 per0 controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-13-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC Peripheral-0(per0) pinctrl
controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/starfive/Kconfig              |  12 ++
 drivers/pinctrl/starfive/Makefile             |   1 +
 .../starfive/pinctrl-starfive-jhb100-per0.c   | 154 ++++++++++++++++++
 3 files changed, 167 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per0.c

diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index da11d486779a..1e1bfdf87c31 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -55,6 +55,18 @@ config PINCTRL_STARFIVE_JHB100
 	select GPIOLIB_IRQCHIP
 	select OF_GPIO
 
+config PINCTRL_STARFIVE_JHB100_PER0
+	tristate "StarFive JHB100 SoC Peripheral-0 pinctrl and GPIO driver"
+	depends on ARCH_STARFIVE || COMPILE_TEST
+	depends on OF
+	select PINCTRL_STARFIVE_JHB100
+	default ARCH_STARFIVE
+	help
+	  Say yes here to support Peripheral-0 pin control on the StarFive JHB100 SoC.
+	  This also provides an interface to the GPIO pins not used by other
+	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
+	  and interrupts on input changes.
+
 config PINCTRL_STARFIVE_JHB100_SYS0
 	tristate "StarFive JHB100 SoC System-0 pinctrl and GPIO driver"
 	depends on ARCH_STARFIVE || COMPILE_TEST
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index b817ad93b91d..f2bb0c35a2a0 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -7,6 +7,7 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_SYS)	+= pinctrl-starfive-jh7110-sys.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON)	+= pinctrl-starfive-jh7110-aon.o
 
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)		+= pinctrl-starfive-jhb100.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER0)	+= pinctrl-starfive-jhb100-per0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0H)	+= pinctrl-starfive-jhb100-sys0h.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS1)	+= pinctrl-starfive-jhb100-sys1.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per0.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per0.c
new file mode 100644
index 000000000000..d3364dfd9cbe
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per0.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC Peripheral-0 domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_per0_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 60, .name = "gpio", .gpio_func_sel = 0 },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_per0_pinctrl_rl_desc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 60,
+		.input_enable			= { .shift = 0, .width = 1 },
+		.mode_select			= { .shift = 1, .width = 2 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.open_drain_pull_up_sel		= { .shift = 5, .width = 2 },
+		.schmitt_trigger_select		= { .shift = 7, .width = 1 },
+		.reserved			= { .shift = 8, .width = 7 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{ 0xff },
+};
+
+static const struct pinvref_desc pinvref_desc_per0[] = {
+	{
+		/* gpioe-i3c0 */
+		.pin_grp = {
+			PADNUM_PER0_GPIO_B8,
+			PADNUM_PER0_GPIO_B9,
+			PADNUM_PER0_GPIO_B10,
+			PADNUM_PER0_GPIO_B11,
+			PADNUM_PER0_GPIO_B32,
+			PADNUM_PER0_GPIO_B33
+		},
+		.num_pins = 6,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+	{
+		/* gpioe-i3c1 */
+		.pin_grp = {
+			PADNUM_PER0_GPIO_B12,
+			PADNUM_PER0_GPIO_B13,
+			PADNUM_PER0_GPIO_B14,
+			PADNUM_PER0_GPIO_B15,
+			PADNUM_PER0_GPIO_B34,
+			PADNUM_PER0_GPIO_B35
+		},
+		.num_pins = 6,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+	{
+		/* gpioe-i3c2 */
+		.pin_grp = {
+			PADNUM_PER0_GPIO_B16,
+			PADNUM_PER0_GPIO_B17,
+			PADNUM_PER0_GPIO_B18,
+			PADNUM_PER0_GPIO_B19,
+			PADNUM_PER0_GPIO_B20,
+			PADNUM_PER0_GPIO_B21,
+			PADNUM_PER0_GPIO_B22,
+			PADNUM_PER0_GPIO_B23
+		},
+		.num_pins = 8,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+	{
+		/* gpioe-i3c4 */
+		.pin_grp = {
+			PADNUM_PER0_GPIO_B36,
+			PADNUM_PER0_GPIO_B37,
+			PADNUM_PER0_GPIO_B38,
+			PADNUM_PER0_GPIO_B39,
+			PADNUM_PER0_GPIO_B40,
+			PADNUM_PER0_GPIO_B41,
+			PADNUM_PER0_GPIO_B42,
+			PADNUM_PER0_GPIO_B43
+		},
+		.num_pins = 8,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+};
+
+struct starfive_pinctrl_regs jhb100_per0_pinctrl_regs = {
+	.vref			= { .reg = 0x004, .pv_desc = pinvref_desc_per0,
+				    .num_pv = ARRAY_SIZE(pinvref_desc_per0) },
+	.func_sel		= { .reg = 0x11c, .width_per_pin = 2 },
+	.config			= 0x014,
+	.output			= 0x104,
+	.output_en		= 0x10c,
+	.gpio_status		= 0x114,
+	.irq_en			= 0x12c,
+	.irq_status		= 0x134,
+	.irq_clr		= 0x13c,
+	.irq_trigger		= 0x144,
+	.irq_level		= 0x14c,
+	.irq_both_edge		= 0x154,
+	.irq_edge		= 0x15c,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_per0[] = {
+	{ .func = "gmac_mdio",		.val = 2 },
+	{ .func = "gpio",		.val = 0 },
+	{ .func = "i2c",		.val = 1 },
+	{ .func = "i3c",		.val = 2,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER0_GPIO_B23) },
+	{ .func = "i3c",		.val = 1,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER0_GPIO_B59) },
+	{ .func = "smbalert",		.val = 1 },
+	{ .func = "wdt",		.val = 2 },
+};
+
+static const struct jhb100_pinctrl_domain_info jhb100_per0_pinctrl_info = {
+	.name			= "jhb100-per0",
+	.pl_desc		= jhb100_per0_pl_desc,
+	.crl_desc		= jhb100_per0_pinctrl_rl_desc,
+	.regs			= &jhb100_per0_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_per0,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_per0),
+};
+
+static const struct of_device_id jhb100_per0_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-per0-pinctrl",
+		.data = &jhb100_per0_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_per0_pinctrl_of_match);
+
+static struct platform_driver jhb100_per0_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-per0-pinctrl",
+		.of_match_table = jhb100_per0_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_per0_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC Peripheral-0 domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:39 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:39 -0700
Subject: [PATCH v3 13/21] dt-bindings: pinctrl: Add starfive,jhb100-per1-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-14-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC Peripheral-1(per1) pinctrl
controller.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../pinctrl/starfive,jhb100-per1-pinctrl.yaml | 178 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  38 ++++
 2 files changed, 216 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per1-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per1-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per1-pinctrl.yaml
new file mode 100644
index 000000000000..a21bcc0a0391
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per1-pinctrl.yaml
@@ -0,0 +1,178 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-per1-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 Peripheral-1 Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "per1" pinctrl domain.
+
+  The "per1" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO pad configuration.
+  - GPIO interrupt handling.
+
+  In the Peripheral-1 Pin Controller, there are 36 multi-function GPIO_PADs.
+  Each of them can be multiplexed to several peripherals through function
+  selection. Each iopad has a maximum of up to 3 functions - 0, 1, and 2.
+  Function 0 is the default function which is generally the GPIO function.
+  Function 1 and 2 are the alternate functions or peripheral signals that
+  can be routed to the iopad. The function selection can be carried out by
+  writing the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds, power source and drive type (open-drain or push-pull).
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-per1-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce nanoseconds,
+          drive-open-drain, drive-push-pull, power-source and drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ gpio, i2c, sfc, sgpio, spi ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            oneOf:
+              - type: boolean
+              - enum: [ 600, 900, 1200, 2000 ]
+                description: Pull up RSEL type resistance values (in ohms)
+            description:
+              For normal pull up type there is no need to specify a resistance
+              value, hence this can be specified as a boolean property.
+              For RSEL pull up type a resistance value (in ohms) can be added.
+
+          drive-open-drain: true
+
+          drive-push-pull: true
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          power-source:
+            enum: [ 0, 2 ]
+            description: |
+                0: power supply of 3.3V
+                2: power supply of 1.8V
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+
+required:
+  - compatible
+  - reg
+  - resets
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_per1: pinctrl at 11b42000 {
+            compatible = "starfive,jhb100-per1-pinctrl";
+            reg = <0x0 0x11b42000 0x0 0x800>;
+            resets = <&per1crg 0>;
+            interrupts = <61>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_per1 0 0 0 32>,
+                          <&pinctrl_per1 1 0 32 4>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
index 4fc54b9990d3..54a900a624a3 100644
--- a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -139,6 +139,44 @@
 #define PADNUM_PER0_GPIO_B58				58
 #define PADNUM_PER0_GPIO_B59				59
 
+/* per1 pad numbers */
+#define PADNUM_PER1_GPIO_C0				0
+#define PADNUM_PER1_GPIO_C1				1
+#define PADNUM_PER1_GPIO_C2				2
+#define PADNUM_PER1_GPIO_C3				3
+#define PADNUM_PER1_GPIO_C4				4
+#define PADNUM_PER1_GPIO_C5				5
+#define PADNUM_PER1_GPIO_C6				6
+#define PADNUM_PER1_GPIO_C7				7
+#define PADNUM_PER1_GPIO_C8				8
+#define PADNUM_PER1_GPIO_C9				9
+#define PADNUM_PER1_GPIO_C10				10
+#define PADNUM_PER1_GPIO_C11				11
+#define PADNUM_PER1_GPIO_C12				12
+#define PADNUM_PER1_GPIO_C13				13
+#define PADNUM_PER1_GPIO_C14				14
+#define PADNUM_PER1_GPIO_C15				15
+#define PADNUM_PER1_GPIO_C16				16
+#define PADNUM_PER1_GPIO_C17				17
+#define PADNUM_PER1_GPIO_C18				18
+#define PADNUM_PER1_GPIO_C19				19
+#define PADNUM_PER1_GPIO_C20				20
+#define PADNUM_PER1_GPIO_C21				21
+#define PADNUM_PER1_GPIO_C22				22
+#define PADNUM_PER1_GPIO_C23				23
+#define PADNUM_PER1_GPIO_C24				24
+#define PADNUM_PER1_GPIO_C25				25
+#define PADNUM_PER1_GPIO_C26				26
+#define PADNUM_PER1_GPIO_C27				27
+#define PADNUM_PER1_GPIO_C28				28
+#define PADNUM_PER1_GPIO_C29				29
+#define PADNUM_PER1_GPIO_C30				30
+#define PADNUM_PER1_GPIO_C31				31
+#define PADNUM_PER1_GPIO_C32				32
+#define PADNUM_PER1_GPIO_C33				33
+#define PADNUM_PER1_GPIO_C34				34
+#define PADNUM_PER1_GPIO_C35				35
+
 /* power-source value */
 #define JHB100_PINVREF_3_3V				0
 #define JHB100_PINVREF_2_5V				1
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:40 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:40 -0700
Subject: [PATCH v3 14/21] pinctrl: starfive: Add StarFive JHB100 per1 controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-15-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC Peripheral-1(per1) pinctrl
controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/starfive/Kconfig              |  12 ++
 drivers/pinctrl/starfive/Makefile             |   1 +
 .../starfive/pinctrl-starfive-jhb100-per1.c   | 165 ++++++++++++++++++
 3 files changed, 178 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per1.c

diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index 1e1bfdf87c31..c3889a152f6c 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -67,6 +67,18 @@ config PINCTRL_STARFIVE_JHB100_PER0
 	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
 	  and interrupts on input changes.
 
+config PINCTRL_STARFIVE_JHB100_PER1
+	tristate "StarFive JHB100 SoC Peripheral-1 pinctrl and GPIO driver"
+	depends on ARCH_STARFIVE || COMPILE_TEST
+	depends on OF
+	select PINCTRL_STARFIVE_JHB100
+	default ARCH_STARFIVE
+	help
+	  Say yes here to support Peripheral-1 pin control on the StarFive JHB100 SoC.
+	  This also provides an interface to the GPIO pins not used by other
+	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
+	  and interrupts on input changes.
+
 config PINCTRL_STARFIVE_JHB100_SYS0
 	tristate "StarFive JHB100 SoC System-0 pinctrl and GPIO driver"
 	depends on ARCH_STARFIVE || COMPILE_TEST
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index f2bb0c35a2a0..6beef7e313ef 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON)	+= pinctrl-starfive-jh7110-aon.o
 
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)		+= pinctrl-starfive-jhb100.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER0)	+= pinctrl-starfive-jhb100-per0.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER1)	+= pinctrl-starfive-jhb100-per1.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0H)	+= pinctrl-starfive-jhb100-sys0h.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS1)	+= pinctrl-starfive-jhb100-sys1.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per1.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per1.c
new file mode 100644
index 000000000000..26cc48313263
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per1.c
@@ -0,0 +1,165 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC Peripheral-1 domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_per1_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 36, .name = "gpio", .gpio_func_sel = 0 },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_per1_pinctr_rldesc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 32,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 8 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{
+		.pin_start			= 32,
+		.pin_cnt			= 4,
+		.input_enable			= { .shift = 0, .width = 1 },
+		.mode_select			= { .shift = 1, .width = 2 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.open_drain_pull_up_sel		= { .shift = 5, .width = 2 },
+		.schmitt_trigger_select		= { .shift = 7, .width = 1 },
+		.reserved			= { .shift = 8, .width = 7 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{ 0xff },
+};
+
+static const struct pinvref_desc pinvref_desc_per1[] = {
+	{
+		/* gpioe-spi */
+		.pin_grp = {
+			PADNUM_PER1_GPIO_C0,
+			PADNUM_PER1_GPIO_C1,
+			PADNUM_PER1_GPIO_C2,
+			PADNUM_PER1_GPIO_C3,
+			PADNUM_PER1_GPIO_C4
+		},
+		.num_pins = 5,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+	{
+		/* gpioe-qspi0 */
+		.pin_grp = {
+			PADNUM_PER1_GPIO_C5,
+			PADNUM_PER1_GPIO_C6,
+			PADNUM_PER1_GPIO_C7,
+			PADNUM_PER1_GPIO_C8,
+			PADNUM_PER1_GPIO_C9,
+			PADNUM_PER1_GPIO_C10,
+			PADNUM_PER1_GPIO_C11
+		},
+		.num_pins = 7,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+	{
+		/* gpioe-qspi1 */
+		.pin_grp = {
+			PADNUM_PER1_GPIO_C12,
+			PADNUM_PER1_GPIO_C13,
+			PADNUM_PER1_GPIO_C14,
+			PADNUM_PER1_GPIO_C15,
+			PADNUM_PER1_GPIO_C16,
+			PADNUM_PER1_GPIO_C17,
+			PADNUM_PER1_GPIO_C18,
+			PADNUM_PER1_GPIO_C19
+		},
+		.num_pins = 8,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+	{
+		/* gpioe-qspi2 */
+		.pin_grp = {
+			PADNUM_PER1_GPIO_C20,
+			PADNUM_PER1_GPIO_C21,
+			PADNUM_PER1_GPIO_C22,
+			PADNUM_PER1_GPIO_C23,
+			PADNUM_PER1_GPIO_C24,
+			PADNUM_PER1_GPIO_C25,
+			PADNUM_PER1_GPIO_C26,
+			PADNUM_PER1_GPIO_C27
+		},
+		.num_pins = 8,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_3_3V)
+	},
+};
+
+struct starfive_pinctrl_regs jhb100_per1_pinctrl_regs = {
+	.vref			= { .reg = 0x00, .pv_desc = pinvref_desc_per1,
+				    .num_pv = ARRAY_SIZE(pinvref_desc_per1) },
+	.func_sel		= { .reg = 0xbc, .width_per_pin = 2 },
+	.config			= 0x14,
+	.output			= 0xa4,
+	.output_en		= 0xac,
+	.gpio_status		= 0xb4,
+	.irq_en			= 0xc8,
+	.irq_status		= 0xd0,
+	.irq_clr		= 0xd8,
+	.irq_trigger		= 0xe0,
+	.irq_level		= 0xe8,
+	.irq_both_edge		= 0xf0,
+	.irq_edge		= 0xf8,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_per1[] = {
+	{ .func = "gpio",		.val = 0 },
+	{ .func = "i2c",		.val = 1 },
+	{ .func = "sfc",		.val = 1 },
+	{ .func = "sgpio",		.val = 1,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER1_GPIO_C31) },
+	{ .func = "sgpio",		.val = 2,
+	  .max_pin = JHB100_FUNC_MAPS_MAX_PIN(PADNUM_PER1_GPIO_C35) },
+	{ .func = "spi",		.val = 1 },
+};
+
+static const struct jhb100_pinctrl_domain_info jhb100_per1_pinctrl_info = {
+	.name			= "jhb100-per1",
+	.pl_desc		= jhb100_per1_pl_desc,
+	.crl_desc		= jhb100_per1_pinctr_rldesc,
+	.regs			= &jhb100_per1_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_per1,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_per1),
+};
+
+static const struct of_device_id jhb100_per1_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-per1-pinctrl",
+		.data = &jhb100_per1_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_per1_pinctrl_of_match);
+
+static struct platform_driver jhb100_per1_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-per1-pinctrl",
+		.of_match_table = jhb100_per1_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_per1_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC Peripheral-1 domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:47 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:47 -0700
Subject: [PATCH v3 21/21] riscv: dts: starfive: jhb100: Add pinctrl nodes
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-22-changhuang.liang@starfivetech.com>

Add pinctrl nodes for starfive JHB100 SoC. They contain
pinctrl_per0/pinctrl_per1/pinctrl_per2/pinctrl_per2pok/pinctrl_per3/
pinctrl_sys0/pinctrl_sys0h/pinctrl_sys1/pinctrl_sys2.

Simultaneously add the pinctrl reference for uart6.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 arch/riscv/boot/dts/starfive/jhb100-evb1.dts  |   3 +
 .../boot/dts/starfive/jhb100-pinctrl.dtsi     |  23 ++++
 arch/riscv/boot/dts/starfive/jhb100.dtsi      | 110 ++++++++++++++++++
 3 files changed, 136 insertions(+)
 create mode 100644 arch/riscv/boot/dts/starfive/jhb100-pinctrl.dtsi

diff --git a/arch/riscv/boot/dts/starfive/jhb100-evb1.dts b/arch/riscv/boot/dts/starfive/jhb100-evb1.dts
index 462b6fb7953b..8ad2b30a4e0b 100644
--- a/arch/riscv/boot/dts/starfive/jhb100-evb1.dts
+++ b/arch/riscv/boot/dts/starfive/jhb100-evb1.dts
@@ -4,6 +4,7 @@
  */
 
 #include "jhb100.dtsi"
+#include "jhb100-pinctrl.dtsi"
 
 / {
 	model = "StarFive JHB100 EVB-1";
@@ -29,4 +30,6 @@ memory at 40000000 {
 
 &uart6 {
 	status = "okay";
+	pinctrl-names = "default";
+	pinctrl-0 = <&uart6_pins>;
 };
diff --git a/arch/riscv/boot/dts/starfive/jhb100-pinctrl.dtsi b/arch/riscv/boot/dts/starfive/jhb100-pinctrl.dtsi
new file mode 100644
index 000000000000..acc357e98548
--- /dev/null
+++ b/arch/riscv/boot/dts/starfive/jhb100-pinctrl.dtsi
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0 OR MIT
+/*
+ * Copyright (c) 2025-2026 StarFive Technology Co., Ltd.
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+
+&pinctrl_sys2 {
+	uart6_pins: uart6-grp {
+		uart6-tx-pins {
+			pins = <PADNUM_SYS2_GPIO_A38>;
+			function = "uart";
+			power-source = <JHB100_PINVREF_3_3V>;
+		};
+
+		uart6-rx-pins {
+			pins = <PADNUM_SYS2_GPIO_A39>;
+			function = "uart";
+			input-enable;
+			power-source = <JHB100_PINVREF_3_3V>;
+		};
+	};
+};
diff --git a/arch/riscv/boot/dts/starfive/jhb100.dtsi b/arch/riscv/boot/dts/starfive/jhb100.dtsi
index 943324b3b2fd..f9a7fa9d37e3 100644
--- a/arch/riscv/boot/dts/starfive/jhb100.dtsi
+++ b/arch/riscv/boot/dts/starfive/jhb100.dtsi
@@ -428,6 +428,19 @@ per0crg: clock-controller at 11a08000 {
 				#reset-cells = <1>;
 			};
 
+			pinctrl_per0: pinctrl at 11a0a000 {
+				compatible = "starfive,jhb100-per0-pinctrl";
+				reg = <0x0 0x11a0a000 0x0 0x1000>;
+				resets = <&per0crg JHB100_PER0RST_GPIO_IOMUX_PRESETN>;
+				interrupts = <60>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_per0 0 0 0 32>,
+					      <&pinctrl_per0 1 0 32 28>;
+			};
+
 			per1crg: clock-controller at 11b40000 {
 				compatible = "starfive,jhb100-per1crg";
 				reg = <0x0 0x11b40000 0x0 0x1000>;
@@ -443,6 +456,19 @@ per1crg: clock-controller at 11b40000 {
 				#reset-cells = <1>;
 			};
 
+			pinctrl_per1: pinctrl at 11b42000 {
+				compatible = "starfive,jhb100-per1-pinctrl";
+				reg = <0x0 0x11b42000 0x0 0x800>;
+				resets = <&per1crg JHB100_PER1RST_IOMUX_PRESETN>;
+				interrupts = <61>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_per1 0 0 0 32>,
+					      <&pinctrl_per1 1 0 32 4>;
+			};
+
 			per2crg: clock-controller at 11bc0000 {
 				compatible = "starfive,jhb100-per2crg";
 				reg = <0x0 0x11bc0000 0x0 0x1000>;
@@ -464,6 +490,30 @@ per2crg: clock-controller at 11bc0000 {
 				#reset-cells = <1>;
 			};
 
+			pinctrl_per2: pinctrl at 11bc2000 {
+				compatible = "starfive,jhb100-per2-pinctrl";
+				reg = <0x0 0x11bc2000 0x0 0x400>;
+				resets = <&per2crg JHB100_PER2RST_IOMUX_PRESETN>;
+				interrupts = <62>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_per2 0 0 0 31>;
+			};
+
+			pinctrl_per2pok: pinctrl at 11bc2400 {
+				compatible = "starfive,jhb100-per2pok-pinctrl";
+				reg = <0x0 0x11bc2400 0x0 0x400>;
+				resets = <&per2crg JHB100_PER2RST_POK_IOMUX_PRESETN>;
+				interrupts = <63>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_per2pok 0 0 0 18>;
+			};
+
 			per3crg: clock-controller at 11c40000 {
 				compatible = "starfive,jhb100-per3crg";
 				reg = <0x0 0x11c40000 0x0 0x1000>;
@@ -483,6 +533,18 @@ per3crg: clock-controller at 11c40000 {
 				#reset-cells = <1>;
 			};
 
+			pinctrl_per3: pinctrl at 11c42000 {
+				compatible = "starfive,jhb100-per3-pinctrl";
+				reg = <0x0 0x11c42000 0x0 0x1000>;
+				resets = <&per3crg JHB100_PER3RST_IOMUX_PRESETN>;
+				interrupts = <64>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_per3 0 0 0 11>;
+			};
+
 			sys0crg: clock-controller at 13000000 {
 				compatible = "starfive,jhb100-sys0crg";
 				reg = <0x0 0x13000000 0x0 0x4000>;
@@ -517,6 +579,54 @@ sys2crg: clock-controller at 13008000 {
 				#reset-cells = <1>;
 			};
 
+			pinctrl_sys0: pinctrl at 13080000 {
+				compatible = "starfive,jhb100-sys0-pinctrl";
+				reg = <0x0 0x13080000 0x0 0x800>;
+				resets = <&sys0crg JHB100_SYS0RST_SYS0_IOMUX_PRESETN>;
+				interrupts = <56>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_sys0 0 0 0 4>;
+			};
+
+			pinctrl_sys0h: pinctrl at 13080800 {
+				compatible = "starfive,jhb100-sys0h-pinctrl";
+				reg = <0x0 0x13080800 0x0 0x800>;
+				resets = <&sys0crg JHB100_SYS0RST_SYS0H_IOMUX_PRESETN>;
+				interrupts = <57>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_sys0h 0 0 0 12>;
+			};
+
+			pinctrl_sys1: pinctrl at 13081000 {
+				compatible = "starfive,jhb100-sys1-pinctrl";
+				reg = <0x0 0x13081000 0x0 0x1000>;
+				resets = <&sys1crg JHB100_SYS1RST_SYS1_IOMUX_PRESETN>;
+				interrupts = <58>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_sys1 0 0 0 8>;
+			};
+
+			pinctrl_sys2: pinctrl at 13082000 {
+				compatible = "starfive,jhb100-sys2-pinctrl";
+				reg = <0x0 0x13082000 0x0 0x1000>;
+				interrupts = <59>;
+				interrupt-controller;
+				#interrupt-cells = <3>;
+				gpio-controller;
+				#gpio-cells = <3>;
+				gpio-ranges = <&pinctrl_sys2 0 0 0 32>,
+					      <&pinctrl_sys2 1 0 32 5>;
+			};
+
 			intc: interrupt-controller at 13220000 {
 				compatible = "starfive,jhb100-intc";
 				reg = <0x0 0x13220000 0x0 0x80>;
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:41 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:41 -0700
Subject: [PATCH v3 15/21] dt-bindings: pinctrl: Add starfive,jhb100-per2-pinctrl
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-16-changhuang.liang@starfivetech.com>

Add pinctrl bindings for StarFive JHB100 SoC Peripheral-2(per2) pinctrl
controller.

Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 .../pinctrl/starfive,jhb100-per2-pinctrl.yaml | 168 ++++++++++++++++++
 .../pinctrl/starfive,jhb100-pinctrl.h         |  33 ++++
 2 files changed, 201 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2-pinctrl.yaml

diff --git a/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2-pinctrl.yaml b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2-pinctrl.yaml
new file mode 100644
index 000000000000..c6d88b6a60e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/starfive,jhb100-per2-pinctrl.yaml
@@ -0,0 +1,168 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/pinctrl/starfive,jhb100-per2-pinctrl.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: StarFive JHB100 Peripheral-2 Pin Controller
+
+description: |
+  Pinctrl bindings for JHB100 RISC-V SoC from StarFive Technology Ltd.
+
+  The JHB100 SoC has 13 pinctrl domains - sys0, sys0h, sys1, sys2, per0, per1,
+  per2, per2pok, per3, adc0, adc1, emmc, and vga.
+  This document provides an overview of the "per2" pinctrl domain.
+
+  The "per2" domain has a pin controller which provides
+  - function selection for GPIO pads.
+  - GPIO pad configuration.
+  - GPIO interrupt handling.
+
+  In the Peripheral-2 Pin Controller, there are 31 multi-function GPIO_PADs.
+  Each of them can be multiplexed to several peripherals through function
+  selection. Each iopad has a maximum of up to 4 functions - 0, 1, 2, and 3.
+  Function 0 is the default function which is generally the GPIO function.
+  Function 1, 2, and 3 are the alternate functions or peripheral signals
+  that can be routed to an iopad. The function selection can be carried
+  out by writing the function number to the iopad function select register.
+
+  Each iopad is configurable with parameters such as input-enable, internal
+  pull-up/pull-down bias, drive strength, schmitt trigger, slew rate, input
+  debounce nanoseconds, power source.
+
+maintainers:
+  - Changhuang Liang <changhuang.liang at starfivetech.com>
+
+properties:
+  compatible:
+    items:
+      - const: starfive,jhb100-per2-pinctrl
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  resets:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  interrupt-controller: true
+
+  '#interrupt-cells':
+    const: 3
+
+  gpio-controller: true
+
+  '#gpio-cells':
+    const: 3
+
+  gpio-ranges: true
+
+  gpio-line-names: true
+
+patternProperties:
+  '-grp$':
+    type: object
+    additionalProperties: false
+    patternProperties:
+      '-pins$':
+        type: object
+        description: |
+          A pinctrl node should contain at least one subnode representing the
+          pinctrl groups available in the domain. Each subnode will list the
+          pins it needs, and how they should be configured, with regard to
+          function selection, bias, input enable/disable, input schmitt
+          trigger enable/disable, slew-rate, input debounce nanoseconds,
+          power-source and drive-strength.
+        allOf:
+          - $ref: /schemas/pinctrl/pincfg-node.yaml
+          - $ref: /schemas/pinctrl/pinmux-node.yaml
+        additionalProperties: false
+
+        properties:
+          pins:
+            description:
+              The list of IOs that properties in the pincfg node apply to.
+
+          function:
+            description:
+              A string containing the name of the function to mux for these
+              pins.
+            enum: [ fan_tach, gmac_rgmii, gmac_rmii, gpio, host0_port80,
+                    host1_port80 ]
+
+          bias-disable: true
+
+          bias-pull-down:
+            type: boolean
+
+          bias-pull-up:
+            type: boolean
+
+          drive-strength:
+            enum: [ 2, 4, 8, 12 ]
+
+          drive-strength-microamp:
+            enum: [ 2000, 4000, 8000, 12000 ]
+
+          input-debounce-ns:
+            minimum: 0
+            maximum: 4294967295
+
+          input-disable: true
+
+          input-enable: true
+
+          input-schmitt-enable: true
+
+          input-schmitt-disable: true
+
+          power-source:
+            enum: [ 0, 1, 2 ]
+            description: |
+                0: power supply of 3.3V
+                1: power supply of 2.5V
+                2: power supply of 1.8V
+
+          slew-rate:
+            enum: [ 0, 1 ]
+            default: 0
+            description: |
+                0: slow (half frequency)
+                1: fast
+
+required:
+  - compatible
+  - reg
+  - resets
+  - interrupts
+  - interrupt-controller
+  - '#interrupt-cells'
+  - gpio-controller
+  - '#gpio-cells'
+  - gpio-ranges
+
+additionalProperties: false
+
+examples:
+  - |
+    soc {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        pinctrl_per2: pinctrl at 11bc2000 {
+            compatible = "starfive,jhb100-per2-pinctrl";
+            reg = <0x0 0x11bc2000 0x0 0x400>;
+            resets = <&per2crg 0>;
+            interrupts = <62>;
+            interrupt-controller;
+            #interrupt-cells = <3>;
+            gpio-controller;
+            #gpio-cells = <3>;
+            gpio-ranges = <&pinctrl_per2 0 0 0 31>;
+        };
+    };
diff --git a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
index 54a900a624a3..7aeebcf72b8f 100644
--- a/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
+++ b/include/dt-bindings/pinctrl/starfive,jhb100-pinctrl.h
@@ -177,6 +177,39 @@
 #define PADNUM_PER1_GPIO_C34				34
 #define PADNUM_PER1_GPIO_C35				35
 
+/* per2 pad numbers */
+#define PADNUM_PER2_GPIO_D0				0
+#define PADNUM_PER2_GPIO_D1				1
+#define PADNUM_PER2_GPIO_D2				2
+#define PADNUM_PER2_GPIO_D3				3
+#define PADNUM_PER2_GPIO_D4				4
+#define PADNUM_PER2_GPIO_D5				5
+#define PADNUM_PER2_GPIO_D6				6
+#define PADNUM_PER2_GPIO_D7				7
+#define PADNUM_PER2_GPIO_D8				8
+#define PADNUM_PER2_GPIO_D9				9
+#define PADNUM_PER2_GPIO_D10				10
+#define PADNUM_PER2_GPIO_D11				11
+#define PADNUM_PER2_GPIO_D12				12
+#define PADNUM_PER2_GPIO_D13				13
+#define PADNUM_PER2_GPIO_D14				14
+#define PADNUM_PER2_GPIO_D15				15
+#define PADNUM_PER2_GPIO_D16				16
+#define PADNUM_PER2_GPIO_D17				17
+#define PADNUM_PER2_GPIO_D18				18
+#define PADNUM_PER2_GPIO_D19				19
+#define PADNUM_PER2_GPIO_D20				20
+#define PADNUM_PER2_GPIO_D21				21
+#define PADNUM_PER2_GPIO_D22				22
+#define PADNUM_PER2_GPIO_D23				23
+#define PADNUM_PER2_GPIO_D24				24
+#define PADNUM_PER2_GPIO_D25				25
+#define PADNUM_PER2_GPIO_D26				26
+#define PADNUM_PER2_GPIO_D27				27
+#define PADNUM_PER2_GPIO_D28				28
+#define PADNUM_PER2_GPIO_D29				29
+#define PADNUM_PER2_GPIO_D30				30
+
 /* power-source value */
 #define JHB100_PINVREF_3_3V				0
 #define JHB100_PINVREF_2_5V				1
-- 
2.25.1



From changhuang.liang at starfivetech.com  Tue Jun  2 22:53:42 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue,  2 Jun 2026 22:53:42 -0700
Subject: [PATCH v3 16/21] pinctrl: starfive: Add StarFive JHB100 per2 controller driver
In-Reply-To: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
Message-ID: <20260603055347.66845-17-changhuang.liang@starfivetech.com>

Add pinctrl driver for StarFive JHB100 SoC Peripheral-2(per2) pinctrl
controller.

Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
---
 drivers/pinctrl/starfive/Kconfig              |  12 ++
 drivers/pinctrl/starfive/Makefile             |   1 +
 .../starfive/pinctrl-starfive-jhb100-per2.c   | 126 ++++++++++++++++++
 3 files changed, 139 insertions(+)
 create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2.c

diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
index c3889a152f6c..edc3b6d9c8d7 100644
--- a/drivers/pinctrl/starfive/Kconfig
+++ b/drivers/pinctrl/starfive/Kconfig
@@ -79,6 +79,18 @@ config PINCTRL_STARFIVE_JHB100_PER1
 	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
 	  and interrupts on input changes.
 
+config PINCTRL_STARFIVE_JHB100_PER2
+	tristate "StarFive JHB100 SoC Peripheral-2 pinctrl and GPIO driver"
+	depends on ARCH_STARFIVE || COMPILE_TEST
+	depends on OF
+	select PINCTRL_STARFIVE_JHB100
+	default ARCH_STARFIVE
+	help
+	  Say yes here to support Peripheral-2 pin control on the StarFive JHB100 SoC.
+	  This also provides an interface to the GPIO pins not used by other
+	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
+	  and interrupts on input changes.
+
 config PINCTRL_STARFIVE_JHB100_SYS0
 	tristate "StarFive JHB100 SoC System-0 pinctrl and GPIO driver"
 	depends on ARCH_STARFIVE || COMPILE_TEST
diff --git a/drivers/pinctrl/starfive/Makefile b/drivers/pinctrl/starfive/Makefile
index 6beef7e313ef..33213bd1919f 100644
--- a/drivers/pinctrl/starfive/Makefile
+++ b/drivers/pinctrl/starfive/Makefile
@@ -9,6 +9,7 @@ obj-$(CONFIG_PINCTRL_STARFIVE_JH7110_AON)	+= pinctrl-starfive-jh7110-aon.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100)		+= pinctrl-starfive-jhb100.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER0)	+= pinctrl-starfive-jhb100-per0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER1)	+= pinctrl-starfive-jhb100-per1.o
+obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_PER2)	+= pinctrl-starfive-jhb100-per2.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0)	+= pinctrl-starfive-jhb100-sys0.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS0H)	+= pinctrl-starfive-jhb100-sys0h.o
 obj-$(CONFIG_PINCTRL_STARFIVE_JHB100_SYS1)	+= pinctrl-starfive-jhb100-sys1.o
diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2.c
new file mode 100644
index 000000000000..030c68beed6b
--- /dev/null
+++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2.c
@@ -0,0 +1,126 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Pinctrl / GPIO driver for StarFive JHB100 SoC Peripheral-2 domain
+ *
+ * Copyright (C) 2024 StarFive Technology Co., Ltd.
+ * Author: Alex Soo <yuklin.soo at starfivetech.com>
+ *
+ */
+
+#include <dt-bindings/pinctrl/starfive,jhb100-pinctrl.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#include "pinctrl-starfive-jhb100.h"
+
+static const struct jhb100_pin_layout_desc jhb100_per2_pl_desc[] = {
+	{ .pin_start = 0, .pin_cnt = 15, .name = "gpio", .gpio_func_sel = 0 },
+	{ .pin_start = 15, .pin_cnt = 1, .name = "gpio", .gpio_func_sel = -1 },
+	{ .pin_start = 16, .pin_cnt = 15, .name = "gpio", .gpio_func_sel = 0 },
+	{ 0xff },
+};
+
+static struct config_reg_layout_desc jhb100_per2_pinctrl_rl_desc[] = {
+	{
+		.pin_start			= 0,
+		.pin_cnt			= 19,
+		.drive_strength_2bit		= { .shift = 0, .width = 2 },
+		.input_enable			= { .shift = 2, .width = 1 },
+		.pull_down			= { .shift = 3, .width = 1 },
+		.pull_up			= { .shift = 4, .width = 1 },
+		.slew_rate			= { .shift = 5, .width = 1 },
+		.schmitt_trigger_select		= { .shift = 6, .width = 1 },
+		.reserved			= { .shift = 7, .width = 8 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{
+		.pin_start			= 19,
+		.pin_cnt			= 12,
+		.input_enable			= { .shift = 0, .width = 1 },
+		.slew_rate			= { .shift = 1, .width = 1 },
+		.vsel				= { .shift = 2, .width = 2 },
+		.reserved			= { .shift = 4, .width = 11 },
+		.debounce_width			= { .shift = 15, .width = 17 },
+	},
+	{ 0xff },
+};
+
+static const struct pinvref_desc pinvref_desc_per2[] = {
+	{
+		/* gpionw */
+		.pin_grp = {
+			PADNUM_PER2_GPIO_D19,
+			PADNUM_PER2_GPIO_D20,
+			PADNUM_PER2_GPIO_D21,
+			PADNUM_PER2_GPIO_D22,
+			PADNUM_PER2_GPIO_D23,
+			PADNUM_PER2_GPIO_D24,
+			PADNUM_PER2_GPIO_D25,
+			PADNUM_PER2_GPIO_D26,
+			PADNUM_PER2_GPIO_D27,
+			PADNUM_PER2_GPIO_D28,
+			PADNUM_PER2_GPIO_D29,
+			PADNUM_PER2_GPIO_D30
+		},
+		.num_pins = 12,
+		.range = BIT(JHB100_PINVREF_1_8V) | BIT(JHB100_PINVREF_2_5V) |
+			 BIT(JHB100_PINVREF_3_3V)
+	},
+};
+
+struct starfive_pinctrl_regs jhb100_per2_pinctrl_regs = {
+	.vref			= { .reg = 0x00, .pv_desc = pinvref_desc_per2,
+				    .num_pv = ARRAY_SIZE(pinvref_desc_per2) },
+	.func_sel		= { .reg = 0x8c, .width_per_pin = 2 },
+	.config			= 0x04,
+	.output			= 0x80,
+	.output_en		= 0x84,
+	.gpio_status		= 0x88,
+	.irq_en			= 0x94,
+	.irq_status		= 0x98,
+	.irq_clr		= 0x9c,
+	.irq_trigger		= 0xa0,
+	.irq_level		= 0xa4,
+	.irq_both_edge		= 0xa8,
+	.irq_edge		= 0xac,
+};
+
+static const struct jhb100_pinctrl_func_maps jhb100_func_maps_per2[] = {
+	{ .func = "fan_tach",		.val = 1 },
+	{ .func = "gmac_rgmii",		.val = 1 },
+	{ .func = "gmac_rmii",		.val = 2 },
+	{ .func = "gpio",		.val = 0 },
+	{ .func = "host0_port80",	.val = 2 },
+	{ .func = "host1_port80",	.val = 3 },
+};
+
+static const struct jhb100_pinctrl_domain_info jhb100_per2_pinctrl_info = {
+	.name			= "jhb100-per2",
+	.pl_desc		= jhb100_per2_pl_desc,
+	.crl_desc		= jhb100_per2_pinctrl_rl_desc,
+	.regs			= &jhb100_per2_pinctrl_regs,
+	.fmaps			= jhb100_func_maps_per2,
+	.num_maps		= ARRAY_SIZE(jhb100_func_maps_per2),
+};
+
+static const struct of_device_id jhb100_per2_pinctrl_of_match[] = {
+	{
+		.compatible = "starfive,jhb100-per2-pinctrl",
+		.data = &jhb100_per2_pinctrl_info,
+	},
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jhb100_per2_pinctrl_of_match);
+
+static struct platform_driver jhb100_per2_pinctrl_driver = {
+	.probe = jhb100_pinctrl_probe,
+	.driver = {
+		.name = "starfive-jhb100-per2-pinctrl",
+		.of_match_table = jhb100_per2_pinctrl_of_match,
+	},
+};
+module_platform_driver(jhb100_per2_pinctrl_driver);
+
+MODULE_DESCRIPTION("Pinctrl driver for StarFive JHB100 SoC Peripheral-2 domain");
+MODULE_AUTHOR("Alex Soo <yuklin.soo at starfivetech.com>");
+MODULE_LICENSE("GPL");
-- 
2.25.1



From unicorn_wang at outlook.com  Tue Jun  2 23:17:42 2026
From: unicorn_wang at outlook.com (Chen Wang)
Date: Wed, 3 Jun 2026 14:17:42 +0800
Subject: [GIT PULL] RISC-V Sophgo Devicetrees for v7.2
Message-ID: <MA5PR01MB1250024541E71412DDA04B4AAFE132@MA5PR01MB12500.INDPRD01.PROD.OUTLOOK.COM>

Hey Arnd,

Please pull this dt changes for RISC-V/Sophgo.

BTW: Next PR, I will start using my new work email address: 
chen.wang at linux.dev.

Thanks,

Chen

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

 ? Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

 ? https://github.com/sophgo/linux.git tags/riscv-sophgo-dt-for-v7.2

for you to fetch changes up to 903a9364e40563faf4730dc63ad7446246f494ff:

 ? riscv: dts: sophgo: reduce SG2042 MSI count to 16 (2026-06-03 
10:09:38 +0800)

----------------------------------------------------------------
RISC-V Devicetrees for v7.2

Sophgo:

For CV18xx serials:
- Add bindings for Milk-V "Duo S" board.

For SG2042:
- The CPU unit address incorrectly used decimal numbers,
 ? especially for those nodes which value >= 10. Now
 ? corrected to use hexadecimal.
- The MSI controller actually only supports 16 interrupts;
 ? corrected to match the actual situation.
- PCIe RCs are cache-coherent with the CPU. Marked it out
 ? for RC nodes.

For SG2044:
- The same as SG2042, use hex for CPU unit address.

In additional, update Chen Wang's email address for Sopgho
SoC maintainer.

Signed-off-by: Chen Wang <unicorn_wang at outlook.com>

----------------------------------------------------------------
Chen Wang (1):
 ? ? ? MAINTAINERS: update Chen Wang's email address

Han Gao (1):
 ? ? ? riscv: dts: sophgo: Add dma-coherent to SG2042 PCIe controllers

Icenowy Zheng (1):
 ? ? ? riscv: dts: sophgo: reduce SG2042 MSI count to 16

Inochi Amaoto (2):
 ? ? ? riscv: dts: sophgo: sg2044: use hex for CPU unit address
 ? ? ? riscv: dts: sophgo: sg2042: use hex for CPU unit address

Joshua Milas (2):
 ? ? ? dt-bindings: soc: sophgo: add Milk-V Duo S board compatibles
 ? ? ? dt-bindings: soc: sophgo: add sg2000 plic and clint documentation

 ?.../interrupt-controller/sifive,plic-1.0.0.yaml? ? |? ?1 +
 ?.../devicetree/bindings/soc/sophgo/sophgo.yaml? ? ?|? ?4 +
 ?.../devicetree/bindings/timer/sifive,clint.yaml? ? |? ?1 +
 ?MAINTAINERS? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? |? ?2 +-
 ?arch/riscv/boot/dts/sophgo/sg2042-cpus.dtsi? ? ? ? | 236 
++++++++++-----------
 ?arch/riscv/boot/dts/sophgo/sg2042.dtsi? ? ? ? ? ? ?|? ?6 +-
 ?arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi? ? ? ? | 236 
++++++++++-----------
 ?7 files changed, 248 insertions(+), 238 deletions(-)



From chenwandun1 at gmail.com  Tue Jun  2 23:44:13 2026
From: chenwandun1 at gmail.com (Wandun)
Date: Wed, 3 Jun 2026 14:44:13 +0800
Subject: [PATCH v3 03/11] of: reserved_mem: avoid post-init UAF when
 alloc_reserved_mem_array() fails
In-Reply-To: <20260602162450.GA442759-robh@kernel.org>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <20260527032917.3385849-4-chenwandun1@gmail.com>
 <20260602162450.GA442759-robh@kernel.org>
Message-ID: <79932afc-2e91-4a54-aff9-f550be784c36@gmail.com>



On 6/3/26 00:24, Rob Herring wrote:
> On Wed, May 27, 2026 at 11:29:09AM +0800, Wandun Chen wrote:
>> From: Wandun Chen <chenwandun at lixiang.com>
>>
>> The global pointer 'reserved_mem' continues to reference the
>> reserved_mem_array which lives in __initdata if
>> alloc_reserved_mem_array() fails. of_reserved_mem_lookup() is
>> exported for post-init use, that would dereference freed memory
>> and trigger a use-after-free.
>>
>> So reset reserved_mem_count to 0 when alloc_reserved_mem_array()
>> fails.
>>
>> Fixes: 00c9a452a235 ("of: reserved_mem: Add code to dynamically allocate reserved_mem array")
> Fixes should come first in a series.
Understood, will do in future submissions.
>
>> Signed-off-by: Wandun Chen <chenwandun at lixiang.com>
>> ---
>>   drivers/of/of_reserved_mem.c | 20 ++++++++++++++------
>>   1 file changed, 14 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
>> index 313cbc57aa45..6d479381ff1f 100644
>> --- a/drivers/of/of_reserved_mem.c
>> +++ b/drivers/of/of_reserved_mem.c
>> @@ -69,29 +69,31 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
>>    * the initial static array is copied over to this new array and
>>    * the new array is used from this point on.
>>    */
>> -static void __init alloc_reserved_mem_array(void)
>> +static bool __init alloc_reserved_mem_array(void)
>>   {
>>   	struct reserved_mem *new_array;
>>   	size_t alloc_size, copy_size, memset_size;
>>   
>> +	if (!total_reserved_mem_cnt)
>> +		return true;
>> +
>>   	alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array));
>>   	if (alloc_size == SIZE_MAX) {
>>   		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
>> -		return;
>> +		goto fail;
>>   	}
>>   
>>   	new_array = memblock_alloc(alloc_size, SMP_CACHE_BYTES);
>>   	if (!new_array) {
>>   		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -ENOMEM);
>> -		return;
>> +		goto fail;
>>   	}
>>   
>>   	copy_size = array_size(reserved_mem_count, sizeof(*new_array));
>>   	if (copy_size == SIZE_MAX) {
>>   		memblock_free(new_array, alloc_size);
>> -		total_reserved_mem_cnt = MAX_RESERVED_REGIONS;
>>   		pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
> These prints could be moved to 'fail'. Perhaps instead of just printing
> an error value, you can return the error value instead of boolean.
Will do, consolidating pr_err() under 'fail' and changing the return type
to int.
>
> If you respin just this patch, I can pick it up for 7.2.
Before I respin, I'd like to flag a dependency:
patch 05/07 in this series build on the signature change introduced by this
patch ("the void -> bool return type change of alloc_reserved_mem_array()")

Could you let me know which of the following you'd prefer:
a) Take patch 03 alone via your tree as you suggested, after it lands, I'll
 ? ?respin the remaining patches of this series.

b) Keep patch 03 in the v4 respin of the full series, reordered to the front
 ? ?per your earlier comment.

Best regards,
Wandun
>
> Rob



From anup at brainfault.org  Tue Jun  2 23:44:36 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 12:14:36 +0530
Subject: [PATCH] driver core: platform: Setup device MSI domain just
 before driver probe
In-Reply-To: <89e1334f-e7c2-4992-ba39-0d23f5605275@arm.com>
References: <20260526145240.1627200-1-anup.patel@oss.qualcomm.com> <89e1334f-e7c2-4992-ba39-0d23f5605275@arm.com>
Message-ID: <CAAhSdy0dOeCrH2YEkEyrNQU2nyO-41AT3m4-BaYJuQ3GbocqmQ@mail.gmail.com>

On Tue, May 26, 2026 at 8:53?PM Robin Murphy <robin.murphy at arm.com> wrote:
>
> On 26/05/2026 3:52 pm, Anup Patel wrote:
> > On RISC-V, the MSI controller (aka RISC-V IMSIC) is probed as a regular
> > platform device and MSI client drivers are always probed after the MSI
> > controller driver using fw_devlink. Unfortunately, this is not sufficient
> > to ensure device MSI domain is set for MSI client devices before driver
> > probe because OF framework sets device MSI domain at the time of platform
> > device creation whereas ACPI framework expects arch specific code to set
> > the device MSI domain at the time of platform device creation.
> >
> > Currently, to work-around the problem of missing device MSI domain,
> > various RISC-V MSI client drivers explicitly set device MSI domain
> > in the driver probe function using below code pattern:
> >
> >       /*
> >        * The device MSI domain for platform devices on RISC-V architecture
> >        * is only available after the MSI controller driver is probed so,
> >        * explicitly configure here.
> >        */
> >       if (!dev_get_msi_domain(dev)) {
> >               /*
> >                * The device MSI domain for OF devices is only set at the
> >                * time of populating/creating OF device. If the device MSI
> >                * domain is discovered later after the OF device is created
> >                * then we need to set it explicitly before using any platform
> >                * MSI functions.
> >                */
> >               if (is_of_node(fwnode)) {
> >                       of_msi_configure(dev, dev_of_node(dev));
> >               } else if (is_acpi_device_node(fwnode)) {
> >                       struct irq_domain *msi_domain;
> >                       msi_domain = irq_find_matching_fwnode(imsic_acpi_get_fwnode(dev),
> >                                                             DOMAIN_BUS_PLATFORM_MSI);
> >                       dev_set_msi_domain(dev, msi_domain);
> >               }
> >
> >               if (!dev_get_msi_domain(dev))
> >                       return -EPROBE_DEFER;
> >       }
> >
> > Instead of the above approach, extend the platform_dma_configure() to set
> > device MSI domain for both OF and ACPI based platform devices before driver
> > probe and remove the duplicate code pattern from RISC-V MSI client drivers.
> >
> > Co-developed-by: Sunil V L <sunilvl at oss.qualcomm.com>
> > Signed-off-by: Sunil V L <sunilvl at oss.qualcomm.com>
> > Signed-off-by: Anup Patel <anup.patel at oss.qualcomm.com>
> > ---
> >   drivers/acpi/riscv/irq.c                | 13 +++++++++++
> >   drivers/acpi/scan.c                     | 10 +++++++++
> >   drivers/base/platform.c                 |  4 ++++
> >   drivers/iommu/riscv/iommu-platform.c    |  9 --------
> >   drivers/irqchip/irq-riscv-aplic-msi.c   | 27 -----------------------
> >   drivers/irqchip/irq-riscv-rpmi-sysmsi.c | 29 -------------------------
> >   drivers/mailbox/riscv-sbi-mpxy-mbox.c   | 29 -------------------------
> >   include/acpi/acpi_bus.h                 |  1 +
> >   include/linux/acpi.h                    | 10 +++++++++
> >   9 files changed, 38 insertions(+), 94 deletions(-)
> >
> > diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
> > index 9b88d0993e88..17fa5dcdd2c0 100644
> > --- a/drivers/acpi/riscv/irq.c
> > +++ b/drivers/acpi/riscv/irq.c
> > @@ -5,8 +5,11 @@
> >    */
> >
> >   #include <linux/acpi.h>
> > +#include <linux/device.h>
> >   #include <linux/sort.h>
> >   #include <linux/irq.h>
> > +#include <linux/irqdomain.h>
> > +#include <linux/irqchip/riscv-imsic.h>
> >
> >   #include "init.h"
> >
> > @@ -397,6 +400,16 @@ static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
> >       return count;
> >   }
> >
> > +void acpi_arch_msi_configure(struct device *dev)
> > +{
> > +     struct irq_domain *msi_domain;
> > +
> > +     msi_domain = irq_find_matching_fwnode(imsic_acpi_get_fwnode(dev),
> > +                                           DOMAIN_BUS_PLATFORM_MSI);
> > +     if (msi_domain)
> > +             dev_set_msi_domain(dev, msi_domain);
> > +}
> > +
> >   u32 arch_acpi_add_auto_dep(acpi_handle handle)
> >   {
> >       if (acpi_has_method(handle, "_PRT"))
> > diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> > index 530547cda8b2..e50e5d246a54 100644
> > --- a/drivers/acpi/scan.c
> > +++ b/drivers/acpi/scan.c
> > @@ -1648,6 +1648,16 @@ static int acpi_iommu_configure_id(struct device *dev, const u32 *id_in)
> >
> >   #endif /* !CONFIG_IOMMU_API */
> >
> > +/**
> > + * acpi_msi_configure - Set-up MSI domain for the device.
> > + * @dev: The pointer to the device
> > + */
> > +void acpi_msi_configure(struct device *dev)
> > +{
> > +     acpi_arch_msi_configure(dev);
> > +}
> > +EXPORT_SYMBOL_GPL(acpi_msi_configure);
> > +
> >   /**
> >    * acpi_dma_configure_id - Set-up DMA configuration for the device.
> >    * @dev: The pointer to the device
> > diff --git a/drivers/base/platform.c b/drivers/base/platform.c
> > index a19dd22deef2..225e33080bc6 100644
> > --- a/drivers/base/platform.c
> > +++ b/drivers/base/platform.c
> > @@ -1470,8 +1470,12 @@ static int platform_dma_configure(struct device *dev)
> >       int ret = 0;
> >
> >       if (is_of_node(fwnode)) {
> > +             if (!dev_get_msi_domain(dev))
> > +                     of_msi_configure(dev, dev->of_node);
> >               ret = of_dma_configure(dev, to_of_node(fwnode), true);
> >       } else if (is_acpi_device_node(fwnode)) {
> > +             if (!dev_get_msi_domain(dev))
> > +                     acpi_msi_configure(dev);
>
> But surely this needs to handle the deferral case that's being removed
> from some of the users below?

The deferral cases removed by this patch are redundant because:
1) For device tree, the fw_devlink support in Linux DD core takes
case of probe ordering and individual driver don't need to explicitly
do EPROBE_DEFER
2) For ACPI, the _DEP objects helps us ensure probe ordering.

In other words, the issue of probe ordering or deferral is already
handled for both device tree and ACPI.

The only problem which remains is msi_domain pointer not set
in struct device before the driver is probed. This happens because
MSI controller driver is a regular platform driver hence MSI domain
pointer is not set when platform devices are created.

>
> Also I'm not really convinced about bundling it into dma_configure,
> since it's mroe about IRQs than DMA. I wonder if overall it wouldn't be

Using platform_dma_configure() to update the MSI domain
in struct device is appropriate because:
1) MSIs are device initiated writes just like DMA writes
    initiated by the device.
2) The iommu_device_use_default_domain() called by
   platform_dma_configure() will override MSI domain
   in struct device for architectures (such as x86 and
   RISC-V) where IOMMU driver implements a IRQ
   remap MSI domain for MSI capable devices.

> better with a flow closer to regular request_irq(), with
> msi_create_device_irq_domain() growing the ability to distingush between
> "there is no domain" and "there is no domain now, but could be if we try
> again later", such that drivers can handle deferral at the point where
> they request MSI vectors?

Like mentioned above, the problem is not about probe deferral
(aka returning EPROBE_DEFER) from request_irq() or
msi_create_device_irq_domain() rather about updating the
MSI domain pointer in struct device before driver probe.

Regards,
Anup


From cp0613 at linux.alibaba.com  Wed Jun  3 00:14:29 2026
From: cp0613 at linux.alibaba.com (Chen Pei)
Date: Wed,  3 Jun 2026 15:14:29 +0800
Subject: [PATCH 1/8] scripts/sorttable: Handle RISC-V patchable ftrace entries
In-Reply-To: <20260527123530.2593918-2-wanghan@linux.alibaba.com>
References: <20260527123530.2593918-2-wanghan@linux.alibaba.com>
Message-ID: <20260603071430.59794-1-cp0613@linux.alibaba.com>

On Wed, 27 May 2026 20:35:23 +0800, wanghan at linux.alibaba.com wrote:

> On an affected RISC-V QEMU boot with both CONFIG_FTRACE_SORT_STARTUP_TEST
> and CONFIG_FTRACE_STARTUP_TEST enabled, the sort check still passes
> while ftrace reports zero usable entries and the early selftests fail:
> 
>   [    0.000000] ftrace section at ffffffff8101da98 sorted properly
>   [    0.000000] ftrace: allocating 0 entries in 128 pages
>   [    0.054999] Testing tracer function: .. no entries found ..FAILED!
>   [    0.172407] tracer: function failed selftest, disabling
>   [    0.178186] Failed to init function_graph tracer, init returned -19
> 
> Handle RISC-V like arm64 for the function-range check and allow
> patchable entries up to 8 bytes before the function address.
> 
> With this fix, a RISC-V QEMU smoke boot with ftrace startup tests shows
> the vmlinux ftrace table is populated and dynamic ftrace still works:
> 
>   [    0.000000] ftrace: allocating 46749 entries in 184 pages
>   [    0.051115] Testing tracer function: PASSED
>   [    1.283782] Testing dynamic ftrace: PASSED
>   [    6.275456] Testing tracer function_graph: PASSED
> 
> Fixes: 0ca1724b56af ("riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT")

Oops, sorry for missing that. Thanks for the quick fix!

Reviewed-by: Chen Pei <cp0613 at linux.alibaba.com>


From bjorn at kernel.org  Wed Jun  3 00:16:56 2026
From: bjorn at kernel.org (=?UTF-8?B?QmrDtnJuIFTDtnBlbA==?=)
Date: Wed, 3 Jun 2026 09:16:56 +0200
Subject: [PATCH bpf-next 2/2] bpf, riscv: inline bpf_get_current_task()
 and bpf_get_current_task_btf()
In-Reply-To: <20260602205847.102825-3-varunrmallya@gmail.com>
References: <20260602205847.102825-1-varunrmallya@gmail.com> <20260602205847.102825-3-varunrmallya@gmail.com>
Message-ID: <CAJ+HfNgWvufshCz2CwTeJ=NyjGKVhCrkTLz_v0g+34K=5MEC1A@mail.gmail.com>

On Tue, 2 Jun 2026 at 22:59, Varun R Mallya <varunrmallya at gmail.com> wrote:
>
> On RISC-V, the current task pointer is stored in the thread pointer
> register (tp). Emit a single `mv a5, tp` instead of a full helper
> call for BPF_FUNC_get_current_task and BPF_FUNC_get_current_task_btf.
>
> Register bpf_jit_inlines_helper_call() entries for both helpers so the
> verifier treats them as inlined, and add the expected `mv a5, tp`
> annotation to the riscv64 selftests.
>
> The following show changes before and after this patch.
>
> Before patch:
>
>       auipc  t1,0x817a    # load upper PC-relative address
>       jalr   -2004(t1)    # call bpf_get_current_task helper
>       mv     a5,a0        # move return value to BPF_REG_0
>
> After patch:
>
>       mv     a5,tp        # directly: a5 = current (tp = thread pointer)
>
> Benchmark (bpf_prog_test_run wrapping bpf_get_current_task in loop,
> batch=100, 10s, QEMU RISC-V):
>
>               | runs/sec  | helper-calls/sec | ns/call
>  -------------+-----------+------------------+---------
>  Before patch |   173,490 |       17,349,090 |      57
>  After patch  |   320,497 |       32,049,780 |      31
>  -------------+-----------+------------------+---------
>  Improvement  |   +84.7%  |          +84.7%  |  -45.6%
>
> Signed-off-by: Varun R Mallya <varunrmallya at gmail.com>

Acked-by: Bj?rn T?pel <bjorn at kernel.org>


From bjorn at kernel.org  Wed Jun  3 00:21:41 2026
From: bjorn at kernel.org (=?UTF-8?B?QmrDtnJuIFTDtnBlbA==?=)
Date: Wed, 3 Jun 2026 09:21:41 +0200
Subject: [PATCH bpf-next 1/2] selftests/bpf: use host CPU features in JIT disassembler
In-Reply-To: <20260602205847.102825-2-varunrmallya@gmail.com>
References: <20260602205847.102825-1-varunrmallya@gmail.com> <20260602205847.102825-2-varunrmallya@gmail.com>
Message-ID: <CAJ+HfNjWsEDUaEX0aqMMYhXFJDLqEVkhRw00eT3c453OR_FE3g@mail.gmail.com>

On Tue, 2 Jun 2026 at 22:59, Varun R Mallya <varunrmallya at gmail.com> wrote:
>
> Pass the host CPU name and feature string to
> LLVMCreateDisasmCPUFeatures() instead of using LLVMCreateDisasm(), so
> the disassembler correctly decodes CPU-specific instructions and
> extensions such as RISC-V compressed and vector instructions.
>
> Signed-off-by: Varun R Mallya <varunrmallya at gmail.com>

Reviewed-by: Bj?rn T?pel <bjorn at kernel.org>


From p.zabel at pengutronix.de  Wed Jun  3 00:34:31 2026
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 03 Jun 2026 09:34:31 +0200
Subject: [PATCH v2] MAINTAINERS: add entry for SpacemiT reset controller
 driver
In-Reply-To: <20260603-b4-spacemit-reset-maintainers-v2-1-db0716d43a7f@gmail.com>
References: <20260603-b4-spacemit-reset-maintainers-v2-1-db0716d43a7f@gmail.com>
Message-ID: <62e1781e127176294088cee9c120b3173359ec4b.camel@pengutronix.de>

On Mi, 2026-06-03 at 06:26 -0400, Guodong Xu wrote:
> Add a MAINTAINERS entry for the SpacemiT reset controller driver
> (drivers/reset/spacemit/) and its reset-ID header. I intend to
> maintain it: the K1 and K3 instances now, and future SpacemiT SoCs
> that reuse the common code.
> 
> Link: https://lore.kernel.org/spacemit/20260120-k3-reset-v3-0-effe87f4bdbe at riscstar.com/
> Acked-by: Alex Elder <elder at riscstar.com>
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>

Acked-by: Philipp Zabel <p.zabel at pengutronix.de>

regards
Philipp


From joel at jms.id.au  Wed Jun  3 00:42:12 2026
From: joel at jms.id.au (Joel Stanley)
Date: Wed,  3 Jun 2026 17:12:12 +0930
Subject: [PATCH 0/7] riscv: dts: tenstorrent: Add Atlantis platform
Message-ID: <20260603074222.593243-1-joel@jms.id.au>

Add initial support for the Tenstorrent Atlantis platform, based on the
Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.

The series adds a bare bones device tree with the CPU, interrupt
controllers and a UART. This will be replaced in time with a full
featured machine once details are available.

Patches 1, 2, 3, 5, and 6 add compatibles or extensions to existing
bindings.

Patch 4 adds a new binding document for the aclint timer device.

The series has been boot tested on QEMU[1] and internal development
platforms.

[1] https://lore.kernel.org/qemu-riscv/20260603065859.592063-1-joel at jms.id.au/


Drew Fustini (1):
  dt-bindings: riscv: add Smrnmi extension description

Joel Stanley (6):
  dt-bindings: aplic: Add Tenstorrent Atlantis compatible
  dt-bindings: imsics: Add Tenstorrent Atlantis compatible
  dt-bindings: riscv: cpus: Add Tenstorrent Ascalon
  dt-bindings: timer: Add RISC-V ACLINT bindings
  dt-bindings: riscv: Add Tenstorrent Atlantis platform
  riscv: dts: tenstorrent: Add Atlantis platform

 MAINTAINERS                                   |   1 +
 .../interrupt-controller/riscv,aplic.yaml     |   1 +
 .../interrupt-controller/riscv,imsics.yaml    |   1 +
 .../devicetree/bindings/riscv/cpus.yaml       |   5 +
 .../devicetree/bindings/riscv/extensions.yaml |   6 +
 .../bindings/riscv/tenstorrent.yaml           |   4 +
 .../bindings/timer/riscv,aclint-mtimer.yaml   |  52 ++
 arch/riscv/boot/dts/tenstorrent/Makefile      |   1 +
 .../boot/dts/tenstorrent/atlantis-evb.dts     |  31 ++
 .../boot/dts/tenstorrent/atlantis-soc.dtsi    | 470 ++++++++++++++++++
 10 files changed, 572 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
 create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
 create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi

-- 
2.47.3



From joel at jms.id.au  Wed Jun  3 00:42:13 2026
From: joel at jms.id.au (Joel Stanley)
Date: Wed,  3 Jun 2026 17:12:13 +0930
Subject: [PATCH 1/7] dt-bindings: aplic: Add Tenstorrent Atlantis compatible
In-Reply-To: <20260603074222.593243-1-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
Message-ID: <20260603074222.593243-2-joel@jms.id.au>

Add compatible for APLIC in Tenstorrent Atlantis SoC.

Signed-off-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 .../devicetree/bindings/interrupt-controller/riscv,aplic.yaml    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
index 0718071444d2..d4e17861eda4 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
@@ -29,6 +29,7 @@ properties:
       - enum:
           - qemu,aplic
           - spacemit,k3-aplic
+          - tenstorrent,atlantis-aplic
       - const: riscv,aplic
 
   reg:
-- 
2.47.3



From joel at jms.id.au  Wed Jun  3 00:42:14 2026
From: joel at jms.id.au (Joel Stanley)
Date: Wed,  3 Jun 2026 17:12:14 +0930
Subject: [PATCH 2/7] dt-bindings: imsics: Add Tenstorrent Atlantis compatible
In-Reply-To: <20260603074222.593243-1-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
Message-ID: <20260603074222.593243-3-joel@jms.id.au>

Add compatible for IMSICS in Tenstorrent Atlantis SoC.

Signed-off-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 .../devicetree/bindings/interrupt-controller/riscv,imsics.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
index feec122bddde..442b8870f9c5 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
@@ -49,6 +49,7 @@ properties:
       - enum:
           - qemu,imsics
           - spacemit,k3-imsics
+          - tenstorrent,atlantis-imsics
       - const: riscv,imsics
 
   reg:
-- 
2.47.3



From joel at jms.id.au  Wed Jun  3 00:42:15 2026
From: joel at jms.id.au (Joel Stanley)
Date: Wed,  3 Jun 2026 17:12:15 +0930
Subject: [PATCH 3/7] dt-bindings: riscv: cpus: Add Tenstorrent Ascalon
In-Reply-To: <20260603074222.593243-1-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
Message-ID: <20260603074222.593243-4-joel@jms.id.au>

Add Tenstorrent Ascalon microarchitecture and the Tenstorrent Ascalon-XG
core.

Signed-off-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 Documentation/devicetree/bindings/riscv/cpus.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
index 5feeb2203050..2a57bd14569e 100644
--- a/Documentation/devicetree/bindings/riscv/cpus.yaml
+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
@@ -75,6 +75,11 @@ properties:
               - sifive,x280
           - const: sifive,rocket0
           - const: riscv
+      - items:
+          - enum:
+              - tenstorrent,ascalon-xg
+          - const: tenstorrent,ascalon
+          - const: riscv
       - const: riscv    # Simulator only
     description:
       Identifies that the hart uses the RISC-V instruction set
-- 
2.47.3



From joel at jms.id.au  Wed Jun  3 00:42:16 2026
From: joel at jms.id.au (Joel Stanley)
Date: Wed,  3 Jun 2026 17:12:16 +0930
Subject: [PATCH 4/7] dt-bindings: timer: Add RISC-V ACLINT bindings
In-Reply-To: <20260603074222.593243-1-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
Message-ID: <20260603074222.593243-5-joel@jms.id.au>

Document the bindings for the RISC-V ACLINT.

Signed-off-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 MAINTAINERS                                   |  1 +
 .../bindings/timer/riscv,aclint-mtimer.yaml   | 52 +++++++++++++++++++
 2 files changed, 53 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml

diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..43dd9873bbc5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23005,6 +23005,7 @@ M:	Joel Stanley <jms at oss.tenstorrent.com>
 L:	linux-riscv at lists.infradead.org
 S:	Maintained
 T:	git https://github.com/tenstorrent/linux.git
+F:	Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
 F:	Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
 F:	Documentation/devicetree/bindings/riscv/tenstorrent.yaml
 F:	arch/riscv/boot/dts/tenstorrent/
diff --git a/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
new file mode 100644
index 000000000000..192ff3fcf79f
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
@@ -0,0 +1,52 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/riscv,aclint-mtimer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RISC-V Advanced Core Local Interruptor (ACLINT)
+
+maintainers:
+  - Joel Stanley <jms at oss.tenstorrent.com>
+
+description:
+  This RISC-V ACLINT specification defines a set of memory mapped devices which
+  provide inter-processor interrupts (IPI) and timer functionalities for each
+  HART on a multi-HART RISC-V platform. The specification can be found at
+  https://github.com/riscvarchive/riscv-aclint/
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - tenstorrent,atlantis-aclint
+          - qemu,aclint-mtimer
+      - const: riscv,aclint-mtimer
+
+  reg:
+    minItems: 1
+    maxItems: 4095
+
+  interrupts-extended:
+    minItems: 1
+    maxItems: 4095
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    // Example 1
+
+    timer at ac000000 {
+      compatible = "tenstorrent,atlantis-aclint", "riscv,aclint-mtimer";
+      interrupts-extended = <&cpu1intc 7>,
+                            <&cpu2intc 7>,
+                            <&cpu3intc 7>,
+                            <&cpu4intc 7>;
+      reg = <0xac000000 0x00010000>;
+    };
+...
-- 
2.47.3



From joel at jms.id.au  Wed Jun  3 00:42:17 2026
From: joel at jms.id.au (Joel Stanley)
Date: Wed,  3 Jun 2026 17:12:17 +0930
Subject: [PATCH 5/7] dt-bindings: riscv: add Smrnmi extension description
In-Reply-To: <20260603074222.593243-1-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
Message-ID: <20260603074222.593243-6-joel@jms.id.au>

From: Drew Fustini <fustini at kernel.org>

Add description for the Smrnmi extension (Resumable Non-Maskable
Interrupts) as ratified in 35eb3948bf0b ("Merge pull request #1492 from
riscv/smrnmi-ratified") of the riscv-isa-manual.

Signed-off-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 Documentation/devicetree/bindings/riscv/extensions.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb21..3e3b4481724f 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -193,6 +193,12 @@ properties:
             ratified at commit d70011dde6c2 ("Update to ratified state")
             of riscv-j-extension.
 
+        - const: smrnmi
+          description: |
+            The standard Smrnmi extension for Resumable Non-Maskable Interrupts
+            as ratified in commit 35eb3948bf0b ("Merge pull request #1492 from
+            riscv/smrnmi-ratified") of the riscv-isa-manual.
+
         - const: smstateen
           description: |
             The standard Smstateen extension for controlling access to CSRs
-- 
2.47.3



From joel at jms.id.au  Wed Jun  3 00:42:18 2026
From: joel at jms.id.au (Joel Stanley)
Date: Wed,  3 Jun 2026 17:12:18 +0930
Subject: [PATCH 6/7] dt-bindings: riscv: Add Tenstorrent Atlantis platform
In-Reply-To: <20260603074222.593243-1-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
Message-ID: <20260603074222.593243-7-joel@jms.id.au>

Add compatible for the Tenstorrent Atlantis platform.

Signed-off-by: Joel Stanley <joel at jms.id.au>
Signed-off-by: Drew Fustini <fustini at kernel.org>
---
 Documentation/devicetree/bindings/riscv/tenstorrent.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/tenstorrent.yaml b/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
index e15359b2aab6..7fb640e38455 100644
--- a/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
+++ b/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
@@ -22,6 +22,10 @@ properties:
         items:
           - const: tenstorrent,blackhole-card
           - const: tenstorrent,blackhole
+      - description: Tenstorrent Atlantis
+        items:
+          - const: tenstorrent,atlantis-evb
+          - const: tenstorrent,atlantis
 
 additionalProperties: true
 
-- 
2.47.3



From joel at jms.id.au  Wed Jun  3 00:42:19 2026
From: joel at jms.id.au (Joel Stanley)
Date: Wed,  3 Jun 2026 17:12:19 +0930
Subject: [PATCH 7/7] riscv: dts: tenstorrent: Add Atlantis platform
In-Reply-To: <20260603074222.593243-1-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
Message-ID: <20260603074222.593243-8-joel@jms.id.au>

Add initial support for the Tenstorrent Atlantis platform, based on the
Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.

The evb machine represents an internal bringup vehicle with just the
interrupt controllers and a UART. This will be replaced in time with a
full featured machine once details are available.

Signed-off-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 arch/riscv/boot/dts/tenstorrent/Makefile      |   1 +
 .../boot/dts/tenstorrent/atlantis-evb.dts     |  31 ++
 .../boot/dts/tenstorrent/atlantis-soc.dtsi    | 470 ++++++++++++++++++
 3 files changed, 502 insertions(+)
 create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
 create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi

diff --git a/arch/riscv/boot/dts/tenstorrent/Makefile b/arch/riscv/boot/dts/tenstorrent/Makefile
index 2c81faaba462..92d8bb1a683f 100644
--- a/arch/riscv/boot/dts/tenstorrent/Makefile
+++ b/arch/riscv/boot/dts/tenstorrent/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_TENSTORRENT) += blackhole-card.dtb
+dtb-$(CONFIG_ARCH_TENSTORRENT) += atlantis-evb.dtb
diff --git a/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
new file mode 100644
index 000000000000..28576b87d300
--- /dev/null
+++ b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/dts-v1/;
+
+#include "atlantis-soc.dtsi"
+
+/ {
+	model = "Tenstorrent Atlantis development platform";
+	compatible = "tenstorrent,atlantis-evb", "tenstorrent,atlantis";
+
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	memory at 0 {
+		device_type = "memory";
+		reg = <0x0 0x00000000 0x0 0x80000000>,
+		      <0x1 0x80000000 0x0 0x80000000>;
+	};
+
+	aliases {
+		serial0 = &uart1;
+	};
+
+	chosen {
+		bootargs = "earlycon console=ttyS0";
+		stdout-path = "serial0";
+	};
+};
+
+&uart1 {
+	status = "okay";
+};
diff --git a/arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi b/arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi
new file mode 100644
index 000000000000..1e312b1363f8
--- /dev/null
+++ b/arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi
@@ -0,0 +1,470 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h>
+
+/ {
+	model = "Tenstorrent Atlantis";
+	compatible = "tenstorrent,atlantis";
+
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		timebase-frequency = <1000000000>;
+
+		cpu0: cpu at 0 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <0>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu0_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu1: cpu at 1 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <1>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu1_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu2: cpu at 2 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <2>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu2_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu3: cpu at 3 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <3>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu3_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu4: cpu at 4 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <4>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu4_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu5: cpu at 5 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <5>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu5_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu6: cpu at 6 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <6>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu6_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu7: cpu at 7 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <7>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu7_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		l2_cache: l2-cache {
+			compatible = "cache";
+			cache-block-size = <64>;
+			cache-level = <2>;
+			cache-size = <0xc00000>;
+			cache-sets = <512>;
+			cache-unified;
+		};
+	};
+
+	clocks {
+		osc_24m: clock-24m {
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+			clock-output-names = "osc_24m";
+			#clock-cells = <0>;
+		};
+	};
+
+	soc {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		compatible = "simple-bus";
+		interrupt-parent = <&aplic_s>;
+		ranges;
+
+		imsic_m: interrupt-controller at a0000000 {
+			compatible = "tenstorrent,atlantis-imsics", "riscv,imsics";
+			riscv,num-ids = <255>;
+			riscv,guest-index-bits = <6>;
+			reg = <0x0 0xa0000000 0x0 0x200000>;
+			interrupts-extended = <&cpu0_intc 11>, <&cpu1_intc 11>,
+					      <&cpu2_intc 11>, <&cpu3_intc 11>,
+					      <&cpu4_intc 11>, <&cpu5_intc 11>,
+					      <&cpu6_intc 11>, <&cpu7_intc 11>;
+			msi-controller;
+			#msi-cells = <0>;
+			interrupt-controller;
+			#interrupt-cells = <0>;
+		};
+
+		mtimer: timer at a2180000 {
+			compatible = "tenstorrent,atlantis-aclint", "riscv,aclint-mtimer";
+			interrupts-extended = <&cpu0_intc 7>, <&cpu1_intc 7>,
+					      <&cpu2_intc 7>, <&cpu3_intc 7>,
+					      <&cpu4_intc 7>, <&cpu5_intc 7>,
+					      <&cpu6_intc 7>, <&cpu7_intc 7>;
+			reg = <0x0 0xa2180000 0x0 0x8000 0x00 0xa2188000 0x0 0x8000>;
+		};
+
+		imsic_s: interrupt-controller at a4000000 {
+			compatible = "tenstorrent,atlantis-imsics", "riscv,imsics";
+			riscv,num-ids = <255>;
+			riscv,guest-index-bits = <6>;
+			reg = <0x0 0xa4000000 0x0 0x200000>;
+			interrupts-extended = <&cpu0_intc 9>, <&cpu1_intc 9>,
+					      <&cpu2_intc 9>, <&cpu3_intc 9>,
+					      <&cpu4_intc 9>, <&cpu5_intc 9>,
+					      <&cpu6_intc 9>, <&cpu7_intc 9>;
+			msi-controller;
+			#msi-cells = <0>;
+			interrupt-controller;
+			#interrupt-cells = <0>;
+		};
+
+		aplic_m: interrupt-controller at cc000000 {
+			compatible = "tenstorrent,atlantis-aplic", "riscv,aplic";
+			msi-parent = <&imsic_m>;
+			riscv,delegation = <&aplic_s 1 96>;
+			riscv,children = <&aplic_s>;
+			riscv,num-sources = <96>;
+			reg = <0x0 0xcc000000 0x0 0x4000000>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			#address-cells = <0>;
+		};
+
+		prcm_rcpu: clock-controller at d0000000 {
+			compatible = "tenstorrent,atlantis-prcm-rcpu";
+			reg = <0x00 0xd0000000 0x00 0x10000>;
+			clocks = <&osc_24m>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			assigned-clocks = <&prcm_rcpu CLK_RCPU_ROOT>, <&prcm_rcpu CLK_NOCC_CLK>;
+			assigned-clock-parents = <&prcm_rcpu CLK_RCPU_ROOT>, <&prcm_rcpu CLK_NOC_PLL>;
+		};
+
+		uart0: serial at d4100000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART0_PCLK>;
+			reg = <0x0 0xd4100000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		uart1: serial at d4110000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART1_PCLK>;
+			reg = <0x0 0xd4110000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		uart2: serial at d4120000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <40 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART2_PCLK>;
+			reg = <0x0 0xd4120000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		uart3: serial at d4130000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <41 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART3_PCLK>;
+			reg = <0x0 0xd4130000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		uart4: serial at d4140000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <42 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART4_PCLK>;
+			reg = <0x0 0xd4140000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		aplic_s: interrupt-controller at e8000000 {
+			compatible = "tenstorrent,atlantis-aplic", "riscv,aplic";
+			msi-parent = <&imsic_s>;
+			riscv,num-sources = <96>;
+			reg = <0x0 0xe8000000 0x0 0x4000000>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			#address-cells = <0>;
+		};
+	};
+};
-- 
2.47.3



From anup at brainfault.org  Wed Jun  3 00:46:14 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 13:16:14 +0530
Subject: [PATCH v2 4/7] RISC-V: KVM: Allow Zicfiss/Zicfilp extensions for Guest/VM
In-Reply-To: <ah1pgb4S-UoSWhC_@inochi.infowork>
References: <20260601084336.2601675-1-inochiama@gmail.com> <20260601084336.2601675-5-inochiama@gmail.com>
 <ah1pgb4S-UoSWhC_@inochi.infowork>
Message-ID: <CAAhSdy0ZycwjYrKowzaydKhh=fcEDD9-C6TKmb838s0hq8a2hA@mail.gmail.com>

On Mon, Jun 1, 2026 at 4:46?PM Inochi Amaoto <inochiama at gmail.com> wrote:
>
> On Mon, Jun 01, 2026 at 04:43:32PM +0800, Inochi Amaoto wrote:
> > Extend the KVM ISA extension array to allow KVM userspace to
> > detect and enable Zicfiss/Zicfilp extensions for Guest/VM.
> >
> > Assisted-by: YuanSheng:claude-4.7-opus
> > Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
> > Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
> > Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> > ---
> >  arch/riscv/include/uapi/asm/kvm.h | 2 ++
> >  arch/riscv/kvm/isa.c              | 2 ++
> >  2 files changed, 4 insertions(+)
> >
>
> I have forgot to add CSR_SSP to the context, will add in the next
> version. But I have a small question for it: could I reuse the
> generic subtype or use a new CSR subtype?
>

Add another CSR subtype for Zicfiss.

Regards,
Anup


From anup at brainfault.org  Wed Jun  3 00:47:43 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 13:17:43 +0530
Subject: [PATCH 1/7] dt-bindings: aplic: Add Tenstorrent Atlantis compatible
In-Reply-To: <20260603074222.593243-2-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au> <20260603074222.593243-2-joel@jms.id.au>
Message-ID: <CAAhSdy0VgZd+7x0j5CZTj-9D6n4=UehzKZKp0nzTBpmuJESqeg@mail.gmail.com>

On Wed, Jun 3, 2026 at 1:12?PM Joel Stanley <joel at jms.id.au> wrote:
>
> Add compatible for APLIC in Tenstorrent Atlantis SoC.
>
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Regards,
Anup

> ---
>  .../devicetree/bindings/interrupt-controller/riscv,aplic.yaml    | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
> index 0718071444d2..d4e17861eda4 100644
> --- a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
> +++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
> @@ -29,6 +29,7 @@ properties:
>        - enum:
>            - qemu,aplic
>            - spacemit,k3-aplic
> +          - tenstorrent,atlantis-aplic
>        - const: riscv,aplic
>
>    reg:
> --
> 2.47.3
>


From anup at brainfault.org  Wed Jun  3 00:48:05 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 13:18:05 +0530
Subject: [PATCH 2/7] dt-bindings: imsics: Add Tenstorrent Atlantis compatible
In-Reply-To: <20260603074222.593243-3-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au> <20260603074222.593243-3-joel@jms.id.au>
Message-ID: <CAAhSdy2emR_vKfWXeLfx6RLTgaNTASroNxhDPzkortHkhASP1Q@mail.gmail.com>

On Wed, Jun 3, 2026 at 1:13?PM Joel Stanley <joel at jms.id.au> wrote:
>
> Add compatible for IMSICS in Tenstorrent Atlantis SoC.
>
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Regards,
Anup

> ---
>  .../devicetree/bindings/interrupt-controller/riscv,imsics.yaml   | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
> index feec122bddde..442b8870f9c5 100644
> --- a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
> +++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
> @@ -49,6 +49,7 @@ properties:
>        - enum:
>            - qemu,imsics
>            - spacemit,k3-imsics
> +          - tenstorrent,atlantis-imsics
>        - const: riscv,imsics
>
>    reg:
> --
> 2.47.3
>


From anup at brainfault.org  Wed Jun  3 00:50:29 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 13:20:29 +0530
Subject: [PATCH 4/7] dt-bindings: timer: Add RISC-V ACLINT bindings
In-Reply-To: <20260603074222.593243-5-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au> <20260603074222.593243-5-joel@jms.id.au>
Message-ID: <CAAhSdy3cDWy3yNSx=exEk3hjSWYrt2Uye7-eK6Yq9qHOrk0Xyg@mail.gmail.com>

On Wed, Jun 3, 2026 at 1:13?PM Joel Stanley <joel at jms.id.au> wrote:
>
> Document the bindings for the RISC-V ACLINT.
>
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>
> ---
>  MAINTAINERS                                   |  1 +
>  .../bindings/timer/riscv,aclint-mtimer.yaml   | 52 +++++++++++++++++++
>  2 files changed, 53 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2fb1c75afd16..43dd9873bbc5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23005,6 +23005,7 @@ M:      Joel Stanley <jms at oss.tenstorrent.com>
>  L:     linux-riscv at lists.infradead.org
>  S:     Maintained
>  T:     git https://github.com/tenstorrent/linux.git
> +F:     Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
>  F:     Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
>  F:     Documentation/devicetree/bindings/riscv/tenstorrent.yaml
>  F:     arch/riscv/boot/dts/tenstorrent/
> diff --git a/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> new file mode 100644
> index 000000000000..192ff3fcf79f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> @@ -0,0 +1,52 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/timer/riscv,aclint-mtimer.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: RISC-V Advanced Core Local Interruptor (ACLINT)
> +
> +maintainers:
> +  - Joel Stanley <jms at oss.tenstorrent.com>
> +
> +description:
> +  This RISC-V ACLINT specification defines a set of memory mapped devices which
> +  provide inter-processor interrupts (IPI) and timer functionalities for each
> +  HART on a multi-HART RISC-V platform. The specification can be found at
> +  https://github.com/riscvarchive/riscv-aclint/
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - tenstorrent,atlantis-aclint

Use "tenstorrent,atlantis-aclint-mtimer" as compatible string
to be consistent.

> +          - qemu,aclint-mtimer
> +      - const: riscv,aclint-mtimer
> +
> +  reg:
> +    minItems: 1
> +    maxItems: 4095
> +
> +  interrupts-extended:
> +    minItems: 1
> +    maxItems: 4095
> +
> +required:
> +  - compatible
> +  - reg
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    // Example 1
> +
> +    timer at ac000000 {
> +      compatible = "tenstorrent,atlantis-aclint", "riscv,aclint-mtimer";
> +      interrupts-extended = <&cpu1intc 7>,
> +                            <&cpu2intc 7>,
> +                            <&cpu3intc 7>,
> +                            <&cpu4intc 7>;
> +      reg = <0xac000000 0x00010000>;
> +    };
> +...
> --
> 2.47.3
>

Regards,
Anup


From inochiama at gmail.com  Wed Jun  3 01:02:35 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Wed, 3 Jun 2026 16:02:35 +0800
Subject: [PATCH v2 4/7] RISC-V: KVM: Allow Zicfiss/Zicfilp extensions for
 Guest/VM
In-Reply-To: <CAAhSdy0ZycwjYrKowzaydKhh=fcEDD9-C6TKmb838s0hq8a2hA@mail.gmail.com>
References: <20260601084336.2601675-1-inochiama@gmail.com>
 <20260601084336.2601675-5-inochiama@gmail.com>
 <ah1pgb4S-UoSWhC_@inochi.infowork>
 <CAAhSdy0ZycwjYrKowzaydKhh=fcEDD9-C6TKmb838s0hq8a2hA@mail.gmail.com>
Message-ID: <ah_fkXOLpNHvnmNM@inochi.infowork>

On Wed, Jun 03, 2026 at 01:16:14PM +0530, Anup Patel wrote:
> On Mon, Jun 1, 2026 at 4:46?PM Inochi Amaoto <inochiama at gmail.com> wrote:
> >
> > On Mon, Jun 01, 2026 at 04:43:32PM +0800, Inochi Amaoto wrote:
> > > Extend the KVM ISA extension array to allow KVM userspace to
> > > detect and enable Zicfiss/Zicfilp extensions for Guest/VM.
> > >
> > > Assisted-by: YuanSheng:claude-4.7-opus
> > > Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
> > > Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
> > > Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> > > ---
> > >  arch/riscv/include/uapi/asm/kvm.h | 2 ++
> > >  arch/riscv/kvm/isa.c              | 2 ++
> > >  2 files changed, 4 insertions(+)
> > >
> >
> > I have forgot to add CSR_SSP to the context, will add in the next
> > version. But I have a small question for it: could I reuse the
> > generic subtype or use a new CSR subtype?
> >
> 
> Add another CSR subtype for Zicfiss.
> 
> Regards,
> Anup

Thanks, I will do it.

Regards,
Inochi


From anup at brainfault.org  Wed Jun  3 01:18:38 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 13:48:38 +0530
Subject: [PATCH 1/4] RISC-V: KVM: Add the split page cache for ioctl context
In-Reply-To: <20260513153901371U0gWZRa45N893VGbU7Gf9@zte.com.cn>
References: <20260513153656847l3c4fI5hBsAyoIZi8aGIs@zte.com.cn> <20260513153901371U0gWZRa45N893VGbU7Gf9@zte.com.cn>
Message-ID: <CAAhSdy0Wd2=hmJ_1ZXa1mB6ojt32HeA8AW43=GLh52_5DuZqmw@mail.gmail.com>

On Wed, May 13, 2026 at 1:09?PM <wang.yechao255 at zte.com.cn> wrote:
>
> From: Wang Yechao <wang.yechao255 at zte.com.cn>
>
> Add the split page cache for dirty logging enablement and the
> KVM_CLEAR_DIRTY_LOG ioctl.
>
> Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
> ---
>  arch/riscv/include/asm/kvm_host.h | 2 ++
>  arch/riscv/kvm/mmu.c              | 3 +++
>  2 files changed, 5 insertions(+)
>
> diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
> index 75b0a951c1bc..e2f40854305f 100644
> --- a/arch/riscv/include/asm/kvm_host.h
> +++ b/arch/riscv/include/asm/kvm_host.h
> @@ -93,6 +93,8 @@ struct kvm_arch {
>
>         /* KVM_CAP_RISCV_MP_STATE_RESET */
>         bool mp_state_reset;
> +
> +       struct kvm_mmu_memory_cache split_page_cache;

Rename it to pgd_split_page_cache and add it below
pgd_levels.

>  };
>
>  struct kvm_cpu_trap {
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 2d3def024270..85a3fb2622a4 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -549,6 +549,7 @@ int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm)
>         kvm->arch.pgd = page_to_virt(pgd_page);
>         kvm->arch.pgd_phys = page_to_phys(pgd_page);
>         kvm->arch.pgd_levels = kvm_riscv_gstage_max_pgd_levels;
> +       kvm->arch.split_page_cache.gfp_zero = __GFP_ZERO;
>
>         return 0;
>  }
> @@ -572,6 +573,8 @@ void kvm_riscv_mmu_free_pgd(struct kvm *kvm)
>
>         if (pgd)
>                 free_pages((unsigned long)pgd, get_order(kvm_riscv_gstage_pgd_size));
> +
> +       kvm_mmu_free_memory_cache(&kvm->arch.split_page_cache);
>  }
>
>  void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu)
> --
> 2.27.0

Regards,
Anup


From anup at brainfault.org  Wed Jun  3 01:18:41 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 13:48:41 +0530
Subject: =?UTF-8?Q?Re=3A_=5BPATCH_2=2F4=5D_RISC=2DV=3A_KVM=3A_Split_huge_pages_when_d?=
	=?UTF-8?Q?irty_logging_is=C2=A0enabled?=
In-Reply-To: <20260513154125023xfKNqfea7TklqO9_RRrkt@zte.com.cn>
References: <20260513153656847l3c4fI5hBsAyoIZi8aGIs@zte.com.cn> <20260513154125023xfKNqfea7TklqO9_RRrkt@zte.com.cn>
Message-ID: <CAAhSdy28AR=Gs90nofSWPkh9z_gmwmmTjsae_PCyyL_5qXcGhQ@mail.gmail.com>

On Wed, May 13, 2026 at 1:11?PM <wang.yechao255 at zte.com.cn> wrote:
>
> From: Wang Yechao <wang.yechao255 at zte.com.cn>
>
> Split huge pages eagerly when enabling dirty logging. The goal is to
> avoid doing it while faulting on write-protected pages, which
> negatively impacts guest performance.
>
> The benefits of eager page splitting are the same as in x86 and arm64,
> added with commit a3fe5dbda0a4 ("KVM: x86/mmu: Split huge pages mapped
> by the TDP MMU when dirty logging is enabled") and commit e7bf7a490c68
> ("KVM: arm64: Split huge pages when dirty logging is enabled")
>
> Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
> ---
>  arch/riscv/kvm/mmu.c | 62 ++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 62 insertions(+)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 85a3fb2622a4..14c558ee5f15 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -90,6 +90,50 @@ void kvm_riscv_mmu_iounmap(struct kvm *kvm, gpa_t gpa, unsigned long size)
>         spin_unlock(&kvm->mmu_lock);
>  }
>
> +static bool need_topup_split_caches_or_resched(struct kvm_mmu_memory_cache *cache,
> +                                              int count)
> +{
> +       if (need_resched())
> +               return true;
> +
> +       return kvm_mmu_memory_cache_nr_free_objects(cache) < count;
> +}
> +
> +/* the caller must held mmu lock */
> +static void kvm_riscv_split_huge_pages(struct kvm_gstage *gstage,
> +                                      phys_addr_t start, phys_addr_t end,
> +                                      bool flush)

s/kvm_riscv_split_huge_pages/mmu_split_huge_pages/

> +{
> +       struct kvm *kvm = gstage->kvm;
> +       struct kvm_mmu_memory_cache *pcache = &kvm->arch.split_page_cache;
> +       int count = gstage->pgd_levels;
> +       phys_addr_t addr = start;
> +       int ret;
> +

lockdep_assert_held ??

> +       while (addr < end) {
> +               if (need_topup_split_caches_or_resched(pcache, count)) {
> +                       spin_unlock(&kvm->mmu_lock);
> +                       cond_resched();
> +
> +                       ret = kvm_mmu_topup_memory_cache(pcache, count);
> +                       if (ret) {
> +                               kvm_err("Failed to toup split page cache\n");
> +                               spin_lock(&kvm->mmu_lock);
> +                               return;
> +                       }
> +                       spin_lock(&kvm->mmu_lock);
> +               }
> +
> +               ret = kvm_riscv_gstage_split_huge(gstage, pcache, addr, 0, flush);
> +               if (ret != 0) {
> +                       kvm_err("split huge page for addr(0x%llx) failed %d\n", addr, ret);
> +                       break;
> +               }
> +
> +               addr += PMD_SIZE;
> +       }
> +}
> +
>  void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
>                                              struct kvm_memory_slot *slot,
>                                              gfn_t gfn_offset,
> @@ -136,6 +180,23 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
>         spin_unlock(&kvm->mmu_lock);
>  }
>
> +static void kvm_riscv_split_memory_region(struct kvm *kvm, int slot)

s/kvm_riscv_split_memory_region/mmu_split_memory_region/

> +{
> +       struct kvm_memslots *slots = kvm_memslots(kvm);
> +       struct kvm_memory_slot *memslot = id_to_memslot(slots, slot);
> +       phys_addr_t start = memslot->base_gfn << PAGE_SHIFT;
> +       phys_addr_t end = (memslot->base_gfn + memslot->npages) << PAGE_SHIFT;
> +       struct kvm_gstage gstage;
> +
> +       kvm_riscv_gstage_init(&gstage, kvm);
> +
> +       spin_lock(&kvm->mmu_lock);
> +       kvm_riscv_split_huge_pages(&gstage, start, end, false);
> +       spin_unlock(&kvm->mmu_lock);
> +
> +       kvm_flush_remote_tlbs_memslot(kvm, memslot);
> +}
> +
>  void kvm_arch_commit_memory_region(struct kvm *kvm,
>                                 struct kvm_memory_slot *old,
>                                 const struct kvm_memory_slot *new,
> @@ -150,6 +211,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
>                 if (kvm_dirty_log_manual_protect_and_init_set(kvm))
>                         return;
>                 mmu_wp_memory_region(kvm, new->id);
> +               kvm_riscv_split_memory_region(kvm, new->id);
>         }
>  }
>
> --
> 2.27.0

Regards,
Anup


From anup at brainfault.org  Wed Jun  3 01:18:47 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 13:48:47 +0530
Subject: [PATCH 4/4] RISC-V: KVM: Add the eager_page_split module parameter
In-Reply-To: <20260513154500183qjAlxzbei98Q4B5HjLpMx@zte.com.cn>
References: <20260513153656847l3c4fI5hBsAyoIZi8aGIs@zte.com.cn> <20260513154500183qjAlxzbei98Q4B5HjLpMx@zte.com.cn>
Message-ID: <CAAhSdy13aO5b7rXfE4eNz+r8cLUhN3-T_YMegRPE2=15KCR1+Q@mail.gmail.com>

On Wed, May 13, 2026 at 1:15?PM <wang.yechao255 at zte.com.cn> wrote:
>
> From: Wang Yechao <wang.yechao255 at zte.com.cn>
>
> Add an eager_page_split module parameter for RISC-V KVM, following
> the same approach as on x86. This parameter controls whether eager
> page splitting is enabled. The default value is on.
>
> When eager page splitting is enabled, KVM proactively splits large
> pages (huge pages) into smaller pages when needed for dirty logging
> or other operations. Disabling it can be beneficial for VM workloads
> that rarely perform writes, or that only write to a small region of
> memory, as it allows huge pages to remain intact for read accesses.
>
> Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>

Update Documentation/admin-guide/kernel-parameters.txt as part
of this patch.

Regards,
Anup


> ---
>  arch/riscv/kvm/mmu.c | 13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 2cdea3e3ed4b..2af03c48aff3 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -16,6 +16,9 @@
>  #include <asm/kvm_mmu.h>
>  #include <asm/kvm_nacl.h>
>
> +bool __read_mostly eager_page_split = true;
> +module_param(eager_page_split, bool, 0644);
> +
>  static void mmu_wp_memory_region(struct kvm *kvm, int slot)
>  {
>         struct kvm_memslots *slots = kvm_memslots(kvm);
> @@ -148,8 +151,10 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
>
>         kvm_riscv_gstage_wp_range(&gstage, start, end);
>
> -       if (kvm_dirty_log_manual_protect_and_init_set(kvm))
> -               kvm_riscv_split_huge_pages(&gstage, start, end, true);
> +       if (kvm_dirty_log_manual_protect_and_init_set(kvm)) {
> +               if (READ_ONCE(eager_page_split))
> +                       kvm_riscv_split_huge_pages(&gstage, start, end, true);
> +       }
>  }
>
>  void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
> @@ -214,7 +219,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
>                 if (kvm_dirty_log_manual_protect_and_init_set(kvm))
>                         return;
>                 mmu_wp_memory_region(kvm, new->id);
> -               kvm_riscv_split_memory_region(kvm, new->id);
> +
> +               if (READ_ONCE(eager_page_split))
> +                       kvm_riscv_split_memory_region(kvm, new->id);
>         }
>  }
>
> --
> 2.27.0


From anup at brainfault.org  Wed Jun  3 01:18:44 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 13:48:44 +0530
Subject: [PATCH 3/4] RISC-V: KVM: Split huge pages during KVM_CLEAR_DIRTY_LOG
In-Reply-To: <20260513154251861FBOlxl8ySih_oqyoJL1iA@zte.com.cn>
References: <20260513153656847l3c4fI5hBsAyoIZi8aGIs@zte.com.cn> <20260513154251861FBOlxl8ySih_oqyoJL1iA@zte.com.cn>
Message-ID: <CAAhSdy3vB+jes4WxQh4jN2GSmLYU6i_tySfKd3Y2xcZJQ6K0Yw@mail.gmail.com>

On Wed, May 13, 2026 at 1:13?PM <wang.yechao255 at zte.com.cn> wrote:
>
> From: Wang Yechao <wang.yechao255 at zte.com.cn>
>
> Split huge pages on the range specified using KVM_CLEAR_DIRTY_LOG.
> And do not split when enabling dirty logging if
> KVM_DIRTY_LOG_INITIALLY_SET is set.
>
> Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup


> ---
>  arch/riscv/kvm/mmu.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 14c558ee5f15..2cdea3e3ed4b 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -147,6 +147,9 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
>         kvm_riscv_gstage_init(&gstage, kvm);
>
>         kvm_riscv_gstage_wp_range(&gstage, start, end);
> +
> +       if (kvm_dirty_log_manual_protect_and_init_set(kvm))
> +               kvm_riscv_split_huge_pages(&gstage, start, end, true);
>  }
>
>  void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
> --
> 2.27.0


From lpieralisi at kernel.org  Wed Jun  3 01:20:56 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Wed, 03 Jun 2026 10:20:56 +0200
Subject: [PATCH v2 0/6] irqchip/ACPI: Arm GICv5 IWB ACPI IRQ probe deferral
Message-ID: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>

On Arm GICv5 systems, the IWB (Interrupt Wire Bridge) handles wired interrupts
and it is in charge of translating interrupt wires to GICv5 ITS messages.

In ACPI systems, an IWB is backed by a platform device. Device drivers for
devices whose IRQs are routed to an IWB might probe earlier than the IWB device
driver, which can result in failures in that until the IWB driver is probed and
its IRQ domain is duly registered, IRQs routed to it cannot be resolved.

Some interrupt controllers for the RISC-V architecture suffer from the same
issue; RISC-V, in its ACPI IRQ layer solved the problem by automatically
creating device dependencies that result in the interrupt controllers drivers
being probed before any device driver whose devices IRQs are routed to them is
probed.

Instead of reinventing the wheel, this series move the aforementioned RISC-V
code to generic ACPI IRQ handling code (while fixing some bits and pieces) and
implement GICv5 IWB ACPI probe deferral on top of it.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
---
Changes in v2:
- Split the patchset in several logic units according to review
- Link to v1: https://patch.msgid.link/20260505-gic-v5-acpi-iwb-probe-deferral-v1-0-b37b85998362 at kernel.org

---
Lorenzo Pieralisi (6):
      ACPI: RISC-V: Fix riscv_acpi_irq_get_dep() loop termination
      ACPI: RISC-V: Check acpi_get_handle() status in riscv_acpi_add_prt_dep()
      ACPI: RISC-V: Fix riscv_acpi_add_prt_dep() loop handling
      ACPI: irq: Move RISC-V interrupt controllers autodep to ACPI IRQ code
      ACPI/IORT: Implement ACPI infrastructure to enable GICv5 IWB probe deferral
      irqchip/gic-v5: Enable GICv5 IWB ACPI probe ordering detection

 arch/riscv/include/asm/acpi.h       |   1 +
 drivers/acpi/arm64/iort.c           |  22 ++++-
 drivers/acpi/irq.c                  | 172 +++++++++++++++++++++++++++++++++++-
 drivers/acpi/riscv/irq.c            | 141 +----------------------------
 drivers/acpi/scan.c                 |   1 +
 drivers/irqchip/irq-gic-v3.c        |   2 +-
 drivers/irqchip/irq-gic-v5-iwb.c    |   5 ++
 drivers/irqchip/irq-gic-v5.c        |  13 ++-
 drivers/irqchip/irq-gic.c           |   2 +-
 drivers/irqchip/irq-loongarch-cpu.c |   2 +-
 drivers/irqchip/irq-riscv-intc.c    |   3 +-
 include/linux/acpi.h                |   5 +-
 include/linux/acpi_iort.h           |   3 +-
 13 files changed, 218 insertions(+), 154 deletions(-)
---
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
change-id: 20260427-gic-v5-acpi-iwb-probe-deferral-cdc849b1a854

Best regards,
--  
Lorenzo Pieralisi <lpieralisi at kernel.org>



From lpieralisi at kernel.org  Wed Jun  3 01:20:57 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Wed, 03 Jun 2026 10:20:57 +0200
Subject: [PATCH v2 1/6] ACPI: RISC-V: Fix riscv_acpi_irq_get_dep() loop
 termination
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
Message-ID: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-1-23ffa16b6ebb@kernel.org>

In riscv_acpi_add_irq_dep() the main loop condition would currently stop
the loop if an interrupt descriptor contains an interrupt for which the
respective GSI handle is NULL, which is not correct because subsequent
interrupts in the interrupt descriptor might still have a GSI dependency
that must not be skipped.

Rework riscv_acpi_add_irq_dep() and the riscv_acpi_irq_get_dep() call chain
to fix it - by not forcing the loop to stop in order to guarantee
dependency detection for all the interrupt entries in the CRS descriptor.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: "Rafael J. Wysocki" <rafael at kernel.org>
Cc: Sunil V L <sunilvl at ventanamicro.com>
---
 drivers/acpi/riscv/irq.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
index 9b88d0993e88..cd83c3035cf6 100644
--- a/drivers/acpi/riscv/irq.c
+++ b/drivers/acpi/riscv/irq.c
@@ -299,6 +299,7 @@ static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *c
 			return AE_OK;
 
 		ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
+		ctx->rc = 0;
 		return AE_CTRL_TERMINATE;
 	}
 
@@ -314,10 +315,8 @@ static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_h
 
 	acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
 	*gsi_handle = ctx.handle;
-	if (*gsi_handle)
-		return 1;
 
-	return 0;
+	return ctx.rc;
 }
 
 static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
@@ -381,8 +380,11 @@ static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
 	int i;
 
 	for (i = 0;
-	     riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
+	     !riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
 	     i++) {
+		if (!gsi_handle)
+			continue;
+
 		dep_devices.count = 1;
 		dep_devices.handles = kzalloc_objs(*dep_devices.handles, 1);
 		if (!dep_devices.handles) {

-- 
2.54.0



From lpieralisi at kernel.org  Wed Jun  3 01:20:58 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Wed, 03 Jun 2026 10:20:58 +0200
Subject: [PATCH v2 2/6] ACPI: RISC-V: Check acpi_get_handle() status in
 riscv_acpi_add_prt_dep()
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
Message-ID: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-2-23ffa16b6ebb@kernel.org>

In riscv_acpi_add_prt_dep(), the acpi_get_handle() call can fail which
would leave link_handle uninitialized.

Fix it by checking the acpi_get_handle() return status and skip the entry
if it fails.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: "Rafael J. Wysocki" <rafael at kernel.org>
Cc: Sunil V L <sunilvl at ventanamicro.com>
---
 drivers/acpi/riscv/irq.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
index cd83c3035cf6..75170151c614 100644
--- a/drivers/acpi/riscv/irq.c
+++ b/drivers/acpi/riscv/irq.c
@@ -339,7 +339,9 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
 	entry = buffer.pointer;
 	while (entry && (entry->length > 0)) {
 		if (entry->source[0]) {
-			acpi_get_handle(handle, entry->source, &link_handle);
+			status = acpi_get_handle(handle, entry->source, &link_handle);
+			if (ACPI_FAILURE(status))
+				continue;
 			dep_devices.count = 1;
 			dep_devices.handles = kzalloc_objs(*dep_devices.handles,
 							   1);

-- 
2.54.0



From lpieralisi at kernel.org  Wed Jun  3 01:20:59 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Wed, 03 Jun 2026 10:20:59 +0200
Subject: [PATCH v2 3/6] ACPI: RISC-V: Fix riscv_acpi_add_prt_dep() loop
 handling
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
Message-ID: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-3-23ffa16b6ebb@kernel.org>

The loop in riscv_acpi_add_prt_dep() includes error conditions that are
handled in a dubious - if not outright wrong - way, by continuining the
loop (which skips and misses the entry pointer update to point to the next
entry).

Rewrite the loop as a for loop (that handles the continuation correctly)
and wrap the condition and update statements using helper functions to make
it cleaner.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: "Rafael J. Wysocki" <rafael at kernel.org>
Cc: Sunil V L <sunilvl at ventanamicro.com>
---
 drivers/acpi/riscv/irq.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
index 75170151c614..0cdec5dd575e 100644
--- a/drivers/acpi/riscv/irq.c
+++ b/drivers/acpi/riscv/irq.c
@@ -319,6 +319,20 @@ static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_h
 	return ctx.rc;
 }
 
+static bool acpi_prt_entry_valid(void *prt_entry)
+{
+	struct acpi_pci_routing_table *entry = prt_entry;
+
+	return entry && entry->length > 0;
+}
+
+static void *acpi_prt_next_entry(void *prt_entry)
+{
+	struct acpi_pci_routing_table *entry = prt_entry;
+
+	return prt_entry + entry->length;
+}
+
 static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
 {
 	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
@@ -337,7 +351,7 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
 	}
 
 	entry = buffer.pointer;
-	while (entry && (entry->length > 0)) {
+	for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) {
 		if (entry->source[0]) {
 			status = acpi_get_handle(handle, entry->source, &link_handle);
 			if (ACPI_FAILURE(status))
@@ -365,9 +379,6 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
 			dep_devices.handles[0] = gsi_handle;
 			count += acpi_scan_add_dep(handle, &dep_devices);
 		}
-
-		entry = (struct acpi_pci_routing_table *)
-			((unsigned long)entry + entry->length);
 	}
 
 	kfree(buffer.pointer);

-- 
2.54.0



From lpieralisi at kernel.org  Wed Jun  3 01:21:00 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Wed, 03 Jun 2026 10:21:00 +0200
Subject: [PATCH v2 4/6] ACPI: irq: Move RISC-V interrupt controllers
 autodep to ACPI IRQ code
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
Message-ID: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-4-23ffa16b6ebb@kernel.org>

RISC-V implements arch code to detect probe dependencies for devices and
the interrupt controller the devices GSIs are routed to.

The code itself is arch agnostic apart from an arch specific helper
function required to retrieve the acpi_handle of the interrupt controller
that manages the device GSI interrupt.

In order to enable IRQ probe dependencies detection on other architectures,
move RISC-V IRQ probe dependency detection code to generic ACPI IRQ code.

Allow interrupt controller drivers to register an arch specific function to
determine the acpi_handle for a specific GSI number to use the mechanism if
needed by the respective interrupt controller drivers.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Huacai Chen <chenhuacai at kernel.org>
Cc: Thomas Gleixner <tglx at kernel.org>
Cc: Anup Patel <anup at brainfault.org>
Cc: "Rafael J. Wysocki" <rafael at kernel.org>
Cc: Sunil V L <sunilvl at ventanamicro.com>
Cc: Marc Zyngier <maz at kernel.org>
---
 arch/riscv/include/asm/acpi.h       |   1 +
 drivers/acpi/irq.c                  | 172 +++++++++++++++++++++++++++++++++++-
 drivers/acpi/riscv/irq.c            | 156 +-------------------------------
 drivers/irqchip/irq-gic-v3.c        |   2 +-
 drivers/irqchip/irq-gic-v5.c        |   2 +-
 drivers/irqchip/irq-gic.c           |   2 +-
 drivers/irqchip/irq-loongarch-cpu.c |   2 +-
 drivers/irqchip/irq-riscv-intc.c    |   3 +-
 include/linux/acpi.h                |   5 +-
 9 files changed, 181 insertions(+), 164 deletions(-)

diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index 26ab37c171bc..f598520ac903 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -67,6 +67,7 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
 
 void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
 			     u32 *cboz_size, u32 *cbop_size);
+acpi_handle acpi_get_riscv_gsi_handle(u32 gsi);
 #else
 static inline void acpi_init_rintc_map(void) { }
 static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
diff --git a/drivers/acpi/irq.c b/drivers/acpi/irq.c
index d1595156c86a..e4293458bf61 100644
--- a/drivers/acpi/irq.c
+++ b/drivers/acpi/irq.c
@@ -13,6 +13,7 @@
 enum acpi_irq_model_id acpi_irq_model;
 
 static acpi_gsi_domain_disp_fn acpi_get_gsi_domain_id;
+static acpi_gsi_handle_disp_fn acpi_get_gsi_handle;
 static u32 (*acpi_gsi_to_irq_fallback)(u32 gsi);
 
 /**
@@ -321,15 +322,19 @@ const struct cpumask *acpi_irq_get_affinity(acpi_handle handle,
 
 /**
  * acpi_set_irq_model - Setup the GSI irqdomain information
- * @model: the value assigned to acpi_irq_model
- * @fn: a dispatcher function that will return the domain fwnode
- *	for a given GSI
+ * @model:	the value assigned to acpi_irq_model
+ * @fn:		a dispatcher function that will return the domain fwnode
+ *		for a given GSI
+ * @gsi_dep_fn: a function to retrieve the acpi_handle a GSI interrupt is
+ *		dependent on
+ *
  */
 void __init acpi_set_irq_model(enum acpi_irq_model_id model,
-			       acpi_gsi_domain_disp_fn fn)
+			       acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn)
 {
 	acpi_irq_model = model;
 	acpi_get_gsi_domain_id = fn;
+	acpi_get_gsi_handle = gsi_dep_fn;
 }
 
 /*
@@ -385,3 +390,162 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
 					   host_data);
 }
 EXPORT_SYMBOL_GPL(acpi_irq_create_hierarchy);
+
+struct acpi_irq_dep_ctx {
+	int		rc;
+	unsigned int	index;
+	acpi_handle	handle;
+};
+
+static acpi_status acpi_irq_get_parent(struct acpi_resource *ares, void *context)
+{
+	struct acpi_irq_dep_ctx *ctx = context;
+	struct acpi_resource_irq *irq;
+	struct acpi_resource_extended_irq *eirq;
+
+	switch (ares->type) {
+	case ACPI_RESOURCE_TYPE_IRQ:
+		irq = &ares->data.irq;
+		if (ctx->index >= irq->interrupt_count) {
+			ctx->index -= irq->interrupt_count;
+			return AE_OK;
+		}
+		ctx->handle = acpi_get_gsi_handle(irq->interrupts[ctx->index]);
+		ctx->rc = 0;
+		return AE_CTRL_TERMINATE;
+	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+		eirq = &ares->data.extended_irq;
+		if (eirq->producer_consumer == ACPI_PRODUCER)
+			return AE_OK;
+
+		if (ctx->index >= eirq->interrupt_count) {
+			ctx->index -= eirq->interrupt_count;
+			return AE_OK;
+		}
+
+		/* Support GSIs only */
+		if (eirq->resource_source.string_length)
+			return AE_OK;
+
+		ctx->handle = acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
+		ctx->rc = 0;
+		return AE_CTRL_TERMINATE;
+	}
+
+	return AE_OK;
+}
+
+static int acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)
+{
+	struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};
+
+	if (!gsi_handle)
+		return -EINVAL;
+
+	acpi_walk_resources(handle, METHOD_NAME__CRS, acpi_irq_get_parent, &ctx);
+	*gsi_handle = ctx.handle;
+
+	return ctx.rc;
+}
+
+static bool acpi_prt_entry_valid(void *prt_entry)
+{
+	struct acpi_pci_routing_table *entry = prt_entry;
+
+	return entry && entry->length > 0;
+}
+
+static void *acpi_prt_next_entry(void *prt_entry)
+{
+	struct acpi_pci_routing_table *entry = prt_entry;
+
+	return prt_entry + entry->length;
+}
+
+static u32 acpi_add_prt_dep(acpi_handle handle)
+{
+	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+	struct acpi_pci_routing_table *entry;
+	struct acpi_handle_list dep_devices;
+	acpi_handle gsi_handle;
+	acpi_handle link_handle;
+	acpi_status status;
+	u32 count = 0;
+
+	status = acpi_get_irq_routing_table(handle, &buffer);
+	if (ACPI_FAILURE(status)) {
+		acpi_handle_err(handle, "failed to get IRQ routing table\n");
+		kfree(buffer.pointer);
+		return 0;
+	}
+
+	entry = buffer.pointer;
+	for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) {
+		if (entry->source[0]) {
+			status = acpi_get_handle(handle, entry->source, &link_handle);
+			if (ACPI_FAILURE(status))
+				continue;
+			dep_devices.count = 1;
+			dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+			if (!dep_devices.handles) {
+				acpi_handle_err(handle, "failed to allocate memory\n");
+				continue;
+			}
+
+			dep_devices.handles[0] = link_handle;
+			count += acpi_scan_add_dep(handle, &dep_devices);
+		} else {
+			gsi_handle = acpi_get_gsi_handle(entry->source_index);
+			if (!gsi_handle)
+				continue;
+			dep_devices.count = 1;
+			dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+			if (!dep_devices.handles) {
+				acpi_handle_err(handle, "failed to allocate memory\n");
+				continue;
+			}
+
+			dep_devices.handles[0] = gsi_handle;
+			count += acpi_scan_add_dep(handle, &dep_devices);
+		}
+	}
+
+	kfree(buffer.pointer);
+	return count;
+}
+
+static u32 acpi_add_irq_dep(acpi_handle handle)
+{
+	struct acpi_handle_list dep_devices;
+	acpi_handle gsi_handle;
+	u32 count = 0;
+	int i;
+
+	for (i = 0; !acpi_irq_get_dep(handle, i, &gsi_handle); i++) {
+		if (!gsi_handle)
+			continue;
+
+		dep_devices.count = 1;
+		dep_devices.handles = kcalloc(1, sizeof(*dep_devices.handles), GFP_KERNEL);
+		if (!dep_devices.handles) {
+			acpi_handle_err(handle, "failed to allocate memory\n");
+			continue;
+		}
+
+		dep_devices.handles[0] = gsi_handle;
+		count += acpi_scan_add_dep(handle, &dep_devices);
+	}
+
+	return count;
+}
+
+u32 acpi_irq_add_auto_dep(acpi_handle handle)
+{
+	if (!acpi_get_gsi_handle)
+		return 0;
+
+	if (acpi_has_method(handle, "_PRT"))
+		return acpi_add_prt_dep(handle);
+
+	return acpi_add_irq_dep(handle);
+}
diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
index 0cdec5dd575e..da2c42e0ebfd 100644
--- a/drivers/acpi/riscv/irq.c
+++ b/drivers/acpi/riscv/irq.c
@@ -23,12 +23,6 @@ struct riscv_ext_intc_list {
 	struct list_head	list;
 };
 
-struct acpi_irq_dep_ctx {
-	int		rc;
-	unsigned int	index;
-	acpi_handle	handle;
-};
-
 LIST_HEAD(ext_intc_list);
 
 static int irqchip_cmp_func(const void *in0, const void *in1)
@@ -254,7 +248,7 @@ void __init riscv_acpi_init_gsi_mapping(void)
 	acpi_get_devices("RSCV0006", riscv_acpi_create_gsi_map_smsi, NULL, NULL);
 }
 
-static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
+acpi_handle acpi_get_riscv_gsi_handle(u32 gsi)
 {
 	struct riscv_ext_intc_list *ext_intc_element;
 	struct list_head *i;
@@ -269,153 +263,7 @@ static acpi_handle riscv_acpi_get_gsi_handle(u32 gsi)
 	return NULL;
 }
 
-static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *context)
-{
-	struct acpi_irq_dep_ctx *ctx = context;
-	struct acpi_resource_irq *irq;
-	struct acpi_resource_extended_irq *eirq;
-
-	switch (ares->type) {
-	case ACPI_RESOURCE_TYPE_IRQ:
-		irq = &ares->data.irq;
-		if (ctx->index >= irq->interrupt_count) {
-			ctx->index -= irq->interrupt_count;
-			return AE_OK;
-		}
-		ctx->handle = riscv_acpi_get_gsi_handle(irq->interrupts[ctx->index]);
-		return AE_CTRL_TERMINATE;
-	case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
-		eirq = &ares->data.extended_irq;
-		if (eirq->producer_consumer == ACPI_PRODUCER)
-			return AE_OK;
-
-		if (ctx->index >= eirq->interrupt_count) {
-			ctx->index -= eirq->interrupt_count;
-			return AE_OK;
-		}
-
-		/* Support GSIs only */
-		if (eirq->resource_source.string_length)
-			return AE_OK;
-
-		ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
-		ctx->rc = 0;
-		return AE_CTRL_TERMINATE;
-	}
-
-	return AE_OK;
-}
-
-static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_handle *gsi_handle)
-{
-	struct acpi_irq_dep_ctx ctx = {-EINVAL, index, NULL};
-
-	if (!gsi_handle)
-		return 0;
-
-	acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
-	*gsi_handle = ctx.handle;
-
-	return ctx.rc;
-}
-
-static bool acpi_prt_entry_valid(void *prt_entry)
-{
-	struct acpi_pci_routing_table *entry = prt_entry;
-
-	return entry && entry->length > 0;
-}
-
-static void *acpi_prt_next_entry(void *prt_entry)
-{
-	struct acpi_pci_routing_table *entry = prt_entry;
-
-	return prt_entry + entry->length;
-}
-
-static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
-{
-	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-	struct acpi_pci_routing_table *entry;
-	struct acpi_handle_list dep_devices;
-	acpi_handle gsi_handle;
-	acpi_handle link_handle;
-	acpi_status status;
-	u32 count = 0;
-
-	status = acpi_get_irq_routing_table(handle, &buffer);
-	if (ACPI_FAILURE(status)) {
-		acpi_handle_err(handle, "failed to get IRQ routing table\n");
-		kfree(buffer.pointer);
-		return 0;
-	}
-
-	entry = buffer.pointer;
-	for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) {
-		if (entry->source[0]) {
-			status = acpi_get_handle(handle, entry->source, &link_handle);
-			if (ACPI_FAILURE(status))
-				continue;
-			dep_devices.count = 1;
-			dep_devices.handles = kzalloc_objs(*dep_devices.handles,
-							   1);
-			if (!dep_devices.handles) {
-				acpi_handle_err(handle, "failed to allocate memory\n");
-				continue;
-			}
-
-			dep_devices.handles[0] = link_handle;
-			count += acpi_scan_add_dep(handle, &dep_devices);
-		} else {
-			gsi_handle = riscv_acpi_get_gsi_handle(entry->source_index);
-			dep_devices.count = 1;
-			dep_devices.handles = kzalloc_objs(*dep_devices.handles,
-							   1);
-			if (!dep_devices.handles) {
-				acpi_handle_err(handle, "failed to allocate memory\n");
-				continue;
-			}
-
-			dep_devices.handles[0] = gsi_handle;
-			count += acpi_scan_add_dep(handle, &dep_devices);
-		}
-	}
-
-	kfree(buffer.pointer);
-	return count;
-}
-
-static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
-{
-	struct acpi_handle_list dep_devices;
-	acpi_handle gsi_handle;
-	u32 count = 0;
-	int i;
-
-	for (i = 0;
-	     !riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
-	     i++) {
-		if (!gsi_handle)
-			continue;
-
-		dep_devices.count = 1;
-		dep_devices.handles = kzalloc_objs(*dep_devices.handles, 1);
-		if (!dep_devices.handles) {
-			acpi_handle_err(handle, "failed to allocate memory\n");
-			continue;
-		}
-
-		dep_devices.handles[0] = gsi_handle;
-		count += acpi_scan_add_dep(handle, &dep_devices);
-	}
-
-	return count;
-}
-
 u32 arch_acpi_add_auto_dep(acpi_handle handle)
 {
-	if (acpi_has_method(handle, "_PRT"))
-		return riscv_acpi_add_prt_dep(handle);
-
-	return riscv_acpi_add_irq_dep(handle);
+	return acpi_irq_add_auto_dep(handle);
 }
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 99444a1b2ffa..2673954d4577 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -2588,7 +2588,7 @@ gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
 	if (err)
 		goto out_fwhandle_free;
 
-	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id);
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v3_get_gsi_domain_id, NULL);
 
 	if (static_branch_likely(&supports_deactivate_key))
 		gic_acpi_setup_kvm_info();
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index 6b0903be8ebf..03cc2830b260 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -1242,7 +1242,7 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
 	if (ret)
 		goto out_irs;
 
-	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id);
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id, NULL);
 
 	return 0;
 
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index ec70c84e9f91..f6bc29f515fb 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1690,7 +1690,7 @@ static int __init gic_v2_acpi_init(union acpi_subtable_headers *header,
 		return ret;
 	}
 
-	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id);
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC, gic_v2_get_gsi_domain_id, NULL);
 
 	if (IS_ENABLED(CONFIG_ARM_GIC_V2M))
 		gicv2m_init(NULL, gic_data[0].domain);
diff --git a/drivers/irqchip/irq-loongarch-cpu.c b/drivers/irqchip/irq-loongarch-cpu.c
index 950bc087e388..84ce24889488 100644
--- a/drivers/irqchip/irq-loongarch-cpu.c
+++ b/drivers/irqchip/irq-loongarch-cpu.c
@@ -168,7 +168,7 @@ static int __init cpuintc_acpi_init(union acpi_subtable_headers *header,
 		panic("Failed to add irqdomain for LoongArch CPU");
 
 	set_handle_irq(&handle_cpu_irq);
-	acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id);
+	acpi_set_irq_model(ACPI_IRQ_MODEL_LPIC, lpic_get_gsi_domain_id, NULL);
 	acpi_set_gsi_to_irq_fallback(lpic_gsi_to_irq);
 	ret = acpi_cascade_irqdomain_init();
 
diff --git a/drivers/irqchip/irq-riscv-intc.c b/drivers/irqchip/irq-riscv-intc.c
index 84418dbd5a27..0595144116e2 100644
--- a/drivers/irqchip/irq-riscv-intc.c
+++ b/drivers/irqchip/irq-riscv-intc.c
@@ -384,7 +384,8 @@ static int __init riscv_intc_acpi_init(union acpi_subtable_headers *header,
 	if (rc)
 		irq_domain_free_fwnode(fn);
 	else
-		acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id);
+		acpi_set_irq_model(ACPI_IRQ_MODEL_RINTC, riscv_acpi_get_gsi_domain_id,
+				   acpi_get_riscv_gsi_handle);
 
 	return rc;
 }
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 67effb91fa98..468fc6a54651 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -360,9 +360,10 @@ int acpi_gsi_to_irq (u32 gsi, unsigned int *irq);
 int acpi_isa_irq_to_gsi (unsigned isa_irq, u32 *gsi);
 
 typedef struct fwnode_handle *(*acpi_gsi_domain_disp_fn)(u32);
+typedef acpi_handle (*acpi_gsi_handle_disp_fn)(u32);
 
 void acpi_set_irq_model(enum acpi_irq_model_id model,
-			acpi_gsi_domain_disp_fn fn);
+			acpi_gsi_domain_disp_fn fn, acpi_gsi_handle_disp_fn gsi_dep_fn);
 acpi_gsi_domain_disp_fn acpi_get_gsi_dispatcher(void);
 void acpi_set_gsi_to_irq_fallback(u32 (*)(u32));
 
@@ -372,6 +373,8 @@ struct irq_domain *acpi_irq_create_hierarchy(unsigned int flags,
 					     const struct irq_domain_ops *ops,
 					     void *host_data);
 
+u32 acpi_irq_add_auto_dep(acpi_handle handle);
+
 #ifdef CONFIG_X86_IO_APIC
 extern int acpi_get_override_irq(u32 gsi, int *trigger, int *polarity);
 #else

-- 
2.54.0



From lpieralisi at kernel.org  Wed Jun  3 01:21:01 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Wed, 03 Jun 2026 10:21:01 +0200
Subject: [PATCH v2 5/6] ACPI/IORT: Implement ACPI infrastructure to enable
 GICv5 IWB probe deferral
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
Message-ID: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-5-23ffa16b6ebb@kernel.org>

Implement an IORT ACPI hook to retrieve the acpi_handle of the interrupt
controller handling a specific GSI (if any, on GICv5 systems only the IWB
is represented in firmware with an ACPI device object) and add the IWB to
the list of devices whose dependencies can be detected (and cleared) in
ACPI core to guarantee that probe dependencies for the IWB can be
satisfied.

Enable autodep detection for arm64 by adding the arch_acpi_add_auto_dep()
callback in the ACPI IORT driver.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Hanjun Guo <guohanjun at huawei.com>
Cc: Sudeep Holla <sudeep.holla at kernel.org>
Cc: "Rafael J. Wysocki" <rafael at kernel.org>
---
 drivers/acpi/arm64/iort.c | 22 +++++++++++++++++++---
 drivers/acpi/scan.c       |  1 +
 include/linux/acpi_iort.h |  3 ++-
 3 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
index af7a9b2fd5bc..34412cd697d8 100644
--- a/drivers/acpi/arm64/iort.c
+++ b/drivers/acpi/arm64/iort.c
@@ -789,11 +789,9 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
 	return irq_find_matching_fwnode(handle, bus_token);
 }
 
-struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
+acpi_handle iort_iwb_handle(u32 iwb_id)
 {
-	struct fwnode_handle *fwnode;
 	struct acpi_iort_node *node;
-	struct acpi_device *device;
 	struct acpi_iort_iwb *iwb;
 	acpi_status status;
 	acpi_handle handle;
@@ -808,6 +806,19 @@ struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
 	if (ACPI_FAILURE(status))
 		return NULL;
 
+	return handle;
+}
+
+struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id)
+{
+	struct fwnode_handle *fwnode;
+	struct acpi_device *device;
+	acpi_handle handle;
+
+	handle = iort_iwb_handle(iwb_id);
+	if (!handle)
+		return NULL;
+
 	device = acpi_get_acpi_dev(handle);
 	if (!device)
 		return NULL;
@@ -2090,6 +2101,11 @@ static void __init iort_init_platform_devices(void)
 	}
 }
 
+u32 arch_acpi_add_auto_dep(acpi_handle handle)
+{
+	return acpi_irq_add_auto_dep(handle);
+}
+
 void __init acpi_iort_init(void)
 {
 	acpi_status status;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 530547cda8b2..ba15da9058dc 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -856,6 +856,7 @@ static const char * const acpi_ignore_dep_ids[] = {
 
 /* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */
 static const char * const acpi_honor_dep_ids[] = {
+	"ARMH0003", /* ARM GICv5 IWB */
 	"INT3472", /* Camera sensor PMIC / clk and regulator info */
 	"INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */
 	"INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */
diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
index 17bb3374f4ca..931eaa7bbf6a 100644
--- a/include/linux/acpi_iort.h
+++ b/include/linux/acpi_iort.h
@@ -27,7 +27,8 @@ int iort_register_domain_token(int trans_id, phys_addr_t base,
 			       struct fwnode_handle *fw_node);
 void iort_deregister_domain_token(int trans_id);
 struct fwnode_handle *iort_find_domain_token(int trans_id);
-struct fwnode_handle *iort_iwb_handle(u32 iwb_id);
+acpi_handle iort_iwb_handle(u32 iwb_id);
+struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id);
 
 #ifdef CONFIG_ACPI_IORT
 u32 iort_msi_map_id(struct device *dev, u32 id);

-- 
2.54.0



From lpieralisi at kernel.org  Wed Jun  3 01:21:02 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Wed, 03 Jun 2026 10:21:02 +0200
Subject: [PATCH v2 6/6] irqchip/gic-v5: Enable GICv5 IWB ACPI probe
 ordering detection
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
Message-ID: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-6-23ffa16b6ebb@kernel.org>

Register an ACPI hook in the ACPI interrupt management code for GICv5 to
retrieve the ACPI interrupt controller handle (if any) of the controller
handling a specific GSI, by updating the acpi_set_irq_model() call with
the gic_v5_get_gsi_handle() function pointer parameter.

gicv5_get_gsi_handle() allows ACPI core to detect the ACPI handle
of the controller that manages a specific GSI interrupt.

Update the IWB driver to clear device dependencies in ACPI core once the
IWB driver has probed.

Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
Cc: Thomas Gleixner <tglx at kernel.org>
Cc: Marc Zyngier <maz at kernel.org>
---
 drivers/irqchip/irq-gic-v5-iwb.c |  5 +++++
 drivers/irqchip/irq-gic-v5.c     | 13 +++++++++++--
 2 files changed, 16 insertions(+), 2 deletions(-)

diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c
index 9103feb70ce8..a02cb9537b15 100644
--- a/drivers/irqchip/irq-gic-v5-iwb.c
+++ b/drivers/irqchip/irq-gic-v5-iwb.c
@@ -269,6 +269,11 @@ static int gicv5_iwb_device_probe(struct platform_device *pdev)
 	if (IS_ERR(iwb_node))
 		return PTR_ERR(iwb_node);
 
+#ifdef CONFIG_ACPI
+	if (has_acpi_companion(&pdev->dev))
+		acpi_dev_clear_dependencies(ACPI_COMPANION(&pdev->dev));
+#endif
+
 	return 0;
 }
 
diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
index 03cc2830b260..26cfaea1af41 100644
--- a/drivers/irqchip/irq-gic-v5.c
+++ b/drivers/irqchip/irq-gic-v5.c
@@ -1217,11 +1217,19 @@ static struct fwnode_handle *gsi_domain_handle;
 static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
 {
 	if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
-		return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
+		return iort_iwb_handle_fwnode(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
 
 	return gsi_domain_handle;
 }
 
+static acpi_handle gic_v5_get_gsi_handle(u32 gsi)
+{
+	if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
+		return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
+
+	return NULL;
+}
+
 static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
 {
 	struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
@@ -1242,7 +1250,8 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
 	if (ret)
 		goto out_irs;
 
-	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id, NULL);
+	acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id,
+			   gic_v5_get_gsi_handle);
 
 	return 0;
 

-- 
2.54.0



From m.szyprowski at samsung.com  Wed Jun  3 01:21:32 2026
From: m.szyprowski at samsung.com (Marek Szyprowski)
Date: Wed,  3 Jun 2026 10:21:32 +0200
Subject: [PATCH] riscv: defconfig: thead: enable PCA953X GPIO driver
References: <CGME20260603082156eucas1p1f44a198f7957d9d82ec0b8bc296fb03c@eucas1p1.samsung.com>
Message-ID: <20260603082132.3200787-1-m.szyprowski@samsung.com>

Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
LicheePi4a board.

Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
---
 arch/riscv/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 08445df56006..a51a423d53f4 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -174,6 +174,8 @@ CONFIG_PINCTRL_SOPHGO_SG2002=y
 CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_SIFIVE=y
 CONFIG_GPIO_SPACEMIT_K1=y
+CONFIG_GPIO_PCA953X=y
+CONFIG_GPIO_PCA953X_IRQ=y
 CONFIG_POWER_RESET_GPIO_RESTART=y
 CONFIG_SENSORS_SFCTEMP=m
 CONFIG_CPU_THERMAL=y
-- 
2.34.1



From m.szyprowski at samsung.com  Wed Jun  3 01:23:32 2026
From: m.szyprowski at samsung.com (Marek Szyprowski)
Date: Wed,  3 Jun 2026 10:23:32 +0200
Subject: [PATCH] riscv: defconfig: spacemit: enable i2c driver for K1 SoC
References: <CGME20260603082338eucas1p2ec88154477479bf0547e5221e0919b07@eucas1p2.samsung.com>
Message-ID: <20260603082332.3200814-1-m.szyprowski@samsung.com>

Enable K1 SoC I2C driver to properly probe PMIC chip on BananaPiF3 board.

Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
---
 arch/riscv/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index c2c37327b987..08445df56006 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -157,6 +157,7 @@ CONFIG_HW_RANDOM_JH7110=m
 CONFIG_I2C=y
 CONFIG_I2C_CHARDEV=m
 CONFIG_I2C_DESIGNWARE_CORE=y
+CONFIG_I2C_K1=y
 CONFIG_I2C_MV64XXX=m
 CONFIG_SPI=y
 CONFIG_SPI_CADENCE_QUADSPI=m
-- 
2.34.1



From p.zabel at pengutronix.de  Wed Jun  3 01:41:15 2026
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Wed, 03 Jun 2026 10:41:15 +0200
Subject: [PATCH v3 04/21] pinctrl: starfive: Add StarFive JHB100 sys0
 controller driver
In-Reply-To: <20260603055347.66845-5-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
	 <20260603055347.66845-5-changhuang.liang@starfivetech.com>
Message-ID: <05c54522ba76bfc4421e6838e8ff108437f69636.camel@pengutronix.de>

On Di, 2026-06-02 at 22:53 -0700, Changhuang Liang wrote:
> Add pinctrl driver for StarFive JHB100 SoC System-0(sys0) pinctrl
> controller.
> 
> Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
> ---
[...]
> diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
> new file mode 100644
> index 000000000000..52b97870b991
> --- /dev/null
> +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
> @@ -0,0 +1,1607 @@
[...]
> +int jhb100_pinctrl_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct gpio_irq_chip *girq;
> +	const struct jhb100_pinctrl_domain_info *info;
> +	struct jhb100_pinctrl *sfp;
> +	struct pinctrl_desc *jhb100_pinctrl_desc;
> +	struct starfive_pinctrl_regs *pinctrl_regs;
> +	struct reset_control *rst;
> +	struct clk *clk;
> +	int ret;
> +	int irq;
> +
> +	info = of_device_get_match_data(&pdev->dev);
> +	if (!info)
> +		return -ENODEV;
> +
> +	pinctrl_regs = info->regs;
> +
> +	sfp = devm_kzalloc(dev, sizeof(*sfp), GFP_KERNEL);
> +	if (!sfp)
> +		return -ENOMEM;
> +
> +	sfp->base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(sfp->base))
> +		return PTR_ERR(sfp->base);
> +
> +	clk = devm_clk_get_optional_enabled(dev, NULL);
> +	if (IS_ERR(clk))
> +		return dev_err_probe(dev, PTR_ERR(clk), "could not get & enable clock\n");
> +
> +	rst = devm_reset_control_array_get_optional_shared(dev);

Why is this shared? Are there multiple pinctrl controllers sharing
reset lines?

> +	if (IS_ERR(rst))
> +		return dev_err_probe(dev, PTR_ERR(rst), "could not get reset control\n");
> +
> +	/*
> +	 * we don't want to assert reset and risk undoing pin muxing for the
> +	 * early boot serial console, but let's make sure the reset line is
> +	 * deasserted in case someone runs a really minimal bootloader.
> +	 */
> +	ret = reset_control_deassert(rst);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "could not deassert reset\n");

Missing reset_control_assert() in .remove will unbalance the
deassertion counter if a pin controller with shared reset is
unbound/rebound, causing the reset to never be asserted again.

regards
Philipp


From conor at kernel.org  Wed Jun  3 02:16:42 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 10:16:42 +0100
Subject: [PATCH 7/7] riscv: dts: tenstorrent: Add Atlantis platform
In-Reply-To: <20260603074222.593243-8-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-8-joel@jms.id.au>
Message-ID: <20260603-selective-labored-f9afc652ac7b@spud>

On Wed, Jun 03, 2026 at 05:12:19PM +0930, Joel Stanley wrote:
> Add initial support for the Tenstorrent Atlantis platform, based on the
> Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.
> 
> The evb machine represents an internal bringup vehicle with just the
> interrupt controllers and a UART. This will be replaced in time with a
> full featured machine once details are available.
> 
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>

Signoff chain here, and elsewhere is not right.
What did Drew do? Are they the author or is there a missing
Co-developed-by?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/c04dbe2b/attachment.sig>

From conor at kernel.org  Wed Jun  3 02:23:06 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 10:23:06 +0100
Subject: [PATCH 4/7] dt-bindings: timer: Add RISC-V ACLINT bindings
In-Reply-To: <20260603074222.593243-5-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-5-joel@jms.id.au>
Message-ID: <20260603-tadpole-slept-8b6eeae9cd47@spud>

On Wed, Jun 03, 2026 at 05:12:16PM +0930, Joel Stanley wrote:
> Document the bindings for the RISC-V ACLINT.
> 
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>
> ---
>  MAINTAINERS                                   |  1 +
>  .../bindings/timer/riscv,aclint-mtimer.yaml   | 52 +++++++++++++++++++
>  2 files changed, 53 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2fb1c75afd16..43dd9873bbc5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23005,6 +23005,7 @@ M:	Joel Stanley <jms at oss.tenstorrent.com>
>  L:	linux-riscv at lists.infradead.org
>  S:	Maintained
>  T:	git https://github.com/tenstorrent/linux.git
> +F:	Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
>  F:	Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
>  F:	Documentation/devicetree/bindings/riscv/tenstorrent.yaml
>  F:	arch/riscv/boot/dts/tenstorrent/
> diff --git a/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> new file mode 100644
> index 000000000000..192ff3fcf79f
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> @@ -0,0 +1,52 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/timer/riscv,aclint-mtimer.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: RISC-V Advanced Core Local Interruptor (ACLINT)
> +
> +maintainers:
> +  - Joel Stanley <jms at oss.tenstorrent.com>
> +
> +description:
> +  This RISC-V ACLINT specification defines a set of memory mapped devices which
> +  provide inter-processor interrupts (IPI) and timer functionalities for each
> +  HART on a multi-HART RISC-V platform. The specification can be found at
> +  https://github.com/riscvarchive/riscv-aclint/

This is a draft specification, so having a "riscv,aclint-mtimer"
compatible is not appropriate. Ordinarily I would say that you should be
able to do this once frozen, but this spec is archived and unlikely to
have that happen.
pw-bot: changes-requested

> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - tenstorrent,atlantis-aclint
> +          - qemu,aclint-mtimer
> +      - const: riscv,aclint-mtimer
> +
> +  reg:
> +    minItems: 1
> +    maxItems: 4095

I don't see why this permits so many regions, the draft spec has two
regions, one for MTIME and one for MTIMECMP0-4094.

> +
> +  interrupts-extended:
> +    minItems: 1
> +    maxItems: 4095
> +
> +required:
> +  - compatible
> +  - reg
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    // Example 1

Delete this comment please.

Thanks,
Conor.

> +
> +    timer at ac000000 {
> +      compatible = "tenstorrent,atlantis-aclint", "riscv,aclint-mtimer";
> +      interrupts-extended = <&cpu1intc 7>,
> +                            <&cpu2intc 7>,
> +                            <&cpu3intc 7>,
> +                            <&cpu4intc 7>;
> +      reg = <0xac000000 0x00010000>;
> +    };
> +...
> -- 
> 2.47.3
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/d87537c6/attachment.sig>

From leitao at debian.org  Wed Jun  3 02:31:54 2026
From: leitao at debian.org (Breno Leitao)
Date: Wed, 3 Jun 2026 02:31:54 -0700
Subject: [PATCH RESEND] riscv: kexec: use min to simplify
 riscv_kexec_elf_load
In-Reply-To: <20260602224725.1088385-3-thorsten.blum@linux.dev>
References: <20260602224725.1088385-3-thorsten.blum@linux.dev>
Message-ID: <ah_0fOD8mNWTKz9f@gmail.com>

On Wed, Jun 03, 2026 at 12:47:22AM +0200, Thorsten Blum wrote:
> Use min() to replace the open-coded version and assign the result
> directly to kbuf.bufsz. Drop the now-unused local size variable.
> 
> Signed-off-by: Thorsten Blum <thorsten.blum at linux.dev>

Reviewed-by: Breno Leitao <leitao at debian.org>


From cp0613 at linux.alibaba.com  Wed Jun  3 02:33:01 2026
From: cp0613 at linux.alibaba.com (Chen Pei)
Date: Wed,  3 Jun 2026 17:33:01 +0800
Subject: [PATCH] riscv: cpufeature: Validate H extension via CSR_HGATP probe
Message-ID: <20260603093301.89430-1-cp0613@linux.alibaba.com>

The H extension is advertised to S-mode through three channels --
the DT "riscv,isa" string, the DT "riscv,isa-extensions" list, and
the ACPI RHCT ISA string -- all of which converge in
riscv_resolve_isa().  The H entry has no validate callback today,
so the kernel trusts the description unconditionally.

When firmware advertises H but the hardware does not actually
implement it (common during early bring-up, e.g. QEMU), kvm.ko
reaches kvm_riscv_gstage_mode_detect() and oopses on the first
CSR_HGATP access with an illegal instruction.

Add a validate callback for H that probes CSR_HGATP under an
exception-table fixup.  If the read traps, the H bit is cleared
during ISA resolution and the rest of the kernel sees H as
unavailable.  Because the probe runs in riscv_resolve_isa(), it
covers all three advertisement sources.

Signed-off-by: Chen Pei <cp0613 at linux.alibaba.com>
---
 arch/riscv/kernel/cpufeature.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index f46aa5602d74..b34dd789e94e 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -17,9 +17,11 @@
 #include <linux/of.h>
 #include <asm/acpi.h>
 #include <asm/alternative.h>
+#include <asm/asm-extable.h>
 #include <asm/bugs.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
+#include <asm/csr.h>
 #include <asm/hwcap.h>
 #include <asm/text-patching.h>
 #include <asm/hwprobe.h>
@@ -163,6 +165,32 @@ static int riscv_ext_d_validate(const struct riscv_isa_ext_data *data,
 	return 0;
 }
 
+static int riscv_ext_h_validate(const struct riscv_isa_ext_data *data,
+				const unsigned long *isa_bitmap)
+{
+	unsigned long val, ret = 1;
+
+	/*
+	 * The H extension may be advertised by firmware (DT/ACPI) even
+	 * when the underlying hardware does not implement it, or when
+	 * M-mode firmware has not delegated hypervisor CSR access to
+	 * S-mode.  Probe CSR_HGATP under an exception-table fixup: if
+	 * the read traps with an illegal instruction, ret stays 1.
+	 */
+	asm volatile(
+		"1:	csrr	%0, " __stringify(CSR_HGATP) "\n"
+		"	li	%1, 0\n"
+		"2:\n"
+		_ASM_EXTABLE(1b, 2b)
+		: "=r" (val), "+r" (ret));
+
+	if (ret) {
+		pr_err("H detected in ISA string, disabling as CSR_HGATP is not accessible\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int riscv_ext_vector_x_validate(const struct riscv_isa_ext_data *data,
 				       const unsigned long *isa_bitmap)
 {
@@ -498,7 +526,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
 	__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate),
-	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
+	__RISCV_ISA_EXT_DATA_VALIDATE(h, RISCV_ISA_EXT_h, riscv_ext_h_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
-- 
2.50.1



From conor at kernel.org  Wed Jun  3 02:51:25 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 10:51:25 +0100
Subject: [PATCH] riscv: cpufeature: Validate H extension via CSR_HGATP
 probe
In-Reply-To: <20260603093301.89430-1-cp0613@linux.alibaba.com>
References: <20260603093301.89430-1-cp0613@linux.alibaba.com>
Message-ID: <20260603-fantasy-stiffen-5df518d9a3f5@spud>

On Wed, Jun 03, 2026 at 05:33:01PM +0800, Chen Pei wrote:
> The H extension is advertised to S-mode through three channels --
> the DT "riscv,isa" string, the DT "riscv,isa-extensions" list, and
> the ACPI RHCT ISA string -- all of which converge in
> riscv_resolve_isa().  The H entry has no validate callback today,
> so the kernel trusts the description unconditionally.
> 
> When firmware advertises H but the hardware does not actually
> implement it (common during early bring-up, e.g. QEMU), kvm.ko
> reaches kvm_riscv_gstage_mode_detect() and oopses on the first
> CSR_HGATP access with an illegal instruction.
> 
> Add a validate callback for H that probes CSR_HGATP under an
> exception-table fixup.  If the read traps, the H bit is cleared
> during ISA resolution and the rest of the kernel sees H as
> unavailable.  Because the probe runs in riscv_resolve_isa(), it
> covers all three advertisement sources.

The point of validate callbacks is twofold: checking that the kernel
configuration supports the extension and that extensions that the kernel
depends on to support the one in question are present.
It is not the kernel's job to check that the devicetree matches the
hardware. I can only assume that ACPI has the same policy. Firmware must
not report supporting extensions that hardware does not actually support.

NAK, fix your firmware instead please.

Thanks,
Conor.


> 
> Signed-off-by: Chen Pei <cp0613 at linux.alibaba.com>
> ---
>  arch/riscv/kernel/cpufeature.c | 30 +++++++++++++++++++++++++++++-
>  1 file changed, 29 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index f46aa5602d74..b34dd789e94e 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -17,9 +17,11 @@
>  #include <linux/of.h>
>  #include <asm/acpi.h>
>  #include <asm/alternative.h>
> +#include <asm/asm-extable.h>
>  #include <asm/bugs.h>
>  #include <asm/cacheflush.h>
>  #include <asm/cpufeature.h>
> +#include <asm/csr.h>
>  #include <asm/hwcap.h>
>  #include <asm/text-patching.h>
>  #include <asm/hwprobe.h>
> @@ -163,6 +165,32 @@ static int riscv_ext_d_validate(const struct riscv_isa_ext_data *data,
>  	return 0;
>  }
>  
> +static int riscv_ext_h_validate(const struct riscv_isa_ext_data *data,
> +				const unsigned long *isa_bitmap)
> +{
> +	unsigned long val, ret = 1;
> +
> +	/*
> +	 * The H extension may be advertised by firmware (DT/ACPI) even
> +	 * when the underlying hardware does not implement it, or when
> +	 * M-mode firmware has not delegated hypervisor CSR access to
> +	 * S-mode.  Probe CSR_HGATP under an exception-table fixup: if
> +	 * the read traps with an illegal instruction, ret stays 1.
> +	 */
> +	asm volatile(
> +		"1:	csrr	%0, " __stringify(CSR_HGATP) "\n"
> +		"	li	%1, 0\n"
> +		"2:\n"
> +		_ASM_EXTABLE(1b, 2b)
> +		: "=r" (val), "+r" (ret));
> +
> +	if (ret) {
> +		pr_err("H detected in ISA string, disabling as CSR_HGATP is not accessible\n");
> +		return -EINVAL;
> +	}
> +	return 0;
> +}
> +
>  static int riscv_ext_vector_x_validate(const struct riscv_isa_ext_data *data,
>  				       const unsigned long *isa_bitmap)
>  {
> @@ -498,7 +526,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
>  	__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
>  	__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts),
>  	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate),
> -	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
> +	__RISCV_ISA_EXT_DATA_VALIDATE(h, RISCV_ISA_EXT_h, riscv_ext_h_validate),
>  	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
>  	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
>  	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
> -- 
> 2.50.1
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/3831fece/attachment.sig>

From wang.yechao255 at zte.com.cn  Wed Jun  3 02:52:56 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Wed, 3 Jun 2026 17:52:56 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIHYyIDAvNF0gSW1wbGVtZW50IEVhZ2VyIFBhZ2UgU3BsaXR0aW5nIGZvciBSSVNDLVY=?=
Message-ID: <20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn>

From: Wang Yechao <wang.yechao255 at zte.com.cn>

Eager Page Splitting is implemented on x86 and ARM. It improves the
performance of dirty logging (used in live migrations) when guest memory
is backed by huge pages.

This series implement Eager Page Splitting for RISC-V. The Implementation
similar to x86 and ARM. It provides two ways to split huge pages in ioctl
context instead of on fault in vCPU context:

- Split huge pages when dirty logging is enabled when
  KVM_DIRTY_LOG_INITIALLY_SET is not set. This happens when enabling the
  KVM_MEM_LOG_DIRTY_PAGES flag of a memslot, and splits the whole memslot
  into 4K mappings.

- Split huge pages during KVM_CLEAR_DIRTY_LOG when
  KVM_DIRTY_LOG_INITIALLY_SET is set. This happens when enabling dirty log
  in small chunks. It does not split the whole memslot, but only the
  requested chunk range.

Changes in v2:
 - Rename the split_page_cache.
 - Rename the kvm_riscv_split_huge_pages and
   kvm_riscv_split_memory_region.
 - Add lockdep_assert_held check before split huge pages.
 - Update Documentation/admin-guide/kernel-parameters.txt.

 - Link to v1:
 https://lore.kernel.org/linux-riscv/20260513153656847l3c4fI5hBsAyoIZi8aGIs at zte.com.cn/

Wang Yechao (4):
  RISC-V: KVM: Add the split page cache for ioctl context
  RISC-V: KVM: Split huge pages when dirty logging is enabled
  RISC-V: KVM: Split huge pages during KVM_CLEAR_DIRTY_LOG
  RISC-V: KVM: Add the eager_page_split module parameter

 .../admin-guide/kernel-parameters.txt         |  7 +-
 arch/riscv/include/asm/kvm_host.h             |  1 +
 arch/riscv/kvm/mmu.c                          | 77 +++++++++++++++++++
 3 files changed, 83 insertions(+), 2 deletions(-)

-- 
2.43.5


From changhuang.liang at starfivetech.com  Wed Jun  3 03:17:36 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Wed, 3 Jun 2026 10:17:36 +0000
Subject: [PATCH v3 04/21] pinctrl: starfive: Add StarFive JHB100 sys0
 controller driver
In-Reply-To: <05c54522ba76bfc4421e6838e8ff108437f69636.camel@pengutronix.de>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
	 <20260603055347.66845-5-changhuang.liang@starfivetech.com>
 <05c54522ba76bfc4421e6838e8ff108437f69636.camel@pengutronix.de>
Message-ID: <ZQ4PR01MB1202C6EADCFEF3BDAE70BC17F2132@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>

Hi, Philipp

Thanks for the review.

> On Di, 2026-06-02 at 22:53 -0700, Changhuang Liang wrote:
> > Add pinctrl driver for StarFive JHB100 SoC System-0(sys0) pinctrl
> > controller.
> >
> > Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> > Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> > Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
> > ---
> [...]
> > diff --git a/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
> > b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
> > new file mode 100644
> > index 000000000000..52b97870b991
> > --- /dev/null
> > +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100.c
> > @@ -0,0 +1,1607 @@
> [...]
> > +int jhb100_pinctrl_probe(struct platform_device *pdev) {
> > +	struct device *dev = &pdev->dev;
> > +	struct gpio_irq_chip *girq;
> > +	const struct jhb100_pinctrl_domain_info *info;
> > +	struct jhb100_pinctrl *sfp;
> > +	struct pinctrl_desc *jhb100_pinctrl_desc;
> > +	struct starfive_pinctrl_regs *pinctrl_regs;
> > +	struct reset_control *rst;
> > +	struct clk *clk;
> > +	int ret;
> > +	int irq;
> > +
> > +	info = of_device_get_match_data(&pdev->dev);
> > +	if (!info)
> > +		return -ENODEV;
> > +
> > +	pinctrl_regs = info->regs;
> > +
> > +	sfp = devm_kzalloc(dev, sizeof(*sfp), GFP_KERNEL);
> > +	if (!sfp)
> > +		return -ENOMEM;
> > +
> > +	sfp->base = devm_platform_ioremap_resource(pdev, 0);
> > +	if (IS_ERR(sfp->base))
> > +		return PTR_ERR(sfp->base);
> > +
> > +	clk = devm_clk_get_optional_enabled(dev, NULL);
> > +	if (IS_ERR(clk))
> > +		return dev_err_probe(dev, PTR_ERR(clk), "could not get & enable
> > +clock\n");
> > +
> > +	rst = devm_reset_control_array_get_optional_shared(dev);
> 
> Why is this shared? Are there multiple pinctrl controllers sharing reset lines?

ADC pinctrl has a requirement for sharing a reset line, which is currently not included 
in this series.

> > +	if (IS_ERR(rst))
> > +		return dev_err_probe(dev, PTR_ERR(rst), "could not get reset
> > +control\n");
> > +
> > +	/*
> > +	 * we don't want to assert reset and risk undoing pin muxing for the
> > +	 * early boot serial console, but let's make sure the reset line is
> > +	 * deasserted in case someone runs a really minimal bootloader.
> > +	 */
> > +	ret = reset_control_deassert(rst);
> > +	if (ret)
> > +		return dev_err_probe(dev, ret, "could not deassert reset\n");
> 
> Missing reset_control_assert() in .remove will unbalance the deassertion
> counter if a pin controller with shared reset is unbound/rebound, causing the
> reset to never be asserted again.

Will fix.

Best Regards,
Changhuang

From qirui.001 at bytedance.com  Wed Jun  3 04:53:27 2026
From: qirui.001 at bytedance.com (Rui Qi)
Date: Wed,  3 Jun 2026 19:53:27 +0800
Subject: [PATCH v1 0/2] riscv: stacktrace: Fix return address handling in non-FP unwinder
Message-ID: <20260603115329.791603-1-qirui.001@bytedance.com>

This 2-patch series fixes how the non-frame-pointer version of
walk_stackframe handles return addresses, addressing both the
unwinder layer and the display layer.

Background
==========

In the original RISC-V stacktrace code (commit 5d8544e2d007), both
the FP and non-FP versions of walk_stackframe subtracted 0x4 from
return addresses read from the stack:

  FP version:      pc = frame->ra - 0x4;
  Non-FP version:  pc = (*ksp++) - 0x4;

The intent was to convert the return address (the instruction after
a call) back to the call site for better symbol resolution. However,
this is incorrect on RISC-V because the RVC (compressed instruction)
extension allows 2-byte instructions (e.g. c.jal). Subtracting a
fixed 0x4 assumes all call instructions are 4 bytes, which produces
a wrong address for compressed calls.

Commit b785ec129bd9 ("riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
support") fixed the FP version by replacing "pc = frame->ra - 0x4"
with ftrace_graph_ret_addr(). The commit message explicitly noted:

  "the original calculation, pc = frame->ra - 4, is buggy when the
   instruction at the return address happened to be a compressed inst."

Later, commit 877425424d6c removed the fallback "#else" branch
entirely since HAVE_FUNCTION_GRAPH_RET_ADDR_PTR is always defined
for RISC-V. However, the non-FP version was simply overlooked and
still carries the bogus -0x4 offset.

Patch 1: Remove -0x4 from the unwinder
=======================================

Remove the -0x4 offset from the non-FP walk_stackframe so it reports
raw return addresses, consistent with the FP version and with other
architectures (ARM64, x86, ARM all report return addresses as-is).

Patch 2: Use %pB for backtrace display
========================================

With the -0x4 removed, a pre-existing issue becomes more visible:
when a noreturn function (e.g. panic, do_exit) is the last call in
a function, the saved return address points to the start of the next
function, and kallsyms resolves it to the wrong symbol.

This is not a new problem -- the FP version has the same issue since
it also does not subtract from return addresses. And it is not
specific to RISC-V; other architectures face it too.

The kernel provides sprint_backtrace() (invoked via %pB) specifically
for this purpose: it subtracts 1 from the address before symbol
lookup, which is sufficient to fall back into the calling function's
range. x86 uses %pB in its printk_stack_address() for this reason.

Replace print_ip_sym() (which uses %pS) with a direct printk using
%pB, matching the pattern used by x86.

Design principle
================

The two patches follow a clear separation of concerns:

  - The unwinder reports raw return addresses (no offset adjustment)
  - The display layer handles symbol resolution adjustments (%pB)

This matches the convention used by other architectures and ensures
consistent behavior between the FP and non-FP unwinders.

Jiakai Xu [1] and Wang Han [2] have separate patch series in flight
for other stacktrace issues; these patches are orthogonal to their
work.

  [1] https://lore.kernel.org/all/20260517143704.659416-1-xujiakai2025 at iscas.ac.cn/
  [2] https://lore.kernel.org/all/20260528082310.1994388-1-wanghan at linux.alibaba.com/

Rui Qi (2):
  riscv: stacktrace: Remove bogus -0x4 offset in non-FP walk_stackframe
  riscv: stacktrace: Use %pB for backtrace display

 arch/riscv/kernel/stacktrace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

-- 
2.20.1


From qirui.001 at bytedance.com  Wed Jun  3 04:53:28 2026
From: qirui.001 at bytedance.com (Rui Qi)
Date: Wed,  3 Jun 2026 19:53:28 +0800
Subject: [PATCH v1 1/2] riscv: stacktrace: Remove bogus -0x4 offset in non-FP walk_stackframe
In-Reply-To: <20260603115329.791603-1-qirui.001@bytedance.com>
References: <20260603115329.791603-1-qirui.001@bytedance.com>
Message-ID: <20260603115329.791603-2-qirui.001@bytedance.com>

In the non-frame-pointer version of walk_stackframe, each value read
from the stack is treated as a potential return address and has 0x4
subtracted before being used as the program counter. This was intended
to convert the return address (the instruction after a call) back to
the call site, but it is incorrect:

1. RISC-V has variable-length instructions due to the RVC (compressed
   instruction) extension. A call instruction can be either 4 bytes
   (regular) or 2 bytes (compressed, e.g. c.jal). Subtracting a fixed
   0x4 assumes all call instructions are 4 bytes, which is wrong for
   compressed instructions.

2. Stack traces conventionally report return addresses, not call sites.
   Other architectures (ARM64, x86, ARM) do not subtract instruction
   size from return addresses in their stack unwinding code.

3. The frame-pointer version of walk_stackframe already dropped the
   -0x4 offset. Commit b785ec129bd9 ("riscv/ftrace: Add
   HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support") replaced "pc =
   frame->ra - 0x4" with ftrace_graph_ret_addr(), and the commit
   message explicitly noted that "the original calculation, pc =
   frame->ra - 4, is buggy when the instruction at the return address
   happened to be a compressed inst." The non-FP version was simply
   overlooked.

Remove the bogus -0x4 offset to match the FP version and the
conventions used by other architectures.

Fixes: 5d8544e2d007 ("RISC-V: Generic library routines and assembly")
Signed-off-by: Rui Qi <qirui.001 at bytedance.com>
---
 arch/riscv/kernel/stacktrace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index 2692d3a06afa..c7555447149b 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -129,7 +129,7 @@ void notrace walk_stackframe(struct task_struct *task,
 	while (!kstack_end(ksp)) {
 		if (__kernel_text_address(pc) && unlikely(!fn(arg, pc)))
 			break;
-		pc = READ_ONCE_NOCHECK(*ksp++) - 0x4;
+		pc = READ_ONCE_NOCHECK(*ksp++);
 	}
 }
 
-- 
2.20.1


From qirui.001 at bytedance.com  Wed Jun  3 04:53:29 2026
From: qirui.001 at bytedance.com (Rui Qi)
Date: Wed,  3 Jun 2026 19:53:29 +0800
Subject: [PATCH v1 2/2] riscv: stacktrace: Use %pB for backtrace display
In-Reply-To: <20260603115329.791603-1-qirui.001@bytedance.com>
References: <20260603115329.791603-1-qirui.001@bytedance.com>
Message-ID: <20260603115329.791603-3-qirui.001@bytedance.com>

The print_trace_address callback uses print_ip_sym which formats
addresses with %pS. This does not adjust the address before symbol
lookup, so when a noreturn function (e.g. panic, do_exit) is the last
call in a function, the saved return address can point to the start of
the next function, and kallsyms resolves it to the wrong symbol.

The kernel provides %pB (sprint_backtrace) specifically for this
purpose: it subtracts 1 from the address before symbol lookup, which
is sufficient to fall back into the calling function range. x86 uses
%pB in its printk_stack_address for the same reason.

Replace print_ip_sym with a direct printk using %pB, matching the
pattern used by x86.

Signed-off-by: Rui Qi <qirui.001 at bytedance.com>
---
 arch/riscv/kernel/stacktrace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index c7555447149b..f4eb65bf53ef 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -139,7 +139,7 @@ static bool print_trace_address(void *arg, unsigned long pc)
 {
 	const char *loglvl = arg;
 
-	print_ip_sym(loglvl, pc);
+	printk("%s[<%px>] %pB\n", loglvl, (void *)pc, (void *)pc);
 	return true;
 }
 
-- 
2.20.1


From qingwei.hu at bytedance.com  Wed Jun  3 05:32:14 2026
From: qingwei.hu at bytedance.com (Qingwei Hu)
Date: Wed, 3 Jun 2026 20:32:14 +0800
Subject: [PATCH v1] riscv: cpufeature: Add Zic64b ISA extension support
In-Reply-To: <20260530-spoils-studied-d0858257c982@spud>
References: <20260528141630.2741710-1-qingwei.hu@bytedance.com>
 <302dfaf7-4a38-408f-997e-68ed27de2341@iscas.ac.cn>
 <752F28EA-9255-4DBE-8007-F57947305D71@bytedance.com>
 <20260530-spoils-studied-d0858257c982@spud>
Message-ID: <68DF4B69-6693-447A-ADAC-E943F96CFB77@bytedance.com>



> On May 31, 2026, at 07:09, Conor Dooley <conor at kernel.org> wrote:
> 
> On Sat, May 30, 2026 at 11:36:11AM +0800, Qingwei Hu wrote:
>> Hi Vivian,
>> 
>> Thanks for the feedback.
>> 
>>> On May 29, 2026, at 11:14, Vivian Wang <wangruikang at iscas.ac.cn> wrote:
>>> 
>>> On 5/28/26 22:16, Qingwei Hu wrote:
>>>> Zic64b describes a platform with 64-byte cache block sizes. It is a
>>>> mandatory part of RVA23U64, but a system may provide 64-byte CMO block
>>>> sizes without satisfying all profile requirements.
>>>> 
>>>> The ISA string parser currently ignores Zic64b because the extension is
>>>> not present in the cpufeature table. Add an ISA extension ID and table
>>>> entry for Zic64b so it can be reported in /proc/cpuinfo when firmware
>>>> advertises it.
>>> 
>>> I'd like to understand: What is the motivation to doing this, given that
>>> the very same information is already available as riscv,cbo*-block-size
>>> and hwprobe?
>> 
>> The motivation here is not to replace riscv,cbo*-block-size or hwprobe.
>> Those are still the right interfaces for software that needs the actual
>> CBO block size.
>> 
>> This is more about preserving the ISA extension name reported by
>> firmware. Some platforms report zic64b in the ISA string, but Linux
>> currently drops it because there is no cpufeature entry, so cpuinfo no
>> longer matches what firmware advertised. That makes profile/ISA-string
>> comparison tools a bit awkward.
>> 
>> So the patch only makes zic64b visible as a named ISA extension when
>> firmware reports it, while still validating it against any CBO block
>> sizes that firmware provides.
>> 
>>> If an extension is what we want to go with, then
>>> Documentation/devicetree/bindings/riscv/extensions.yaml also needs
>>> updating to match.
>> 
>> And yes, if we keep this direction, I agree extensions.yaml should be
>> updated in v2.
> 
> And make sure that having zic64b makes the cbo*-block-size properties
> mandatory so that people don't confuse themselves and omit them and
> wonder why stuff doesn't work.
> 
> Does zic64b mean that all of the zicbo* extensions are supported, or
> does it just mean that the supported ones use 64-byte block sizes?
> The answer to that will impact how you make the cbo*-block-size
> properties mandatory.
> 
> Cheers,
> Conor.

Thanks, I will check this with the RISC-V unprivileged/ISA folks first,
and then handle the binding accordingly in v2.


From anup at brainfault.org  Wed Jun  3 06:12:30 2026
From: anup at brainfault.org (Anup Patel)
Date: Wed, 3 Jun 2026 18:42:30 +0530
Subject: [PATCH 0/5] KVM: riscv: Speed up dirty logging write faults
In-Reply-To: <20260517153427.94889-1-tjytimi@163.com>
References: <20260517153427.94889-1-tjytimi@163.com>
Message-ID: <CAAhSdy3YV9Ny4YA+26SzY_yoFrAB0GWGZQBeg0X90H9Q_GSuHA@mail.gmail.com>

On Sun, May 17, 2026 at 9:05?PM Jinyu Tang <tjytimi at 163.com> wrote:
>
> This series speeds up the common dirty logging write fault path for
> RISC-V KVM.
>
> When dirty logging is enabled, guest writes to write-protected G-stage
> 4K leaves currently go through the full fault path and take mmu_lock for
> write.  That is expensive once the leaf already exists and
> only needs its permission and dirty state updated.
>
> The series first makes the existing MMU notifier locking contract
> explicit, switches RISC-V KVM to KVM's rwlock form of mmu_lock, adds an
> atomic G-stage PTE update helper, uses it for existing permission
> updates, and finally handles dirty logging write faults under the read
> side of mmu_lock when a 4K G-stage leaf is already present.
>
> The locking and concurrency model follows existing KVM patterns from x86
> and arm64: use an rwlock mmu_lock, keep structural page-table changes on
> the write side, and use atomic PTE updates for permission-only changes
> that may race with another vCPU.
>
> The fast path marks the memslot page dirty before making the PTE writable
> again.  It also sets the PTE dirty bit, so systems that trap when D is
> clear do not fall back to the slow path for a writable-but-clean PTE.
>
> Performance was measured with KVM selftests inside a QEMU RISC-V host.
>
>   dirty_log_perf_test -m 19 -v 4 -b 1G -i 3
>     base dirty memory avg, iterations 2-3: 53.262493s
>     patch 1-4 dirty memory avg, iterations 2-3: 52.735675s
>     patch 1-5 dirty memory avg, iterations 2-3: 26.422964s
>     patch 1-5 improvement over base: 50.4%
>
>   dirty_log_perf_test -m 19 -v 4 -b 64M -i 3
>     base dirty memory avg, iterations 2-3: 3.203170s
>     patch 1-5 dirty memory avg, iterations 2-3: 1.762452s
>     improvement: 45.0%
>
> Patch 1-4 are prerequisites for the read-side fast path. The
> main speedup comes from patch 5 avoiding the full fault path
> for dirty logging write faults.
>
> Jinyu Tang (5):
>   KVM: riscv: Rely on common MMU notifier locking
>   KVM: riscv: Use an rwlock for mmu_lock
>   KVM: riscv: Add a G-stage PTE cmpxchg helper
>   KVM: riscv: Update G-stage PTE permissions atomically
>   KVM: riscv: Fast-path dirty logging write faults
>
>  arch/riscv/include/asm/kvm_gstage.h |   4 ++
>  arch/riscv/include/asm/kvm_host.h   |   2 +
>  arch/riscv/kvm/gstage.c             |  35 +++++++---
>  arch/riscv/kvm/mmu.c                | 105 +++++++++++++++++++++++-----
>  4 files changed, 122 insertions(+), 24 deletions(-)
>
> --
> 2.43.0
>

LGTM. I tried this at my end as well.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this series for Linux-7.2

Thanks,
Anup


From conor at kernel.org  Wed Jun  3 06:17:57 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 14:17:57 +0100
Subject: [PATCH v1] riscv: cpufeature: Add Zic64b ISA extension support
In-Reply-To: <68DF4B69-6693-447A-ADAC-E943F96CFB77@bytedance.com>
References: <20260528141630.2741710-1-qingwei.hu@bytedance.com>
 <302dfaf7-4a38-408f-997e-68ed27de2341@iscas.ac.cn>
 <752F28EA-9255-4DBE-8007-F57947305D71@bytedance.com>
 <20260530-spoils-studied-d0858257c982@spud>
 <68DF4B69-6693-447A-ADAC-E943F96CFB77@bytedance.com>
Message-ID: <20260603-scanner-justly-51cd1160460c@spud>

On Wed, Jun 03, 2026 at 08:32:14PM +0800, Qingwei Hu wrote:
> 
> 
> > On May 31, 2026, at 07:09, Conor Dooley <conor at kernel.org> wrote:
> > 
> > On Sat, May 30, 2026 at 11:36:11AM +0800, Qingwei Hu wrote:
> >> Hi Vivian,
> >> 
> >> Thanks for the feedback.
> >> 
> >>> On May 29, 2026, at 11:14, Vivian Wang <wangruikang at iscas.ac.cn> wrote:
> >>> 
> >>> On 5/28/26 22:16, Qingwei Hu wrote:
> >>>> Zic64b describes a platform with 64-byte cache block sizes. It is a
> >>>> mandatory part of RVA23U64, but a system may provide 64-byte CMO block
> >>>> sizes without satisfying all profile requirements.
> >>>> 
> >>>> The ISA string parser currently ignores Zic64b because the extension is
> >>>> not present in the cpufeature table. Add an ISA extension ID and table
> >>>> entry for Zic64b so it can be reported in /proc/cpuinfo when firmware
> >>>> advertises it.
> >>> 
> >>> I'd like to understand: What is the motivation to doing this, given that
> >>> the very same information is already available as riscv,cbo*-block-size
> >>> and hwprobe?
> >> 
> >> The motivation here is not to replace riscv,cbo*-block-size or hwprobe.
> >> Those are still the right interfaces for software that needs the actual
> >> CBO block size.
> >> 
> >> This is more about preserving the ISA extension name reported by
> >> firmware. Some platforms report zic64b in the ISA string, but Linux
> >> currently drops it because there is no cpufeature entry, so cpuinfo no
> >> longer matches what firmware advertised. That makes profile/ISA-string
> >> comparison tools a bit awkward.
> >> 
> >> So the patch only makes zic64b visible as a named ISA extension when
> >> firmware reports it, while still validating it against any CBO block
> >> sizes that firmware provides.
> >> 
> >>> If an extension is what we want to go with, then
> >>> Documentation/devicetree/bindings/riscv/extensions.yaml also needs
> >>> updating to match.
> >> 
> >> And yes, if we keep this direction, I agree extensions.yaml should be
> >> updated in v2.
> > 
> > And make sure that having zic64b makes the cbo*-block-size properties
> > mandatory so that people don't confuse themselves and omit them and
> > wonder why stuff doesn't work.
> > 
> > Does zic64b mean that all of the zicbo* extensions are supported, or
> > does it just mean that the supported ones use 64-byte block sizes?
> > The answer to that will impact how you make the cbo*-block-size
> > properties mandatory.
> > 
> > Cheers,
> > Conor.
> 
> Thanks, I will check this with the RISC-V unprivileged/ISA folks first,
> and then handle the binding accordingly in v2.

I noticed that there's another series that's adding zic64b support:
https://lore.kernel.org/all/20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384 at gmail.com/

Probably you should coordinate with Guodong, as your zic64b effort seems
to predate theirs.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/bb67b06c/attachment.sig>

From conor at kernel.org  Wed Jun  3 06:19:35 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed,  3 Jun 2026 14:19:35 +0100
Subject: [PATCH v2] hwmon: add a driver for the temp/voltage sensor on PolarFire SoC
Message-ID: <20260603-ongoing-brunette-51e35be6d93e@spud>

From: Lars Randers <lranders at mail.dk>

Add a driver for the temperature and voltage sensors on PolarFire SoC.
The temperature reports how hot the die is, and the voltages are the
SoC's 1.05, 1.8 and 2.5 volt rails respectively.

The hardware supports alarms in theory, but there is an erratum that
prevents clearing them once triggered, so no support is added for them.

The hardware measures voltage with 16 bits, of which 1 is a sign bit and
the remainder holds the voltage as a fixed point integer value. It's
improbable that the hardware will work if the voltages are negative, so
the driver ignores the sign bits.

There's no dt support etc here because this is the child of a simple-mfd
syscon.

Signed-off-by: Lars Randers <lranders at mail.dk>
Co-developed-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Conor Dooley <conor.dooley at microchip.com>
---

v2:
- Fix some minor things pointed out by Sashiko including inaccurate
  comments, bounds checking of values read from sysfs and Kconfig
  dependencies.
- Make update_interval use milliseconds instead of microseconds
  (I'll add update_interval_us support when that lands, there's a
  proposed workaround for the erratum circulating internally, so it'll
  probably come alongside alarm support).

CC: Guenter Roeck <linux at roeck-us.net>
CC: Jonathan Corbet <corbet at lwn.net>
CC: Shuah Khan <skhan at linuxfoundation.org>
CC: Conor Dooley <conor.dooley at microchip.com>
CC: Daire McNamara <daire.mcnamara at microchip.com>
CC: linux-hwmon at vger.kernel.org
CC: linux-doc at vger.kernel.org
CC: linux-kernel at vger.kernel.org
CC: linux-riscv at lists.infradead.org
CC: Valentina.FernandezAlanis at microchip.com
---
 Documentation/hwmon/index.rst    |   1 +
 Documentation/hwmon/tvs-mpfs.rst |  53 +++++
 MAINTAINERS                      |   1 +
 drivers/hwmon/Kconfig            |  13 +
 drivers/hwmon/Makefile           |   1 +
 drivers/hwmon/tvs-mpfs.c         | 394 +++++++++++++++++++++++++++++++
 6 files changed, 463 insertions(+)
 create mode 100644 Documentation/hwmon/tvs-mpfs.rst
 create mode 100644 drivers/hwmon/tvs-mpfs.c

diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 8b655e5d6b68..84a5339e1d6f 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -262,6 +262,7 @@ Hardware Monitoring Kernel Drivers
    tps53679
    tps546d24
    tsc1641
+   tvs-mpfs
    twl4030-madc-hwmon
    ucd9000
    ucd9200
diff --git a/Documentation/hwmon/tvs-mpfs.rst b/Documentation/hwmon/tvs-mpfs.rst
new file mode 100644
index 000000000000..ff445844d07c
--- /dev/null
+++ b/Documentation/hwmon/tvs-mpfs.rst
@@ -0,0 +1,53 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver tvs-mpfs
+======================
+
+Supported chips:
+
+  * PolarFire SoC
+
+Authors:
+
+   - Conor Dooley <conor.dooley at microchip.com>
+   - Lars Randers <lranders at mail.dk>
+
+Description
+-----------
+
+This driver implements support for the temperature and voltage sensors on
+PolarFire SoC. The temperature reports how hot the die is, and the voltages are
+the SoC's 1.05, 1.8 and 2.5 volt rails respectively.
+
+
+Usage Notes
+-----------
+
+update_interval has a permitted range of 0 to 8.
+
+Temperatures are read in millidegrees Celsius, but the hardware measures in
+degrees Kelvin, storing the result as 11.4 fixed point data, for a maximum
+value of 2047.9375 degrees Kelvin.
+
+Voltages are read in millivolts. The hardware measures in millivolts, storing
+the value as 12.3 fixed point data, for a maximum of 4095.875 millivolts.
+The minimum value reportable by the driver is 0 volts, although the hardware
+is capable of measuring negative values.
+
+Sysfs entries
+-------------
+
+The following attributes are supported. update_interval is read-write, as are
+the enables. All other attributes are read only.
+
+======================= ====================================================
+temp1_label		Fixed name for channel.
+temp1_input		Measured temperature for channel.
+temp1_enable		Enable/disable for channel.
+
+in[0-2]_label		Fixed name for channel.
+in[0-2]_input		Measured voltage for channel.
+in[0-2]_enable		Enable/disable for channel.
+
+update_interval		The interval at which the chip will update readings.
+======================= ====================================================
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..a492cf5ad0fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22938,6 +22938,7 @@ F:	drivers/char/hw_random/mpfs-rng.c
 F:	drivers/clk/microchip/clk-mpfs*.c
 F:	drivers/firmware/microchip/mpfs-auto-update.c
 F:	drivers/gpio/gpio-mpfs.c
+F:	drivers/hwmon/tvs-mpfs.c
 F:	drivers/i2c/busses/i2c-microchip-corei2c.c
 F:	drivers/mailbox/mailbox-mpfs.c
 F:	drivers/pci/controller/plda/pcie-microchip-host.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 14e4cea48acc..2b9622b1db95 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -930,6 +930,19 @@ config SENSORS_JC42
 	  This driver can also be built as a module. If so, the module
 	  will be called jc42.
 
+config SENSORS_POLARFIRE_SOC_TVS
+	tristate "PolarFire SoC (MPFS) temperature and voltage sensor"
+	depends on POLARFIRE_SOC_SYSCONS || COMPILE_TEST
+	depends on MFD_SYSCON
+	help
+	  This driver adds support for the PolarFire SoC (MPFS) Temperature and
+	  Voltage Sensor.
+
+	  To compile this driver as a module, choose M here. the
+	  module will be called tvs-mpfs.
+
+	  If unsure, say N.
+
 config SENSORS_POWERZ
 	tristate "ChargerLAB POWER-Z USB-C tester"
 	depends on USB
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4788996aa137..b58d249e4cf4 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -194,6 +194,7 @@ obj-$(CONFIG_SENSORS_NZXT_SMART2) += nzxt-smart2.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
+obj-$(CONFIG_SENSORS_POLARFIRE_SOC_TVS)  += tvs-mpfs.o
 obj-$(CONFIG_SENSORS_POWERZ)	+= powerz.o
 obj-$(CONFIG_SENSORS_POWR1220)  += powr1220.o
 obj-$(CONFIG_SENSORS_PT5161L)	+= pt5161l.o
diff --git a/drivers/hwmon/tvs-mpfs.c b/drivers/hwmon/tvs-mpfs.c
new file mode 100644
index 000000000000..f086f178b4ba
--- /dev/null
+++ b/drivers/hwmon/tvs-mpfs.c
@@ -0,0 +1,394 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Author: Lars Randers <lranders at mail.dk>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/freezer.h>
+#include <linux/hwmon.h>
+#include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MPFS_TVS_CTRL 0x08
+#define MPFS_TVS_OUTPUT0 0x24
+#define MPFS_TVS_OUTPUT1 0x28
+
+#define MPFS_TVS_CTRL_TEMP_VALID	BIT(19)
+#define MPFS_TVS_CTRL_V2P5_VALID	BIT(18)
+#define MPFS_TVS_CTRL_V1P8_VALID	BIT(17)
+#define MPFS_TVS_CTRL_V1P05_VALID	BIT(16)
+
+#define MPFS_TVS_CTRL_TEMP_ENABLE	BIT(3)
+#define MPFS_TVS_CTRL_V2P5_ENABLE	BIT(2)
+#define MPFS_TVS_CTRL_V1P8_ENABLE	BIT(1)
+#define MPFS_TVS_CTRL_V1P05_ENABLE	BIT(0)
+#define MPFS_TVS_CTRL_ENABLE_ALL	GENMASK(3, 0)
+
+/*
+ * For all of these the value in millivolts is stored in 16 bits, with an upper
+ * sign bit and a lower 3 bits of decimal. These masks discard the sign bit and
+ * decimal places, because if Linux is running these voltages cannot be negative
+ * and so avoid having to convert to two's complement.
+ */
+#define MPFS_OUTPUT0_V1P8_MASK	GENMASK(30, 19)
+#define MPFS_OUTPUT0_V1P05_MASK	GENMASK(14, 3)
+#define MPFS_OUTPUT1_V2P5_MASK	GENMASK(14, 3)
+
+/*
+ * The register map claims that the temperature is stored in bits 31:16, but
+ * application note "AN4682: PolarFire FPGA Temperature and Voltage Sensor"
+ * says that 31 is reserved. Temperature is in kelvin, so what's probably a
+ * sign bit has no value anyway.
+ */
+#define MPFS_OUTPUT1_TEMP_MASK GENMASK(30, 16)
+
+#define MPFS_TVS_INTERVAL_MASK GENMASK(15, 8)
+#define MPFS_TVS_INTERVAL_OFFSET 8
+/* The interval register is in increments of 32 us */
+#define MPFS_TVS_INTERVAL_SCALE 32
+
+/* 273.1875 in 11.4 fixed-point notation */
+#define MPFS_TVS_K_TO_C 0x1113
+
+enum mpfs_tvs_sensors {
+	SENSOR_V1P05 = 0,
+	SENSOR_V1P8,
+	SENSOR_V2P5,
+};
+
+static const char * const mpfs_tvs_voltage_labels[] = { "1P05", "1P8", "2P5" };
+
+struct mpfs_tvs {
+	struct regmap *regmap;
+};
+
+static int mpfs_tvs_voltage_read(struct mpfs_tvs *data, u32 attr,
+				 int channel, long *val)
+{
+	u32 tmp, control;
+
+	if (attr != hwmon_in_input && attr != hwmon_in_enable)
+		return -EOPNOTSUPP;
+
+	regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
+
+	switch (channel) {
+	case SENSOR_V2P5:
+		if (attr == hwmon_in_enable) {
+			*val = FIELD_GET(MPFS_TVS_CTRL_V2P5_ENABLE, control);
+			break;
+		}
+
+		if (!(control & MPFS_TVS_CTRL_V2P5_VALID))
+			return -EINVAL;
+
+		regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
+		*val = FIELD_GET(MPFS_OUTPUT1_V2P5_MASK, tmp);
+		break;
+	case SENSOR_V1P8:
+		if (attr == hwmon_in_enable) {
+			*val = FIELD_GET(MPFS_TVS_CTRL_V1P8_ENABLE, control);
+			break;
+		}
+
+		if (!(control & MPFS_TVS_CTRL_V1P8_VALID))
+			return -EINVAL;
+
+		regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp);
+		*val = FIELD_GET(MPFS_OUTPUT0_V1P8_MASK, tmp);
+		break;
+	case SENSOR_V1P05:
+		if (attr == hwmon_in_enable) {
+			*val = FIELD_GET(MPFS_TVS_CTRL_V1P05_ENABLE, control);
+			break;
+		}
+
+		if (!(control & MPFS_TVS_CTRL_V1P05_VALID))
+			return -EINVAL;
+
+		regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp);
+		*val = FIELD_GET(MPFS_OUTPUT0_V1P05_MASK, tmp);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int mpfs_tvs_voltage_write(struct mpfs_tvs *data, u32 attr,
+				  int channel, long val)
+{
+	u32 tmp;
+
+	if (attr != hwmon_in_enable)
+		return -EOPNOTSUPP;
+
+	switch (channel) {
+	case SENSOR_V2P5:
+		if (val > 1 || val < 0)
+			return -EINVAL;
+
+		tmp = FIELD_PREP(MPFS_TVS_CTRL_V2P5_ENABLE, val);
+		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+				   MPFS_TVS_CTRL_V2P5_ENABLE, tmp);
+		break;
+	case SENSOR_V1P8:
+		if (val > 1 || val < 0)
+			return -EINVAL;
+
+		tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P8_ENABLE, val);
+		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+				   MPFS_TVS_CTRL_V1P8_ENABLE, tmp);
+		break;
+	case SENSOR_V1P05:
+		if (val > 1 || val < 0)
+			return -EINVAL;
+
+		tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P05_ENABLE, val);
+		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+				   MPFS_TVS_CTRL_V1P05_ENABLE, tmp);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int mpfs_tvs_temp_read(struct mpfs_tvs *data, u32 attr, long *val)
+{
+	u32 tmp, control;
+
+	if (attr != hwmon_temp_input && attr != hwmon_temp_enable)
+		return -EOPNOTSUPP;
+
+	regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
+
+	if (attr == hwmon_temp_enable) {
+		*val = FIELD_GET(MPFS_TVS_CTRL_TEMP_ENABLE, control);
+		return 0;
+	}
+
+	if (!(control & MPFS_TVS_CTRL_TEMP_VALID))
+		return -EINVAL;
+
+	regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
+	*val = FIELD_GET(MPFS_OUTPUT1_TEMP_MASK, tmp);
+	*val -= MPFS_TVS_K_TO_C;
+	*val = (1000 * *val) >> 4; /* fixed point (11.4) to millidegrees */
+
+	return 0;
+}
+
+static int mpfs_tvs_temp_write(struct mpfs_tvs *data, u32 attr, long val)
+{
+	u32 tmp;
+
+	if (attr != hwmon_temp_enable)
+		return -EOPNOTSUPP;
+
+	if (val > 1 || val < 0)
+		return -EINVAL;
+
+	tmp = FIELD_PREP(MPFS_TVS_CTRL_TEMP_ENABLE, val);
+	regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+			   MPFS_TVS_CTRL_TEMP_ENABLE, tmp);
+
+	return 0;
+}
+
+static int mpfs_tvs_interval_read(struct mpfs_tvs *data, u32 attr, long *val)
+{
+	u32 tmp;
+
+	if (attr != hwmon_chip_update_interval)
+		return -EOPNOTSUPP;
+
+	regmap_read(data->regmap, MPFS_TVS_CTRL, &tmp);
+	*val = FIELD_GET(MPFS_TVS_INTERVAL_MASK, tmp);
+	*val *= MPFS_TVS_INTERVAL_SCALE;
+	*val /= 1000;
+
+	return 0;
+}
+
+static int mpfs_tvs_interval_write(struct mpfs_tvs *data, u32 attr, long val)
+{
+	unsigned long temp = val;
+
+	if (attr != hwmon_chip_update_interval)
+		return -EOPNOTSUPP;
+
+	temp *= 1000;
+	temp /= MPFS_TVS_INTERVAL_SCALE;
+
+	/*
+	 * The value is 8 bits wide, but 255 is described as
+	 * "255= Do single set of transfers when scoverride set"
+	 * but there's no scoverride bit in the tvs register region.
+	 * Ban using 255 since its behaviour is suspect.
+	 */
+	if (temp > 254)
+		return -EINVAL;
+
+	temp <<= MPFS_TVS_INTERVAL_OFFSET;
+	regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+			   MPFS_TVS_INTERVAL_MASK, temp);
+
+	return 0;
+}
+
+static umode_t mpfs_tvs_is_visible(const void *data,
+				   enum hwmon_sensor_types type,
+				   u32 attr, int channel)
+{
+	if (type == hwmon_chip && attr == hwmon_chip_update_interval)
+		return 0644;
+
+	if (type == hwmon_temp) {
+		switch (attr) {
+		case hwmon_temp_enable:
+			return 0644;
+		case hwmon_temp_input:
+		case hwmon_temp_label:
+			return 0444;
+		default:
+			return 0;
+		}
+	}
+
+	if (type == hwmon_in) {
+		switch (attr) {
+		case hwmon_in_enable:
+			return 0644;
+		case hwmon_in_input:
+		case hwmon_in_label:
+			return 0444;
+		default:
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int mpfs_tvs_read(struct device *dev, enum hwmon_sensor_types type,
+			 u32 attr, int channel, long *val)
+{
+	struct mpfs_tvs *data = dev_get_drvdata(dev);
+
+	switch (type) {
+	case hwmon_temp:
+		return mpfs_tvs_temp_read(data, attr, val);
+	case hwmon_in:
+		return mpfs_tvs_voltage_read(data, attr, channel, val);
+	case hwmon_chip:
+		return mpfs_tvs_interval_read(data, attr, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int mpfs_tvs_write(struct device *dev, enum hwmon_sensor_types type,
+			  u32 attr, int channel, long val)
+{
+	struct mpfs_tvs *data = dev_get_drvdata(dev);
+
+	switch (type) {
+	case hwmon_temp:
+		return mpfs_tvs_temp_write(data, attr, val);
+	case hwmon_in:
+		return mpfs_tvs_voltage_write(data, attr, channel, val);
+	case hwmon_chip:
+		return mpfs_tvs_interval_write(data, attr, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int mpfs_tvs_read_labels(struct device *dev,
+				enum hwmon_sensor_types type,
+				u32 attr, int channel,
+				const char **str)
+{
+	switch (type) {
+	case hwmon_temp:
+		*str = "Die Temp";
+		return 0;
+	case hwmon_in:
+		*str = mpfs_tvs_voltage_labels[channel];
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static const struct hwmon_ops mpfs_tvs_ops = {
+	.is_visible = mpfs_tvs_is_visible,
+	.read_string = mpfs_tvs_read_labels,
+	.read = mpfs_tvs_read,
+	.write = mpfs_tvs_write,
+};
+
+static const struct hwmon_channel_info *mpfs_tvs_info[] = {
+	HWMON_CHANNEL_INFO(chip,
+			   HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
+	HWMON_CHANNEL_INFO(temp,
+			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_ENABLE),
+	HWMON_CHANNEL_INFO(in,
+			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE,
+			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE,
+			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE),
+	NULL
+};
+
+static const struct hwmon_chip_info mpfs_tvs_chip_info = {
+	.ops = &mpfs_tvs_ops,
+	.info = mpfs_tvs_info,
+};
+
+static int mpfs_tvs_probe(struct platform_device *pdev)
+{
+	struct device *hwmon_dev;
+	struct mpfs_tvs *data;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->regmap = device_node_to_regmap(pdev->dev.parent->of_node);
+	if (IS_ERR(data->regmap))
+		return dev_err_probe(&pdev->dev, PTR_ERR(data->regmap),
+				     "Failed to find syscon regmap\n");
+
+	regmap_write(data->regmap, MPFS_TVS_CTRL, MPFS_TVS_CTRL_ENABLE_ALL);
+
+	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "mpfs_tvs",
+							 data,
+							 &mpfs_tvs_chip_info,
+							 NULL);
+	if (IS_ERR(hwmon_dev))
+		return dev_err_probe(&pdev->dev, PTR_ERR(hwmon_dev),
+				     "hwmon device registration failed.\n");
+
+	return 0;
+}
+
+static struct platform_driver mpfs_tvs_driver = {
+	.probe = mpfs_tvs_probe,
+	.driver = {
+		.name = "mpfs-tvs",
+	},
+};
+module_platform_driver(mpfs_tvs_driver);
+
+MODULE_AUTHOR("Lars Randers <lranders at mail.dk>");
+MODULE_DESCRIPTION("PolarFire SoC temperature & voltage sensor driver");
+MODULE_LICENSE("GPL");
-- 
2.53.0



From dlan at kernel.org  Wed Jun  3 07:47:33 2026
From: dlan at kernel.org (Yixun Lan)
Date: Wed, 3 Jun 2026 14:47:33 +0000
Subject: [PATCH v2] MAINTAINERS: add entry for SpacemiT reset controller
 driver
In-Reply-To: <20260603-b4-spacemit-reset-maintainers-v2-1-db0716d43a7f@gmail.com>
References: <20260603-b4-spacemit-reset-maintainers-v2-1-db0716d43a7f@gmail.com>
Message-ID: <20260603144733-GKB3727415@kernel.org>

Hi Guodong,

On 06:26 Wed 03 Jun     , Guodong Xu wrote:
> Add a MAINTAINERS entry for the SpacemiT reset controller driver
> (drivers/reset/spacemit/) and its reset-ID header. I intend to
> maintain it: the K1 and K3 instances now, and future SpacemiT SoCs
> that reuse the common code.
> 
> Link: https://lore.kernel.org/spacemit/20260120-k3-reset-v3-0-effe87f4bdbe at riscstar.com/
> Acked-by: Alex Elder <elder at riscstar.com>
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>

Looks good

Reviewed-by: Yixun Lan <dlan at kernel.org>
-- 
Yixun Lan (dlan)


From dlan at kernel.org  Wed Jun  3 08:00:13 2026
From: dlan at kernel.org (Yixun Lan)
Date: Wed, 3 Jun 2026 15:00:13 +0000
Subject: [PATCH] riscv: defconfig: spacemit: enable i2c driver for K1 SoC
In-Reply-To: <20260603082332.3200814-1-m.szyprowski@samsung.com>
References: <CGME20260603082338eucas1p2ec88154477479bf0547e5221e0919b07@eucas1p2.samsung.com>
 <20260603082332.3200814-1-m.szyprowski@samsung.com>
Message-ID: <20260603150013-GKC3727415@kernel.org>

Hi Marek,

On 10:23 Wed 03 Jun     , Marek Szyprowski wrote:
> Enable K1 SoC I2C driver to properly probe PMIC chip on BananaPiF3 board.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> ---
>  arch/riscv/configs/defconfig | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
> index c2c37327b987..08445df56006 100644
> --- a/arch/riscv/configs/defconfig
> +++ b/arch/riscv/configs/defconfig
> @@ -157,6 +157,7 @@ CONFIG_HW_RANDOM_JH7110=m
>  CONFIG_I2C=y
>  CONFIG_I2C_CHARDEV=m
>  CONFIG_I2C_DESIGNWARE_CORE=y
> +CONFIG_I2C_K1=y
We've got one patch already which try to solve it in another way..
https://lore.kernel.org/all/20260526-orangepi-sd-card-i2c-v1-1-b92268bfd467 at gmail.com/

-- 
Yixun Lan (dlan)


From conor at kernel.org  Wed Jun  3 08:16:09 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 16:16:09 +0100
Subject: [PATCH v3 01/21] dt-bindings: pincfg-node: Add property
 'input-debounce-ns'
In-Reply-To: <20260603055347.66845-2-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-2-changhuang.liang@starfivetech.com>
Message-ID: <20260603-prevail-stereo-e5c6f56a433a@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/64d1ac8a/attachment.sig>

From wang.yechao255 at zte.com.cn  Wed Jun  3 02:54:39 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Wed, 3 Jun 2026 17:54:39 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIHYyIDEvNF0gUklTQy1WOiBLVk06IEFkZCB0aGUgc3BsaXQgcGFnZSBjYWNoZSBmb3IgaW9jdGwgY29udGV4dA==?=
In-Reply-To: <20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn>
References: 20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn
Message-ID: <20260603175439237VrPTLz6fG79fXRYAu-JFW@zte.com.cn>

From: Wang Yechao <wang.yechao255 at zte.com.cn>

Add the split page cache for dirty logging enablement and the
KVM_CLEAR_DIRTY_LOG ioctl.

Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
---
 arch/riscv/include/asm/kvm_host.h | 1 +
 arch/riscv/kvm/mmu.c              | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 75b0a951c1bc..0ee778f0f086 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -84,6 +84,7 @@ struct kvm_arch {
 	pgd_t *pgd;
 	phys_addr_t pgd_phys;
 	unsigned long pgd_levels;
+	struct kvm_mmu_memory_cache pgd_split_page_cache;

 	/* Guest Timer */
 	struct kvm_guest_timer timer;
diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 2d3def024270..0676937bd9a1 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -549,6 +549,7 @@ int kvm_riscv_mmu_alloc_pgd(struct kvm *kvm)
 	kvm->arch.pgd = page_to_virt(pgd_page);
 	kvm->arch.pgd_phys = page_to_phys(pgd_page);
 	kvm->arch.pgd_levels = kvm_riscv_gstage_max_pgd_levels;
+	kvm->arch.pgd_split_page_cache.gfp_zero = __GFP_ZERO;

 	return 0;
 }
@@ -572,6 +573,8 @@ void kvm_riscv_mmu_free_pgd(struct kvm *kvm)

 	if (pgd)
 		free_pages((unsigned long)pgd, get_order(kvm_riscv_gstage_pgd_size));
+
+	kvm_mmu_free_memory_cache(&kvm->arch.pgd_split_page_cache);
 }

 void kvm_riscv_mmu_update_hgatp(struct kvm_vcpu *vcpu)
-- 
2.43.5


From wang.yechao255 at zte.com.cn  Wed Jun  3 02:57:02 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Wed, 3 Jun 2026 17:57:02 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIHYyIDIvNF0gUklTQy1WOiBLVk06IFNwbGl0IGh1Z2UgcGFnZXMgd2hlbiBkaXJ0eSBsb2dnaW5nIGlzwqBlbmFibGVk?=
In-Reply-To: <20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn>
References: 20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn
Message-ID: <202606031757028642jwiaL-QePBLGAhMW88zw@zte.com.cn>

From: Wang Yechao <wang.yechao255 at zte.com.cn>

Split huge pages eagerly when enabling dirty logging. The goal is to
avoid doing it while faulting on write-protected pages, which
negatively impacts guest performance.

The benefits of eager page splitting are the same as in x86 and arm64,
added with commit a3fe5dbda0a4 ("KVM: x86/mmu: Split huge pages mapped
by the TDP MMU when dirty logging is enabled") and commit e7bf7a490c68
("KVM: arm64: Split huge pages when dirty logging is enabled")

Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
---
 arch/riscv/kvm/mmu.c | 64 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 0676937bd9a1..51bd1db74e1a 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -90,6 +90,52 @@ void kvm_riscv_mmu_iounmap(struct kvm *kvm, gpa_t gpa, unsigned long size)
 	spin_unlock(&kvm->mmu_lock);
 }

+static bool need_topup_split_caches_or_resched(struct kvm_mmu_memory_cache *cache,
+					       int count)
+{
+	if (need_resched())
+		return true;
+
+	return kvm_mmu_memory_cache_nr_free_objects(cache) < count;
+}
+
+/* the caller must held mmu lock */
+static void mmu_split_huge_pages(struct kvm_gstage *gstage,
+				 phys_addr_t start, phys_addr_t end,
+				 bool flush)
+{
+	struct kvm *kvm = gstage->kvm;
+	struct kvm_mmu_memory_cache *pcache = &kvm->arch.pgd_split_page_cache;
+	int count = gstage->pgd_levels;
+	phys_addr_t addr = start;
+	int ret;
+
+	lockdep_assert_held(&kvm->mmu_lock);
+
+	while (addr < end) {
+		if (need_topup_split_caches_or_resched(pcache, count)) {
+			spin_unlock(&kvm->mmu_lock);
+			cond_resched();
+
+			ret = kvm_mmu_topup_memory_cache(pcache, count);
+			if (ret) {
+				kvm_err("Failed to toup split page cache\n");
+				spin_lock(&kvm->mmu_lock);
+				return;
+			}
+			spin_lock(&kvm->mmu_lock);
+		}
+
+		ret = kvm_riscv_gstage_split_huge(gstage, pcache, addr, 0, flush);
+		if (ret != 0) {
+			kvm_err("split huge page for addr(0x%llx) failed %d\n", addr, ret);
+			break;
+		}
+
+		addr += PMD_SIZE;
+	}
+}
+
 void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
 					     struct kvm_memory_slot *slot,
 					     gfn_t gfn_offset,
@@ -136,6 +182,23 @@ void kvm_arch_flush_shadow_memslot(struct kvm *kvm,
 	spin_unlock(&kvm->mmu_lock);
 }

+static void mmu_split_memory_region(struct kvm *kvm, int slot)
+{
+	struct kvm_memslots *slots = kvm_memslots(kvm);
+	struct kvm_memory_slot *memslot = id_to_memslot(slots, slot);
+	phys_addr_t start = memslot->base_gfn << PAGE_SHIFT;
+	phys_addr_t end = (memslot->base_gfn + memslot->npages) << PAGE_SHIFT;
+	struct kvm_gstage gstage;
+
+	kvm_riscv_gstage_init(&gstage, kvm);
+
+	spin_lock(&kvm->mmu_lock);
+	mmu_split_huge_pages(&gstage, start, end, false);
+	spin_unlock(&kvm->mmu_lock);
+
+	kvm_flush_remote_tlbs_memslot(kvm, memslot);
+}
+
 void kvm_arch_commit_memory_region(struct kvm *kvm,
 				struct kvm_memory_slot *old,
 				const struct kvm_memory_slot *new,
@@ -150,6 +213,7 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 		if (kvm_dirty_log_manual_protect_and_init_set(kvm))
 			return;
 		mmu_wp_memory_region(kvm, new->id);
+		mmu_split_memory_region(kvm, new->id);
 	}
 }

-- 
2.43.5


From wang.yechao255 at zte.com.cn  Wed Jun  3 02:58:29 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Wed, 3 Jun 2026 17:58:29 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIHYyIDMvNF0gUklTQy1WOiBLVk06IFNwbGl0IGh1Z2UgcGFnZXMgZHVyaW5nIEtWTV9DTEVBUl9ESVJUWV9MT0c=?=
In-Reply-To: <20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn>
References: 20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn
Message-ID: <20260603175829412hzKDF23RSPIQCliiSiIwg@zte.com.cn>

From: Wang Yechao <wang.yechao255 at zte.com.cn>

Split huge pages on the range specified using KVM_CLEAR_DIRTY_LOG.
And do not split when enabling dirty logging if
KVM_DIRTY_LOG_INITIALLY_SET is set.

Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
Reviewed-by: Anup Patel <anup at brainfault.org>
---
 arch/riscv/kvm/mmu.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 51bd1db74e1a..d04680687f4a 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -149,6 +149,9 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,
 	kvm_riscv_gstage_init(&gstage, kvm);

 	kvm_riscv_gstage_wp_range(&gstage, start, end);
+
+	if (kvm_dirty_log_manual_protect_and_init_set(kvm))
+		mmu_split_huge_pages(&gstage, start, end, true);
 }

 void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
-- 
2.43.5


From wang.yechao255 at zte.com.cn  Wed Jun  3 03:00:11 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Wed, 3 Jun 2026 18:00:11 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIIHYyIDQvNF0gUklTQy1WOiBLVk06IEFkZCB0aGUgZWFnZXJfcGFnZV9zcGxpdCBtb2R1bGUgcGFyYW1ldGVy?=
In-Reply-To: <20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn>
References: 20260603175256408L0jnqGs1cJGc0ijCdujci@zte.com.cn
Message-ID: <202606031800111580inoldUz6HzVPmAbLW2SX@zte.com.cn>

From: Wang Yechao <wang.yechao255 at zte.com.cn>

Add an eager_page_split module parameter for RISC-V KVM, following
the same approach as on x86. This parameter controls whether eager
page splitting is enabled. The default value is on.

When eager page splitting is enabled, KVM proactively splits large
pages (huge pages) into smaller pages when needed for dirty logging
or other operations. Disabling it can be beneficial for VM workloads
that rarely perform writes, or that only write to a small region of
memory, as it allows huge pages to remain intact for read accesses.

Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
---
 Documentation/admin-guide/kernel-parameters.txt |  7 +++++--
 arch/riscv/kvm/mmu.c                            | 13 ++++++++++---
 2 files changed, 15 insertions(+), 5 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..d443b5313b79 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -3059,7 +3059,7 @@ Kernel parameters
 			Default is 0 (don't ignore, but inject #GP)

 	kvm.eager_page_split=
-			[KVM,X86] Controls whether or not KVM will try to
+			[KVM,X86,RISCV] Controls whether or not KVM will try to
 			proactively split all huge pages during dirty logging.
 			Eager page splitting reduces interruptions to vCPU
 			execution by eliminating the write-protection faults
@@ -3079,7 +3079,10 @@ Kernel parameters
 			the KVM_CLEAR_DIRTY ioctl, and only for the pages being
 			cleared.

-			Eager page splitting is only supported when kvm.tdp_mmu=Y.
+			On x86, eager page splitting is only supported when
+			kvm.tdp_mmu=Y.
+
+			On RISCV, eager page splitting is supported by default.

 			Default is Y (on).

diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index d04680687f4a..7a910c5a61fe 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -16,6 +16,9 @@
 #include <asm/kvm_mmu.h>
 #include <asm/kvm_nacl.h>

+bool __read_mostly eager_page_split = true;
+module_param(eager_page_split, bool, 0644);
+
 static void mmu_wp_memory_region(struct kvm *kvm, int slot)
 {
 	struct kvm_memslots *slots = kvm_memslots(kvm);
@@ -150,8 +153,10 @@ void kvm_arch_mmu_enable_log_dirty_pt_masked(struct kvm *kvm,

 	kvm_riscv_gstage_wp_range(&gstage, start, end);

-	if (kvm_dirty_log_manual_protect_and_init_set(kvm))
-		mmu_split_huge_pages(&gstage, start, end, true);
+	if (kvm_dirty_log_manual_protect_and_init_set(kvm)) {
+		if (READ_ONCE(eager_page_split))
+			mmu_split_huge_pages(&gstage, start, end, true);
+	}
 }

 void kvm_arch_sync_dirty_log(struct kvm *kvm, struct kvm_memory_slot *memslot)
@@ -216,7 +221,9 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
 		if (kvm_dirty_log_manual_protect_and_init_set(kvm))
 			return;
 		mmu_wp_memory_region(kvm, new->id);
-		mmu_split_memory_region(kvm, new->id);
+
+		if (READ_ONCE(eager_page_split))
+			mmu_split_memory_region(kvm, new->id);
 	}
 }

-- 
2.43.5


From vijendar.mukunda at amd.com  Wed Jun  3 04:47:59 2026
From: vijendar.mukunda at amd.com (Mukunda,Vijendar)
Date: Wed, 3 Jun 2026 17:17:59 +0530
Subject: [PATCH 10/83] ASoC: amd: use .auto_selectable_formats
In-Reply-To: <87o6i3hqs7.wl-kuninori.morimoto.gx@renesas.com>
References: <8733zfj5jj.wl-kuninori.morimoto.gx@renesas.com>
 <87o6i3hqs7.wl-kuninori.morimoto.gx@renesas.com>
Message-ID: <a997db8a-b018-467f-a4ef-87a108817b1e@amd.com>



On 5/26/26 07:32, Kuninori Morimoto wrote:
> We can use .auto_selectable_formats. Let's adds it.
>
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
Reviewed-by: Vijendar Mukunda <Vijendar.Mukunda at amd.com>
> ---
>   sound/soc/amd/acp/acp-i2s.c       | 6 ++++++
>   sound/soc/amd/raven/acp3x-i2s.c   | 6 ++++++
>   sound/soc/amd/vangogh/acp5x-i2s.c | 6 ++++++
>   3 files changed, 18 insertions(+)
>
> diff --git a/sound/soc/amd/acp/acp-i2s.c b/sound/soc/amd/acp/acp-i2s.c
> index 283a674c7e2c3..bb58a9d34993b 100644
> --- a/sound/soc/amd/acp/acp-i2s.c
> +++ b/sound/soc/amd/acp/acp-i2s.c
> @@ -686,6 +686,10 @@ static int acp_i2s_startup(struct snd_pcm_substream *substream, struct snd_soc_d
>   	return 0;
>   }
>   
> +static const u64 acp_i2s_selectable_formats =
> +	SND_SOC_POSSIBLE_DAIFMT_I2S	|
> +	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
> +
>   const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
>   	.startup	= acp_i2s_startup,
>   	.hw_params	= acp_i2s_hwparams,
> @@ -693,6 +697,8 @@ const struct snd_soc_dai_ops asoc_acp_cpu_dai_ops = {
>   	.trigger	= acp_i2s_trigger,
>   	.set_fmt	= acp_i2s_set_fmt,
>   	.set_tdm_slot	= acp_i2s_set_tdm_slot,
> +	.auto_selectable_formats	= &acp_i2s_selectable_formats,
> +	.num_auto_selectable_formats	= 1,
>   };
>   EXPORT_SYMBOL_NS_GPL(asoc_acp_cpu_dai_ops, "SND_SOC_ACP_COMMON");
>   
> diff --git a/sound/soc/amd/raven/acp3x-i2s.c b/sound/soc/amd/raven/acp3x-i2s.c
> index 352485dd98b14..b0147e88ba54c 100644
> --- a/sound/soc/amd/raven/acp3x-i2s.c
> +++ b/sound/soc/amd/raven/acp3x-i2s.c
> @@ -250,11 +250,17 @@ static int acp3x_i2s_trigger(struct snd_pcm_substream *substream,
>   	return ret;
>   }
>   
> +static const u64 acp3x_i2s_selectable_formats =
> +	SND_SOC_POSSIBLE_DAIFMT_I2S	|
> +	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
> +
>   static const struct snd_soc_dai_ops acp3x_i2s_dai_ops = {
>   	.hw_params = acp3x_i2s_hwparams,
>   	.trigger = acp3x_i2s_trigger,
>   	.set_fmt = acp3x_i2s_set_fmt,
>   	.set_tdm_slot = acp3x_i2s_set_tdm_slot,
> +	.auto_selectable_formats = &acp3x_i2s_selectable_formats,
> +	.num_auto_selectable_formats = 1,
>   };
>   
>   static const struct snd_soc_component_driver acp3x_dai_component = {
> diff --git a/sound/soc/amd/vangogh/acp5x-i2s.c b/sound/soc/amd/vangogh/acp5x-i2s.c
> index bf719f6286174..dbfb87e2fe929 100644
> --- a/sound/soc/amd/vangogh/acp5x-i2s.c
> +++ b/sound/soc/amd/vangogh/acp5x-i2s.c
> @@ -337,11 +337,17 @@ static int acp5x_i2s_trigger(struct snd_pcm_substream *substream,
>   	return ret;
>   }
>   
> +static const u64 acp5x_i2s_selectable_formats =
> +	SND_SOC_POSSIBLE_DAIFMT_I2S	|
> +	SND_SOC_POSSIBLE_DAIFMT_DSP_A;
> +
>   static const struct snd_soc_dai_ops acp5x_i2s_dai_ops = {
>   	.hw_params = acp5x_i2s_hwparams,
>   	.trigger = acp5x_i2s_trigger,
>   	.set_fmt = acp5x_i2s_set_fmt,
>   	.set_tdm_slot = acp5x_i2s_set_tdm_slot,
> +	.auto_selectable_formats = &acp5x_i2s_selectable_formats,
> +	.num_auto_selectable_formats = 1,
>   };
>   
>   static const struct snd_soc_component_driver acp5x_dai_component = {



From herve.codina at bootlin.com  Wed Jun  3 05:09:39 2026
From: herve.codina at bootlin.com (Herve Codina)
Date: Wed, 3 Jun 2026 14:09:39 +0200
Subject: [PATCH 02/83] ASoC: codecs: framer-codec: don't use array if
 single pattarn
In-Reply-To: <87zf1nhqxx.wl-kuninori.morimoto.gx@renesas.com>
References: <8733zfj5jj.wl-kuninori.morimoto.gx@renesas.com>
	<87zf1nhqxx.wl-kuninori.morimoto.gx@renesas.com>
Message-ID: <20260603140939.091f126f@bootlin.com>

Hi Kuninori,

On Tue, 26 May 2026 01:58:50 +0000
Kuninori Morimoto <kuninori.morimoto.gx at renesas.com> wrote:

> Because it is confusable during debugging ASoC FW update, tidyup
> auto format style not to use array if single pattern case.
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
> ---
>  sound/soc/codecs/framer-codec.c | 8 +++-----
>  1 file changed, 3 insertions(+), 5 deletions(-)
> 

Just a typo in the commit title:
s/pattarn/pattern/

Or even
s/pattarn/item/

With that fixed,

Reviewed-by: Herve Codina <herve.codina at bootlin.com>

Best regards,
Herv?


From herve.codina at bootlin.com  Wed Jun  3 05:11:47 2026
From: herve.codina at bootlin.com (Herve Codina)
Date: Wed, 3 Jun 2026 14:11:47 +0200
Subject: [PATCH 03/83] ASoC: codecs: idt821034: don't use array if
 single pattarn
In-Reply-To: <87y0h7hqxo.wl-kuninori.morimoto.gx@renesas.com>
References: <8733zfj5jj.wl-kuninori.morimoto.gx@renesas.com>
	<87y0h7hqxo.wl-kuninori.morimoto.gx@renesas.com>
Message-ID: <20260603141147.61943cf0@bootlin.com>

Hi Kuninori,

On Tue, 26 May 2026 01:58:59 +0000
Kuninori Morimoto <kuninori.morimoto.gx at renesas.com> wrote:

> Because it is confusable during debugging ASoC FW update, tidyup
> auto format style not to use array if single pattern case.
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
> ---
>  sound/soc/codecs/idt821034.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 
> diff --git a/sound/soc/codecs/idt821034.c b/sound/soc/codecs/idt821034.c
> index 39bafefa6a186..084090ccef77a 100644
> --- a/sound/soc/codecs/idt821034.c
> +++ b/sound/soc/codecs/idt821034.c
> @@ -860,18 +860,17 @@ static int idt821034_dai_startup(struct snd_pcm_substream *substream,
>  	return 0;
>  }
>  
> -static const u64 idt821034_dai_formats[] = {
> +static const u64 idt821034_dai_formats =
>  	SND_SOC_POSSIBLE_DAIFMT_DSP_A	|
> -	SND_SOC_POSSIBLE_DAIFMT_DSP_B,
> -};
> +	SND_SOC_POSSIBLE_DAIFMT_DSP_B;
>  
>  static const struct snd_soc_dai_ops idt821034_dai_ops = {
>  	.startup      = idt821034_dai_startup,
>  	.hw_params    = idt821034_dai_hw_params,
>  	.set_tdm_slot = idt821034_dai_set_tdm_slot,
>  	.set_fmt      = idt821034_dai_set_fmt,
> -	.auto_selectable_formats     = idt821034_dai_formats,
> -	.num_auto_selectable_formats = ARRAY_SIZE(idt821034_dai_formats),
> +	.auto_selectable_formats     = &idt821034_dai_formats,
> +	.num_auto_selectable_formats = 1,
>  };
>  
>  static struct snd_soc_dai_driver idt821034_dai_driver = {

Same typo in the commit title as in patch 2:
s/pattarn/pattern/

Or even
s/pattarn/item/

With that fixed,

Reviewed-by: Herve Codina <herve.codina at bootlin.com>

Best regards,
Herv?


From herve.codina at bootlin.com  Wed Jun  3 05:17:57 2026
From: herve.codina at bootlin.com (Herve Codina)
Date: Wed, 3 Jun 2026 14:17:57 +0200
Subject: [PATCH 04/83] ASoC: codecs: peb2466: don't use array if single
 pattarn
In-Reply-To: <87wlwrhqxf.wl-kuninori.morimoto.gx@renesas.com>
References: <8733zfj5jj.wl-kuninori.morimoto.gx@renesas.com>
	<87wlwrhqxf.wl-kuninori.morimoto.gx@renesas.com>
Message-ID: <20260603141757.451cad7b@bootlin.com>

Hi Kuninori,

On Tue, 26 May 2026 01:59:08 +0000
Kuninori Morimoto <kuninori.morimoto.gx at renesas.com> wrote:

> Because it is confusable during debugging ASoC FW update, tidyup
> auto format style not to use array if single pattern case.
> 
> Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
> ---
>  sound/soc/codecs/peb2466.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
> 

Same typo in the commit title as in patch 2:
s/pattarn/pattern/

Or even
s/pattarn/item/

With that fixed,

Reviewed-by: Herve Codina <herve.codina at bootlin.com>

Best regards,
Herv?


From conor at kernel.org  Wed Jun  3 08:18:27 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 16:18:27 +0100
Subject: [PATCH v3 02/21] pinctrl: pinconf-generic: Add property
 'input-debounce-ns'
In-Reply-To: <20260603055347.66845-3-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-3-changhuang.liang@starfivetech.com>
Message-ID: <20260603-sinless-mooing-48a37d3d05ea@spud>

Linus,

On Tue, Jun 02, 2026 at 10:53:28PM -0700, Changhuang Liang wrote:
> Add 'input-debounce-ns' to the generic parameters used for parsing DT
> files, along with the corresponding configuration parameter
> PIN_CONFIG_INPUT_DEBOUNCE_NS. This allows debounce time to be specified
> in nanoseconds as an alternative to the existing 'input-debounce'
> property which uses microseconds
> 
> Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
> ---
>  drivers/pinctrl/pinconf-generic.c       | 2 ++
>  include/linux/pinctrl/pinconf-generic.h | 5 +++++
>  2 files changed, 7 insertions(+)
> 
> diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
> index 64ed28309788..9d67e2d26e28 100644
> --- a/drivers/pinctrl/pinconf-generic.c
> +++ b/drivers/pinctrl/pinconf-generic.c
> @@ -43,6 +43,7 @@ static const struct pin_config_item conf_items[] = {
>  	PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true),
>  	PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH_UA, "output drive strength", "uA", true),
>  	PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true),
> +	PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE_NS, "input debounce", "nsec", true),
>  	PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false),
>  	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false),
>  	PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_UV, "input schmitt threshold", "uV", true),
> @@ -185,6 +186,7 @@ static const struct pinconf_generic_params dt_params[] = {
>  	{ "drive-strength", PIN_CONFIG_DRIVE_STRENGTH, 0 },
>  	{ "drive-strength-microamp", PIN_CONFIG_DRIVE_STRENGTH_UA, 0 },
>  	{ "input-debounce", PIN_CONFIG_INPUT_DEBOUNCE, 0 },
> +	{ "input-debounce-ns", PIN_CONFIG_INPUT_DEBOUNCE_NS, 0 },
>  	{ "input-disable", PIN_CONFIG_INPUT_ENABLE, 0 },
>  	{ "input-enable", PIN_CONFIG_INPUT_ENABLE, 1 },
>  	{ "input-schmitt", PIN_CONFIG_INPUT_SCHMITT, 0 },
> diff --git a/include/linux/pinctrl/pinconf-generic.h b/include/linux/pinctrl/pinconf-generic.h
> index a5d4b2d8633a..1df63c732b99 100644
> --- a/include/linux/pinctrl/pinconf-generic.h
> +++ b/include/linux/pinctrl/pinconf-generic.h
> @@ -71,6 +71,10 @@ struct pinctrl_map;
>   *	which means it will wait for signals to settle when reading inputs. The
>   *	argument gives the debounce time in usecs. Setting the
>   *	argument to zero turns debouncing off.
> + * @PIN_CONFIG_INPUT_DEBOUNCE_NS: this will configure the pin to debounce mode,
> + *	which means it will wait for signals to settle when reading inputs. The
> + *	argument gives the debounce time in nsecs. Setting the
> + *	argument to zero turns debouncing off.
>   * @PIN_CONFIG_INPUT_ENABLE: enable the pin's input.  Note that this does not
>   *	affect the pin's ability to drive output.  1 enables input, 0 disables
>   *	input.
> @@ -143,6 +147,7 @@ enum pin_config_param {
>  	PIN_CONFIG_DRIVE_STRENGTH,
>  	PIN_CONFIG_DRIVE_STRENGTH_UA,
>  	PIN_CONFIG_INPUT_DEBOUNCE,
> +	PIN_CONFIG_INPUT_DEBOUNCE_NS,
>  	PIN_CONFIG_INPUT_ENABLE,
>  	PIN_CONFIG_INPUT_SCHMITT,
>  	PIN_CONFIG_INPUT_SCHMITT_ENABLE,

Should this grow a mutual exclusion check in parse_fw_cfg()?
Part of me says yes for consistency, but also as this is a new property
that's going to have had exclusion in the binding from the start part of
me says that it is unnecessary to add that.


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/f8330382/attachment.sig>

From qingwei.hu at bytedance.com  Wed Jun  3 08:22:39 2026
From: qingwei.hu at bytedance.com (Qingwei Hu)
Date: Wed, 3 Jun 2026 23:22:39 +0800
Subject: [External] [PATCH v1] riscv: cpufeature: Add Zic64b ISA extension
 support
In-Reply-To: <20260603-scanner-justly-51cd1160460c@spud>
References: <20260528141630.2741710-1-qingwei.hu@bytedance.com>
 <302dfaf7-4a38-408f-997e-68ed27de2341@iscas.ac.cn>
 <752F28EA-9255-4DBE-8007-F57947305D71@bytedance.com>
 <20260530-spoils-studied-d0858257c982@spud>
 <68DF4B69-6693-447A-ADAC-E943F96CFB77@bytedance.com>
 <20260603-scanner-justly-51cd1160460c@spud>
Message-ID: <6D41F25C-DF17-4206-A811-A0917E342C91@bytedance.com>



> On Jun 3, 2026, at 21:17, Conor Dooley <conor at kernel.org> wrote:
> 
> On Wed, Jun 03, 2026 at 08:32:14PM +0800, Qingwei Hu wrote:
>> 
>> 
>>> On May 31, 2026, at 07:09, Conor Dooley <conor at kernel.org> wrote:
>>> 
>>> On Sat, May 30, 2026 at 11:36:11AM +0800, Qingwei Hu wrote:
>>>> Hi Vivian,
>>>> 
>>>> Thanks for the feedback.
>>>> 
>>>>> On May 29, 2026, at 11:14, Vivian Wang <wangruikang at iscas.ac.cn> wrote:
>>>>> 
>>>>> On 5/28/26 22:16, Qingwei Hu wrote:
>>>>>> Zic64b describes a platform with 64-byte cache block sizes. It is a
>>>>>> mandatory part of RVA23U64, but a system may provide 64-byte CMO block
>>>>>> sizes without satisfying all profile requirements.
>>>>>> 
>>>>>> The ISA string parser currently ignores Zic64b because the extension is
>>>>>> not present in the cpufeature table. Add an ISA extension ID and table
>>>>>> entry for Zic64b so it can be reported in /proc/cpuinfo when firmware
>>>>>> advertises it.
>>>>> 
>>>>> I'd like to understand: What is the motivation to doing this, given that
>>>>> the very same information is already available as riscv,cbo*-block-size
>>>>> and hwprobe?
>>>> 
>>>> The motivation here is not to replace riscv,cbo*-block-size or hwprobe.
>>>> Those are still the right interfaces for software that needs the actual
>>>> CBO block size.
>>>> 
>>>> This is more about preserving the ISA extension name reported by
>>>> firmware. Some platforms report zic64b in the ISA string, but Linux
>>>> currently drops it because there is no cpufeature entry, so cpuinfo no
>>>> longer matches what firmware advertised. That makes profile/ISA-string
>>>> comparison tools a bit awkward.
>>>> 
>>>> So the patch only makes zic64b visible as a named ISA extension when
>>>> firmware reports it, while still validating it against any CBO block
>>>> sizes that firmware provides.
>>>> 
>>>>> If an extension is what we want to go with, then
>>>>> Documentation/devicetree/bindings/riscv/extensions.yaml also needs
>>>>> updating to match.
>>>> 
>>>> And yes, if we keep this direction, I agree extensions.yaml should be
>>>> updated in v2.
>>> 
>>> And make sure that having zic64b makes the cbo*-block-size properties
>>> mandatory so that people don't confuse themselves and omit them and
>>> wonder why stuff doesn't work.
>>> 
>>> Does zic64b mean that all of the zicbo* extensions are supported, or
>>> does it just mean that the supported ones use 64-byte block sizes?
>>> The answer to that will impact how you make the cbo*-block-size
>>> properties mandatory.
>>> 
>>> Cheers,
>>> Conor.
>> 
>> Thanks, I will check this with the RISC-V unprivileged/ISA folks first,
>> and then handle the binding accordingly in v2.
> 
> I noticed that there's another series that's adding zic64b support:
> https://lore.kernel.org/all/20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384 at gmail.com/
> 
> Probably you should coordinate with Guodong, as your zic64b effort seems
> to predate theirs.

Thanks Conor.

Yes, I noticed Guodong's series as well. I will coordinate with Guodong
before sending v2, and check whether this should be folded into that
work or kept as a small separate patch.

I will also clarify the intended Zic64b/Zicbo* relationship with the
RISC-V unprivileged/ISA folks before updating the binding.

Best regards,
Qingwei Hu




From conor at kernel.org  Wed Jun  3 09:17:15 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 17:17:15 +0100
Subject: [PATCH 5/7] dt-bindings: riscv: add Smrnmi extension description
In-Reply-To: <20260603074222.593243-6-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-6-joel@jms.id.au>
Message-ID: <20260603-deviate-steadier-9ff6a23c5e57@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/d5b1f52c/attachment.sig>

From conor at kernel.org  Wed Jun  3 09:17:41 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 17:17:41 +0100
Subject: [PATCH 6/7] dt-bindings: riscv: Add Tenstorrent Atlantis platform
In-Reply-To: <20260603074222.593243-7-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-7-joel@jms.id.au>
Message-ID: <20260603-enrich-primal-69483cc92b84@spud>

On Wed, Jun 03, 2026 at 05:12:18PM +0930, Joel Stanley wrote:
> Add compatible for the Tenstorrent Atlantis platform.
> 
> Signed-off-by: Joel Stanley <joel at jms.id.au>
> Signed-off-by: Drew Fustini <fustini at kernel.org>

This one has weird signoff stuff.
pw-bot: changes-requested

> ---
>  Documentation/devicetree/bindings/riscv/tenstorrent.yaml | 4 ++++
>  1 file changed, 4 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/riscv/tenstorrent.yaml b/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
> index e15359b2aab6..7fb640e38455 100644
> --- a/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
> +++ b/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
> @@ -22,6 +22,10 @@ properties:
>          items:
>            - const: tenstorrent,blackhole-card
>            - const: tenstorrent,blackhole
> +      - description: Tenstorrent Atlantis
> +        items:
> +          - const: tenstorrent,atlantis-evb
> +          - const: tenstorrent,atlantis
>  
>  additionalProperties: true
>  
> -- 
> 2.47.3
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/a3b26b98/attachment.sig>

From conor at kernel.org  Wed Jun  3 09:18:24 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 17:18:24 +0100
Subject: [PATCH 3/7] dt-bindings: riscv: cpus: Add Tenstorrent Ascalon
In-Reply-To: <20260603074222.593243-4-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-4-joel@jms.id.au>
Message-ID: <20260603-freeload-mammary-a9ffe25027a5@spud>

On Wed, Jun 03, 2026 at 05:12:15PM +0930, Joel Stanley wrote:
> Add Tenstorrent Ascalon microarchitecture and the Tenstorrent Ascalon-XG
> core.
> 
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>

Same here.
pw-bot: changes-requested

> ---
>  Documentation/devicetree/bindings/riscv/cpus.yaml | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
> index 5feeb2203050..2a57bd14569e 100644
> --- a/Documentation/devicetree/bindings/riscv/cpus.yaml
> +++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
> @@ -75,6 +75,11 @@ properties:
>                - sifive,x280
>            - const: sifive,rocket0
>            - const: riscv
> +      - items:
> +          - enum:
> +              - tenstorrent,ascalon-xg
> +          - const: tenstorrent,ascalon
> +          - const: riscv
>        - const: riscv    # Simulator only
>      description:
>        Identifies that the hart uses the RISC-V instruction set
> -- 
> 2.47.3
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/5c17c12d/attachment.sig>

From conor at kernel.org  Wed Jun  3 09:18:44 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 17:18:44 +0100
Subject: [PATCH 2/7] dt-bindings: imsics: Add Tenstorrent Atlantis
 compatible
In-Reply-To: <20260603074222.593243-3-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-3-joel@jms.id.au>
Message-ID: <20260603-dwindle-absence-33c1b4386799@spud>

On Wed, Jun 03, 2026 at 05:12:14PM +0930, Joel Stanley wrote:
> Add compatible for IMSICS in Tenstorrent Atlantis SoC.
> 
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>

And here.
pw-bot: changes-requested

> ---
>  .../devicetree/bindings/interrupt-controller/riscv,imsics.yaml   | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
> index feec122bddde..442b8870f9c5 100644
> --- a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
> +++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
> @@ -49,6 +49,7 @@ properties:
>        - enum:
>            - qemu,imsics
>            - spacemit,k3-imsics
> +          - tenstorrent,atlantis-imsics
>        - const: riscv,imsics
>  
>    reg:
> -- 
> 2.47.3
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/29a08476/attachment.sig>

From conor at kernel.org  Wed Jun  3 09:19:10 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 17:19:10 +0100
Subject: [PATCH 1/7] dt-bindings: aplic: Add Tenstorrent Atlantis
 compatible
In-Reply-To: <20260603074222.593243-2-joel@jms.id.au>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-2-joel@jms.id.au>
Message-ID: <20260603-landed-starting-e9ae05ee5bad@spud>

On Wed, Jun 03, 2026 at 05:12:13PM +0930, Joel Stanley wrote:
> Add compatible for APLIC in Tenstorrent Atlantis SoC.
> 
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>

And here. The contents all look fine of course.
pw-bot: changes-requested

> ---
>  .../devicetree/bindings/interrupt-controller/riscv,aplic.yaml    | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
> index 0718071444d2..d4e17861eda4 100644
> --- a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
> +++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
> @@ -29,6 +29,7 @@ properties:
>        - enum:
>            - qemu,aplic
>            - spacemit,k3-aplic
> +          - tenstorrent,atlantis-aplic
>        - const: riscv,aplic
>  
>    reg:
> -- 
> 2.47.3
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/24b9b4ca/attachment.sig>

From conor at kernel.org  Wed Jun  3 09:43:11 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 3 Jun 2026 17:43:11 +0100
Subject: [PATCH v3 03/21] dt-bindings: pinctrl: Add
 starfive,jhb100-sys0-pinctrl
In-Reply-To: <20260603055347.66845-4-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-4-changhuang.liang@starfivetech.com>
Message-ID: <20260603-groin-valid-a1d4445f7a6b@spud>

On Tue, Jun 02, 2026 at 10:53:29PM -0700, Changhuang Liang wrote:

> +          slew-rate:
> +            enum: [ 0, 1 ]
> +            default: 0
> +            description: |
> +                0: slow (half frequency)

Half frequency? Slew rates are usually measured in volts per second, not
hertz. Do you know what the slew rates actually are and could put them
in here as the real units? Or is it just "slow" and "fast" in your docs
with no precise numbers?

I've got no questions other than this, so once this question is sorted,
I'll be happy to ack all the bindings provided they're effectively the
same.

> +                1: fast
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/a5efebc0/attachment.sig>

From robh at kernel.org  Wed Jun  3 10:44:34 2026
From: robh at kernel.org (Rob Herring)
Date: Wed, 3 Jun 2026 12:44:34 -0500
Subject: [PATCH v3 03/11] of: reserved_mem: avoid post-init UAF when
 alloc_reserved_mem_array() fails
In-Reply-To: <79932afc-2e91-4a54-aff9-f550be784c36@gmail.com>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <20260527032917.3385849-4-chenwandun1@gmail.com> <20260602162450.GA442759-robh@kernel.org>
 <79932afc-2e91-4a54-aff9-f550be784c36@gmail.com>
Message-ID: <CAL_JsqJOC1ko1Len3Dyc5SNKrHmhQn9uiDAkFfVbYa2wAfFUTg@mail.gmail.com>

On Wed, Jun 3, 2026 at 1:44?AM Wandun <chenwandun1 at gmail.com> wrote:
>
>
>
> On 6/3/26 00:24, Rob Herring wrote:
> > On Wed, May 27, 2026 at 11:29:09AM +0800, Wandun Chen wrote:
> >> From: Wandun Chen <chenwandun at lixiang.com>
> >>
> >> The global pointer 'reserved_mem' continues to reference the
> >> reserved_mem_array which lives in __initdata if
> >> alloc_reserved_mem_array() fails. of_reserved_mem_lookup() is
> >> exported for post-init use, that would dereference freed memory
> >> and trigger a use-after-free.
> >>
> >> So reset reserved_mem_count to 0 when alloc_reserved_mem_array()
> >> fails.
> >>
> >> Fixes: 00c9a452a235 ("of: reserved_mem: Add code to dynamically allocate reserved_mem array")
> > Fixes should come first in a series.
> Understood, will do in future submissions.
> >
> >> Signed-off-by: Wandun Chen <chenwandun at lixiang.com>
> >> ---
> >>   drivers/of/of_reserved_mem.c | 20 ++++++++++++++------
> >>   1 file changed, 14 insertions(+), 6 deletions(-)
> >>
> >> diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
> >> index 313cbc57aa45..6d479381ff1f 100644
> >> --- a/drivers/of/of_reserved_mem.c
> >> +++ b/drivers/of/of_reserved_mem.c
> >> @@ -69,29 +69,31 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
> >>    * the initial static array is copied over to this new array and
> >>    * the new array is used from this point on.
> >>    */
> >> -static void __init alloc_reserved_mem_array(void)
> >> +static bool __init alloc_reserved_mem_array(void)
> >>   {
> >>      struct reserved_mem *new_array;
> >>      size_t alloc_size, copy_size, memset_size;
> >>
> >> +    if (!total_reserved_mem_cnt)
> >> +            return true;
> >> +
> >>      alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array));
> >>      if (alloc_size == SIZE_MAX) {
> >>              pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
> >> -            return;
> >> +            goto fail;
> >>      }
> >>
> >>      new_array = memblock_alloc(alloc_size, SMP_CACHE_BYTES);
> >>      if (!new_array) {
> >>              pr_err("Failed to allocate memory for reserved_mem array with err: %d", -ENOMEM);
> >> -            return;
> >> +            goto fail;
> >>      }
> >>
> >>      copy_size = array_size(reserved_mem_count, sizeof(*new_array));
> >>      if (copy_size == SIZE_MAX) {
> >>              memblock_free(new_array, alloc_size);
> >> -            total_reserved_mem_cnt = MAX_RESERVED_REGIONS;
> >>              pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
> > These prints could be moved to 'fail'. Perhaps instead of just printing
> > an error value, you can return the error value instead of boolean.
> Will do, consolidating pr_err() under 'fail' and changing the return type
> to int.
> >
> > If you respin just this patch, I can pick it up for 7.2.
> Before I respin, I'd like to flag a dependency:
> patch 05/07 in this series build on the signature change introduced by this
> patch ("the void -> bool return type change of alloc_reserved_mem_array()")
>
> Could you let me know which of the following you'd prefer:
> a) Take patch 03 alone via your tree as you suggested, after it lands, I'll
>     respin the remaining patches of this series.

I would go with this option. AIUI, this series isn't going to land in
7.2, so ultimately you will rebase on v7.2-rc1 which will have the
fix.

>
> b) Keep patch 03 in the v4 respin of the full series, reordered to the front
>     per your earlier comment.


Rob


From asrinivasan at oss.tenstorrent.com  Wed Jun  3 11:33:48 2026
From: asrinivasan at oss.tenstorrent.com (Anirudh Srinivasan)
Date: Wed, 03 Jun 2026 13:33:48 -0500
Subject: [PATCH] riscv: defconfig: Enable Eswin SoCs
Message-ID: <20260603-eswin_defconfig-v1-1-8471691d3153@oss.tenstorrent.com>

Enable support for Eswin SoCs in the default configuration, so that
defconfig kernel/DTs are bootable on Hifive Premier P550 Board.

Signed-off-by: Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>
---
 arch/riscv/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index c2c37327b9877..74ba5acc12a40 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -24,6 +24,7 @@ CONFIG_BLK_DEV_INITRD=y
 CONFIG_PROFILING=y
 CONFIG_ARCH_ANDES=y
 CONFIG_ARCH_ANLOGIC=y
+CONFIG_ARCH_ESWIN=y
 CONFIG_ARCH_MICROCHIP=y
 CONFIG_ARCH_SIFIVE=y
 CONFIG_ARCH_SOPHGO=y

---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260603-eswin_defconfig-3aeb501af076

Best regards,
--  
Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>



From fustini at kernel.org  Wed Jun  3 12:37:00 2026
From: fustini at kernel.org (Drew Fustini)
Date: Wed, 3 Jun 2026 12:37:00 -0700
Subject: [PATCH 6/7] dt-bindings: riscv: Add Tenstorrent Atlantis platform
In-Reply-To: <20260603-enrich-primal-69483cc92b84@spud>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-7-joel@jms.id.au>
 <20260603-enrich-primal-69483cc92b84@spud>
Message-ID: <aiCCXO0XFfFSdLQB@gen8>

On Wed, Jun 03, 2026 at 05:17:41PM +0100, Conor Dooley wrote:
> On Wed, Jun 03, 2026 at 05:12:18PM +0930, Joel Stanley wrote:
> > Add compatible for the Tenstorrent Atlantis platform.
> > 
> > Signed-off-by: Joel Stanley <joel at jms.id.au>
> > Signed-off-by: Drew Fustini <fustini at kernel.org>
> 
> This one has weird signoff stuff.
> pw-bot: changes-requested

Sorry about that. At one point, I was going to send the series so my SoB
got added. It should be dropped from all of these patches authored by
Joel.

Thanks,
Drew
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260603/43dc9383/attachment.sig>

From fustini at kernel.org  Wed Jun  3 12:39:07 2026
From: fustini at kernel.org (Drew Fustini)
Date: Wed, 3 Jun 2026 12:39:07 -0700
Subject: [PATCH] riscv: defconfig: thead: enable PCA953X GPIO driver
In-Reply-To: <20260603082132.3200787-1-m.szyprowski@samsung.com>
References: <CGME20260603082156eucas1p1f44a198f7957d9d82ec0b8bc296fb03c@eucas1p1.samsung.com>
 <20260603082132.3200787-1-m.szyprowski@samsung.com>
Message-ID: <aiCC21nUsYIp1l3M@gen8>

On Wed, Jun 03, 2026 at 10:21:32AM +0200, Marek Szyprowski wrote:
> Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
> LicheePi4a board.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> ---
>  arch/riscv/configs/defconfig | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
> index 08445df56006..a51a423d53f4 100644
> --- a/arch/riscv/configs/defconfig
> +++ b/arch/riscv/configs/defconfig
> @@ -174,6 +174,8 @@ CONFIG_PINCTRL_SOPHGO_SG2002=y
>  CONFIG_GPIO_DWAPB=y
>  CONFIG_GPIO_SIFIVE=y
>  CONFIG_GPIO_SPACEMIT_K1=y
> +CONFIG_GPIO_PCA953X=y
> +CONFIG_GPIO_PCA953X_IRQ=y
>  CONFIG_POWER_RESET_GPIO_RESTART=y
>  CONFIG_SENSORS_SFCTEMP=m
>  CONFIG_CPU_THERMAL=y
> -- 
> 2.34.1
> 

Reviewed-by: Drew Fustini <fustini at kernel.org>

Paul/Conor: what is the right tree for a arch/riscv/configs/defconfig
patch like this?

Thanks,
Drew


From e at freeshell.de  Wed Jun  3 13:17:56 2026
From: e at freeshell.de (E Shattow)
Date: Wed, 3 Jun 2026 13:17:56 -0700
Subject: [PATCH] dts: riscv: spacemit: k3: Fix I/O power settings
In-Reply-To: <20260518-07-dts-pinctrl-io-power-v1-1-abe19c14a726@kernel.org>
References: <20260518-07-dts-pinctrl-io-power-v1-1-abe19c14a726@kernel.org>
Message-ID: <9585b7c7-100c-4d77-bed1-d2b6b25b3940@freeshell.de>

On 5/18/26 13:58, Yixun Lan wrote:
> SpacemiT K3 SoC support dual-voltage I/O power domain, while initially
> configure to 3.3v, and need to access register from APBC space to switch
> to 1.8v domain.
> 
> Fix the GMAC0's I/O pins 1.8v switch failure that will result a broken
> ethernet driver.
> 
> Fixes: d8944577496b ("riscv: dts: spacemit: k3: add pinctrl support")
> Reported-by: Han Gao <gaohan at iscas.ac.cn>
> Signed-off-by: Yixun Lan <dlan at kernel.org>
> ---
> This issue is reported by Han while booting kernel from UFS storage, and
> found the ethernet driver is broken, we can see the message as below:
> 
>  [    1.635881] mdio_bus stmmac-0: MDIO device at address 1 is missing.
> 
> This problem is caused by GMAC driver that unable to configure I/O power
> domain to 1.8v, which leads to the MDIO communication failure.
> 
> We didn't find this problem due to using tftp(net) to load kernel images
> while bootloader already configured the I/O power.
> ---
>  arch/riscv/boot/dts/spacemit/k3.dtsi | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/riscv/boot/dts/spacemit/k3.dtsi b/arch/riscv/boot/dts/spacemit/k3.dtsi
> index 815debd16409..2b0bf9cd755b 100644
> --- a/arch/riscv/boot/dts/spacemit/k3.dtsi
> +++ b/arch/riscv/boot/dts/spacemit/k3.dtsi
> @@ -803,6 +803,7 @@ pinctrl: pinctrl at d401e000 {
>  			clocks = <&syscon_apbc CLK_APBC_AIB>,
>  				 <&syscon_apbc CLK_APBC_AIB_BUS>;
>  			clock-names = "func", "bus";
> +			spacemit,apbc = <&syscon_apbc>;
>  		};
>  
>  		uart10: serial at d401f000 {
> 
> ---
> base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
> change-id: 20260518-07-dts-pinctrl-io-power-1bd33bfe5894
> 
> Best regards,
> --  
> Yixun Lan <dlan at kernel.org>
> 
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv

Hi Yixun,

This property on its own does not seem to be enough to get the ethernet
network port functional on Sipeed K3 Pico-ITX 32GB model that I have,
when it is loading Debian 13 Trixie debian-installer netinst initramfs
(with cross-compiled Linux kernel and modules from -next 20260602).

Reproducer instructions for cross-compiling and debian-installer netinst
initramfs modification at:
https://wiki.debian.org/InstallingDebianOn/SpacemiT/K3PicoITX?action=recall&rev=2

In addition to those instructions above I am using within the factory
pre-installed vendor U-Boot the following commands to try what your
patch does:

fdt addr $fdt_addr_r
fdt resize
fdt header get filesize totalsize
fdt rm /soc/pinctrl at d401e000 spacemit,apbc
fdt get value spacemit_apbc_phandle /soc/system-controller at d4015000 phandle
fdt set /soc/pinctrl at d401e000 spacemit,apbc <$spacemit_apbc_phandle>

I then verify within Linux environment the presence of
/sys/firmware/devicetree/base/soc/pinctrl at d401e000/spacemit,apbc

The same Linux kernel and modules as modified into the installer then do
have functional ethernet networking on that board if running from the
installed system and with the spacemit,apbc devicetree property. Is this
a dependency or ordering issue of the modules, or the Kconfig options?

Also, the more general problem is that cycling rmmod and modprobe on the
ethernet networking related modules fails:

rmmod dwmac_spacemit
rmmod stmmac_platform
rmmod stmmac
rmmod mdio
modprobe dwmac_spacemit

[ 1487.618517] mdio_bus stmmac-0: MDIO device at address 1 is missing.

[ 1487.623815] spacemit-dwmac cac80000.ethernet end0: renamed from eth0

rmmod dwmac_spacemit
rmmod stmmac_platform
rmmod stmmac
rmmod mdio
modprobe dwmac_spacemit

[ 1539.374486] spacemit-dwmac cac80000.ethernet end0: cannot attach to
PHY (erro
r: -ENODEV)
[ 1615.299451] spacemit-dwmac cac80000.ethernet end0: stmmac_dvr_remove:
removin
g driver

Please advise how to troubleshoot?  Thanks,

- E Shattow


From sebastian.reichel at collabora.com  Wed Jun  3 13:46:59 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Wed, 03 Jun 2026 22:46:59 +0200
Subject: (subset) [PATCH v1 0/6] power: Use named initializers for
 platform_device_id arrays
In-Reply-To: <cover.1780048925.git.u.kleine-koenig@baylibre.com>
References: <cover.1780048925.git.u.kleine-koenig@baylibre.com>
Message-ID: <178051961974.2666348.7125017575893735399.b4-ty@collabora.com>


On Fri, 29 May 2026 12:18:15 +0200, Uwe Kleine-K?nig (The Capable Hub) wrote:
> this series targets to use named initializers for platform_device_id
> arrays. In general these are better readable for humans and more robust
> to changes in the respective struct definition.
> 
> This robustness is needed as I want to do
> 
> 	diff --git a/include/linux/mod_devicetable.h b/include/linux/mod_devicetable.h
> 	--- a/include/linux/mod_devicetable.h
> 	+++ b/include/linux/mod_devicetable.h
> 	@@ -610,4 +610,7 @@ struct dmi_system_id {
> 	 struct platform_device_id {
> 		char name[PLATFORM_NAME_SIZE];
> 	-	kernel_ulong_t driver_data;
> 	+	union {
> 	+		kernel_ulong_t driver_data;
> 	+		const void *driver_data_ptr;
> 	+	};
> 	 };
> 
> [...]

Applied, thanks!

[1/6] power: Drop unused assignment of platform_device_id driver data
      commit: 75a0e1e0b86078687c3c6a05107a98c7e59a65a8
[2/6] power: supply: max14577: Drop driver data in of and platform device id arrays
      commit: 37258ad1f3a52ea442c32b3c92ad7146e74050c7
[4/6] power: Use named initializers for platform_device_id arrays
      commit: e28f7498dd819878b8acacb89c4c073a646feea0
[5/6] power: supply: mt6360_charger: Use of match table unconditionally
      commit: eb7ed650e5960fc303130704d1e29d18a7d0e1df
[6/6] power: Unify code style for platform_device_id arrays
      commit: e3f669bed32287ae72c05a4ddab4a6687b0e62ca

Best regards,
-- 
Sebastian Reichel <sebastian.reichel at collabora.com>



From sebastian.reichel at collabora.com  Wed Jun  3 14:39:29 2026
From: sebastian.reichel at collabora.com (Sebastian Reichel)
Date: Wed, 03 Jun 2026 23:39:29 +0200
Subject: (subset) [PATCH v8 phy-next 00/31] Split Generic PHY consumer
 and provider API
In-Reply-To: <20260505100523.1922388-1-vladimir.oltean@nxp.com>
References: <20260505100523.1922388-1-vladimir.oltean@nxp.com>
Message-ID: <178052276949.2678508.3221123153750103034.b4-ty@collabora.com>


On Tue, 05 May 2026 13:04:52 +0300, Vladimir Oltean wrote:
> The biggest problem requiring this split is the fact that consumer
> drivers poke around in struct phy, accessing fields which shouldn't be
> visible to them. Follow the example of mux, gpio, iio, spi offload,
> pwrsec, pinctrl and regulator, which each expose separate headers for
> consumers and providers.
> 
> Some off-list discussions were had with Vinod Koul regarding the 3 PHY
> providers outside the drivers/phy/ subsystem. It was agreed that it is
> desirable to relocate them to drivers/phy/, rather than to publish
> phy-provider.h to include/linux/phy/ for liberal use. Only phy.h and
> (new) phy-props.h - consumer-facing headers - stay there.
> 
> [...]

Applied, thanks!

[26/31] power: supply: cpcap-charger: include missing <linux/property.h>
        commit: a9e36028b688d693d8aefbf84a9899f31a20fcf0

Best regards,
-- 
Sebastian Reichel <sebastian.reichel at collabora.com>



From kuninori.morimoto.gx at renesas.com  Wed Jun  3 15:30:09 2026
From: kuninori.morimoto.gx at renesas.com (Kuninori Morimoto)
Date: Wed, 3 Jun 2026 22:30:09 +0000
Subject: [PATCH 02/83] ASoC: codecs: framer-codec: don't use array if single pattarn
In-Reply-To: <20260603140939.091f126f@bootlin.com>
References: <8733zfj5jj.wl-kuninori.morimoto.gx@renesas.com>
	<87zf1nhqxx.wl-kuninori.morimoto.gx@renesas.com>
	<20260603140939.091f126f@bootlin.com>
Message-ID: <87se7345qm.wl-kuninori.morimoto.gx@renesas.com>


Hi Herve

> > Because it is confusable during debugging ASoC FW update, tidyup
> > auto format style not to use array if single pattern case.
> > 
> > Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx at renesas.com>
> > ---
(snip)
> Just a typo in the commit title:
> s/pattarn/pattern/

Oops, thank you for pointing it.
Will fix in v2

Thank you for your help !!

Best regards
---
Kuninori Morimoto


From changhuang.liang at starfivetech.com  Wed Jun  3 18:37:00 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Thu, 4 Jun 2026 01:37:00 +0000
Subject: [PATCH v3 03/21] dt-bindings: pinctrl: Add
 starfive,jhb100-sys0-pinctrl
In-Reply-To: <20260603-groin-valid-a1d4445f7a6b@spud>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-4-changhuang.liang@starfivetech.com>
 <20260603-groin-valid-a1d4445f7a6b@spud>
Message-ID: <ZQ4PR01MB12022B5C460A34260ABFCE9FF2102@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>

Hi, Conor

Thanks for the review.

> On Tue, Jun 02, 2026 at 10:53:29PM -0700, Changhuang Liang wrote:
> 
> > +          slew-rate:
> > +            enum: [ 0, 1 ]
> > +            default: 0
> > +            description: |
> > +                0: slow (half frequency)
> 
> Half frequency? Slew rates are usually measured in volts per second, not hertz.
> Do you know what the slew rates actually are and could put them in here as
> the real units? Or is it just "slow" and "fast" in your docs with no precise
> numbers?

Yes, there are no precise numbers in our documentation. I will remove "(half frequency)" in the next version.

> I've got no questions other than this, so once this question is sorted, I'll be
> happy to ack all the bindings provided they're effectively the same.
> 
> > +                1: fast

Best Regards,
Changhuang


From chenwandun1 at gmail.com  Wed Jun  3 18:48:44 2026
From: chenwandun1 at gmail.com (Wandun)
Date: Thu, 4 Jun 2026 09:48:44 +0800
Subject: [PATCH v3 03/11] of: reserved_mem: avoid post-init UAF when
 alloc_reserved_mem_array() fails
In-Reply-To: <CAL_JsqJOC1ko1Len3Dyc5SNKrHmhQn9uiDAkFfVbYa2wAfFUTg@mail.gmail.com>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <20260527032917.3385849-4-chenwandun1@gmail.com>
 <20260602162450.GA442759-robh@kernel.org>
 <79932afc-2e91-4a54-aff9-f550be784c36@gmail.com>
 <CAL_JsqJOC1ko1Len3Dyc5SNKrHmhQn9uiDAkFfVbYa2wAfFUTg@mail.gmail.com>
Message-ID: <8e088395-c22d-4bc8-9e58-84235af1e56b@gmail.com>



On 6/4/26 01:44, Rob Herring wrote:
> On Wed, Jun 3, 2026 at 1:44?AM Wandun <chenwandun1 at gmail.com> wrote:
>>
>>
>> On 6/3/26 00:24, Rob Herring wrote:
>>> On Wed, May 27, 2026 at 11:29:09AM +0800, Wandun Chen wrote:
>>>> From: Wandun Chen <chenwandun at lixiang.com>
>>>>
>>>> The global pointer 'reserved_mem' continues to reference the
>>>> reserved_mem_array which lives in __initdata if
>>>> alloc_reserved_mem_array() fails. of_reserved_mem_lookup() is
>>>> exported for post-init use, that would dereference freed memory
>>>> and trigger a use-after-free.
>>>>
>>>> So reset reserved_mem_count to 0 when alloc_reserved_mem_array()
>>>> fails.
>>>>
>>>> Fixes: 00c9a452a235 ("of: reserved_mem: Add code to dynamically allocate reserved_mem array")
>>> Fixes should come first in a series.
>> Understood, will do in future submissions.
>>>> Signed-off-by: Wandun Chen <chenwandun at lixiang.com>
>>>> ---
>>>>    drivers/of/of_reserved_mem.c | 20 ++++++++++++++------
>>>>    1 file changed, 14 insertions(+), 6 deletions(-)
>>>>
>>>> diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
>>>> index 313cbc57aa45..6d479381ff1f 100644
>>>> --- a/drivers/of/of_reserved_mem.c
>>>> +++ b/drivers/of/of_reserved_mem.c
>>>> @@ -69,29 +69,31 @@ static int __init early_init_dt_alloc_reserved_memory_arch(phys_addr_t size,
>>>>     * the initial static array is copied over to this new array and
>>>>     * the new array is used from this point on.
>>>>     */
>>>> -static void __init alloc_reserved_mem_array(void)
>>>> +static bool __init alloc_reserved_mem_array(void)
>>>>    {
>>>>       struct reserved_mem *new_array;
>>>>       size_t alloc_size, copy_size, memset_size;
>>>>
>>>> +    if (!total_reserved_mem_cnt)
>>>> +            return true;
>>>> +
>>>>       alloc_size = array_size(total_reserved_mem_cnt, sizeof(*new_array));
>>>>       if (alloc_size == SIZE_MAX) {
>>>>               pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
>>>> -            return;
>>>> +            goto fail;
>>>>       }
>>>>
>>>>       new_array = memblock_alloc(alloc_size, SMP_CACHE_BYTES);
>>>>       if (!new_array) {
>>>>               pr_err("Failed to allocate memory for reserved_mem array with err: %d", -ENOMEM);
>>>> -            return;
>>>> +            goto fail;
>>>>       }
>>>>
>>>>       copy_size = array_size(reserved_mem_count, sizeof(*new_array));
>>>>       if (copy_size == SIZE_MAX) {
>>>>               memblock_free(new_array, alloc_size);
>>>> -            total_reserved_mem_cnt = MAX_RESERVED_REGIONS;
>>>>               pr_err("Failed to allocate memory for reserved_mem array with err: %d", -EOVERFLOW);
>>> These prints could be moved to 'fail'. Perhaps instead of just printing
>>> an error value, you can return the error value instead of boolean.
>> Will do, consolidating pr_err() under 'fail' and changing the return type
>> to int.
>>> If you respin just this patch, I can pick it up for 7.2.
>> Before I respin, I'd like to flag a dependency:
>> patch 05/07 in this series build on the signature change introduced by this
>> patch ("the void -> bool return type change of alloc_reserved_mem_array()")
>>
>> Could you let me know which of the following you'd prefer:
>> a) Take patch 03 alone via your tree as you suggested, after it lands, I'll
>>      respin the remaining patches of this series.
> I would go with this option. AIUI, this series isn't going to land in
> 7.2, so ultimately you will rebase on v7.2-rc1 which will have the
> fix.
OK, will send v4.

Best regards,
Wandun
>
>> b) Keep patch 03 in the v4 respin of the full series, reordered to the front
>>      per your earlier comment.
>
> Rob



From anup at brainfault.org  Wed Jun  3 22:29:12 2026
From: anup at brainfault.org (Anup Patel)
Date: Thu, 4 Jun 2026 10:59:12 +0530
Subject: [PATCH 1/3] KVM: riscv: Pass the target size to huge G-stage checks
In-Reply-To: <20260520152148.131272-2-tjytimi@163.com>
References: <20260520152148.131272-1-tjytimi@163.com> <20260520152148.131272-2-tjytimi@163.com>
Message-ID: <CAAhSdy14_aMXR6ztaQySOxQqaUNTARfhuZd=pTS=52nXrTQrEw@mail.gmail.com>

On Wed, May 20, 2026 at 8:52?PM Jinyu Tang <tjytimi at 163.com> wrote:
>
> fault_supports_gstage_huge_mapping() already contains the two checks
> needed before installing a G-stage block mapping: the userspace address
> and GPA must have matching offsets within the block, and the whole block
> must be contained within the memslot.
>
> The helper currently hard-codes PMD_SIZE because its only caller is the
> transparent hugepage path. The hugetlb path needs the same checks, but
> the target block size can be either PMD_SIZE or PUD_SIZE depending on the
> hugetlb VMA.
>
> So pass the target mapping size into the helper and use it for the
> alignment and bounds checks. This keeps the existing THP PMD behavior
> unchanged and prepares the helper to be reused for the following hugetlb
> fix.
>
> Signed-off-by: Jinyu Tang <tjytimi at 163.com>
> ---
>  arch/riscv/kvm/mmu.c | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 2d3def024..10be8f683 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -286,7 +286,8 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
>  }
>
>  static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
> -                                              unsigned long hva)
> +                                              unsigned long hva,
> +                                              unsigned long map_size)
>  {
>         hva_t uaddr_start, uaddr_end;
>         gpa_t gpa_start;
> @@ -300,8 +301,8 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>
>         /*
>          * Pages belonging to memslots that don't have the same alignment
> -        * within a PMD for userspace and GPA cannot be mapped with g-stage
> -        * PMD entries, because we'll end up mapping the wrong pages.
> +        * within a huge page for userspace and GPA cannot be mapped with
> +        * g-stage block entries, because we'll end up mapping the wrong pages.
>          *
>          * Consider a layout like the following:
>          *
> @@ -321,7 +322,7 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>          *   e -> g
>          *   f -> h
>          */
> -       if ((gpa_start & (PMD_SIZE - 1)) != (uaddr_start & (PMD_SIZE - 1)))
> +       if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1)))
>                 return false;
>
>         /*
> @@ -336,7 +337,8 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>          * userspace_addr or the base_gfn, as both are equally aligned (per
>          * the check above) and equally sized.
>          */
> -       return (hva >= ALIGN(uaddr_start, PMD_SIZE)) && (hva < ALIGN_DOWN(uaddr_end, PMD_SIZE));
> +       return (hva & ~(map_size - 1)) >= uaddr_start &&
> +              (hva & ~(map_size - 1)) + map_size <= uaddr_end;

This looks counter intuitive.
Why not have "(hva >= ALIGN(uaddr_start, map_size)) && (hva <
ALIGN_DOWN(uaddr_end, map_size))" ?

>  }
>
>  static int get_hva_mapping_size(struct kvm *kvm,
> @@ -404,7 +406,7 @@ static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
>          * sure that the HVA and GPA are sufficiently aligned and that the
>          * block map is contained within the memslot.
>          */
> -       if (fault_supports_gstage_huge_mapping(memslot, hva)) {
> +       if (fault_supports_gstage_huge_mapping(memslot, hva, PMD_SIZE)) {
>                 int sz;
>
>                 sz = get_hva_mapping_size(kvm, hva);
> --
> 2.43.0
>

Regards,
Anup


From anup at brainfault.org  Wed Jun  3 22:40:32 2026
From: anup at brainfault.org (Anup Patel)
Date: Thu, 4 Jun 2026 11:10:32 +0530
Subject: [PATCH 2/3] KVM: riscv: Check hugetlb block mappings against
 memslot bounds
In-Reply-To: <20260520152148.131272-3-tjytimi@163.com>
References: <20260520152148.131272-1-tjytimi@163.com> <20260520152148.131272-3-tjytimi@163.com>
Message-ID: <CAAhSdy2MhnN_6t2_Gpds-bVk+LzYCZsYTe+QXw-CMHdc58o2EA@mail.gmail.com>

On Wed, May 20, 2026 at 8:52?PM Jinyu Tang <tjytimi at 163.com> wrote:
>
> RISC-V KVM has used the hugetlb VMA size directly as the G-stage
> mapping size since stage-2 page table support was added. That is safe
> only if the block covered by the fault is fully contained in the
> memslot and the userspace address has the same offset as the GPA
> within that block.
>
> The THP path already checks those constraints before installing a PMD
> block mapping. The hugetlb path did not, so an unaligned memslot could
> make KVM install a PMD or PUD sized G-stage block that covers memory
> outside the slot or maps the wrong host pages.
>
> Select hugetlb mapping sizes through the same memslot-boundary check,
> falling back from PUD to PMD to PAGE_SIZE. When a smaller hugetlb
> mapping size is selected, fault the GFN aligned to that selected size
> instead of the original VMA size.
>
> Also keep hugetlb mappings out of transparent_hugepage_adjust(). Once
> the hugetlb path has chosen PAGE_SIZE, promoting it again through the
> THP helper would miss the hugetlb fallback decision.
>
> Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming")
> Signed-off-by: Jinyu Tang <tjytimi at 163.com>
> ---
>  arch/riscv/kvm/mmu.c | 40 ++++++++++++++++++++++++++++++++++++----
>  1 file changed, 36 insertions(+), 4 deletions(-)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 10be8f683..d2378bb1f 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -423,12 +423,33 @@ static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
>         return PAGE_SIZE;
>  }
>
> +static unsigned long hugetlb_mapping_size(struct kvm_memory_slot *memslot,
> +                                         unsigned long hva,
> +                                         unsigned long map_size)
> +{
> +       switch (map_size) {
> +       case PUD_SIZE:
> +               if (fault_supports_gstage_huge_mapping(memslot, hva, PUD_SIZE))

This patch is marked with a Fixes tag but does not include the changes
adding map_size parameter to fault_supports_gstage_huge_mapping().

I think it is better to sqash PATCH1 into this patch for completness of
this patch as Fix.

Regards,
Anup

> +                       return PUD_SIZE;
> +               fallthrough;
> +       case PMD_SIZE:
> +               if (fault_supports_gstage_huge_mapping(memslot, hva, PMD_SIZE))
> +                       return PMD_SIZE;
> +               fallthrough;
> +       case PAGE_SIZE:
> +               return PAGE_SIZE;
> +       default:
> +               return map_size;
> +       }
> +}
> +
>  int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
>                       gpa_t gpa, unsigned long hva, bool is_write,
>                       struct kvm_gstage_mapping *out_map)
>  {
>         int ret;
>         kvm_pfn_t hfn;
> +       bool is_hugetlb;
>         bool writable;
>         short vma_pageshift;
>         gfn_t gfn = gpa >> PAGE_SHIFT;
> @@ -462,16 +483,23 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
>                 return -EFAULT;
>         }
>
> -       if (is_vm_hugetlb_page(vma))
> +       is_hugetlb = is_vm_hugetlb_page(vma);
> +       if (is_hugetlb)
>                 vma_pageshift = huge_page_shift(hstate_vma(vma));
>         else
>                 vma_pageshift = PAGE_SHIFT;
>         vma_pagesize = 1ULL << vma_pageshift;
>         if (logging || (vma->vm_flags & VM_PFNMAP))
>                 vma_pagesize = PAGE_SIZE;
> +       else if (is_hugetlb)
> +               vma_pagesize = hugetlb_mapping_size(memslot, hva, vma_pagesize);
>
> +       /*
> +        * For hugetlb mappings, vma_pagesize might have been reduced from the
> +        * VMA size to a smaller safe mapping size.
> +        */
>         if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE)
> -               gfn = (gpa & huge_page_mask(hstate_vma(vma))) >> PAGE_SHIFT;
> +               gfn = ALIGN_DOWN(gpa, vma_pagesize) >> PAGE_SHIFT;
>
>         /*
>          * Read mmu_invalidate_seq so that KVM can detect if the results of
> @@ -513,8 +541,12 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
>         if (mmu_invalidate_retry(kvm, mmu_seq))
>                 goto out_unlock;
>
> -       /* Check if we are backed by a THP and thus use block mapping if possible */
> -       if (!logging && (vma_pagesize == PAGE_SIZE))
> +       /*
> +        * Check if we are backed by a THP and thus use block mapping if
> +        * possible. Hugetlb mappings already selected their target size above,
> +        * so do not promote them through the THP helper.
> +        */
> +       if (!logging && !is_hugetlb && vma_pagesize == PAGE_SIZE)
>                 vma_pagesize = transparent_hugepage_adjust(kvm, memslot, hva, &hfn, &gpa);
>
>         if (writable) {
> --
> 2.43.0
>


From anup at brainfault.org  Wed Jun  3 22:43:17 2026
From: anup at brainfault.org (Anup Patel)
Date: Thu, 4 Jun 2026 11:13:17 +0530
Subject: [PATCH v2] RISC-V: KVM: Document a TOCTOU race in SBI system
 suspend handler
In-Reply-To: <20260525013642.999187-1-xujiakai2025@iscas.ac.cn>
References: <20260525013642.999187-1-xujiakai2025@iscas.ac.cn>
Message-ID: <CAAhSdy0LCXF677cBuS-CUBynUqWL7d_ra8+e+uOJurLm2nZzWg@mail.gmail.com>

On Mon, May 25, 2026 at 7:06?AM Jiakai Xu <xujiakai2025 at iscas.ac.cn> wrote:
>
> The SUSP handler checks that all other vCPUs are stopped before
> entering system suspend, but a concurrent HSM HART_START can start
> a vCPU after it has already passed the check.
>
> This is a known TOCTOU race. We do not fix it because:
> 1. Triggering it requires a pathological guest.
> 2. Only guest state is at risk, not host integrity.
> 3. Userspace can double-check vCPU states before suspend.
>
> Add a comment documenting the race and the rationale for not fixing it.
>
> Signed-off-by: Jiakai Xu <jiakaiPeanut at gmail.com>
> Signed-off-by: Jiakai Xu <xujiakai2025 at iscas.ac.cn>
> Assisted-by: YuanSheng:DeepSeek-V3.2

Queued this patch for Linux-7.2

Thanks,
Anup

> ---
> V1 -> V2:
> - Replaced the fix with a comment.
> Link: https://lore.kernel.org/linux-riscv/20260521142030.1560861-1-xujiakai2025 at iscas.ac.cn/t/#u
> ---
>  arch/riscv/kvm/vcpu_sbi_system.c | 14 ++++++++++++++
>  1 file changed, 14 insertions(+)
>
> diff --git a/arch/riscv/kvm/vcpu_sbi_system.c b/arch/riscv/kvm/vcpu_sbi_system.c
> index c6f7e609ac794..6f64a59e5d3c4 100644
> --- a/arch/riscv/kvm/vcpu_sbi_system.c
> +++ b/arch/riscv/kvm/vcpu_sbi_system.c
> @@ -35,6 +35,20 @@ static int kvm_sbi_ext_susp_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
>                         return 0;
>                 }
>
> +               /*
> +                * Check that all other vCPUs are stopped before entering
> +                * system suspend.
> +                *
> +                * There is a known TOCTOU race here: a concurrent HSM
> +                * HART_START on another vCPU can start a vCPU after it
> +                * has already passed this check, violating the invariant.
> +                *
> +                * We do not fix this because:
> +                * 1. Triggering the race requires a pathological guest.
> +                * 2. Only guest state is at risk, not host integrity.
> +                * 3. Userspace can double-check vCPU states before
> +                *    proceeding with suspend.
> +                */
>                 kvm_for_each_vcpu(i, tmp, vcpu->kvm) {
>                         if (tmp == vcpu)
>                                 continue;
> --
> 2.34.1
>


From anup at brainfault.org  Wed Jun  3 22:48:53 2026
From: anup at brainfault.org (Anup Patel)
Date: Thu, 4 Jun 2026 11:18:53 +0530
Subject: [PATCH] RISC-V: KVM: Fix NULL pointer dereference in AIA IMSIC functions
In-Reply-To: <20260526031517.1166025-1-xujiakai2025@iscas.ac.cn>
References: <20260526031517.1166025-1-xujiakai2025@iscas.ac.cn>
Message-ID: <CAAhSdy0RxUMYP-fs5=drG+6iwVEmwiVvHRL2MRieEXP7YiERjg@mail.gmail.com>

On Tue, May 26, 2026 at 8:45?AM Jiakai Xu <xujiakai2025 at iscas.ac.cn> wrote:
>
> Fuzzer reported a NULL pointer dereference in
> kvm_riscv_vcpu_aia_imsic_put() when a VCPU's imsic_state was NULL while
> kvm_riscv_aia_initialized() returned true.
>
> The global initialized flag is set per-VM in aia_init(), but imsic_state
> is allocated per-VCPU in kvm_riscv_vcpu_aia_imsic_init(). If a VCPU is
> created after aia_init() has already run, its imsic_state remains NULL
> while the global flag is true. When this VCPU is preempted, kvm_sched_out()
> calls kvm_arch_vcpu_put() -> kvm_riscv_vcpu_aia_put() ->
> kvm_riscv_vcpu_aia_imsic_put() which dereferences NULL.
>
> Add NULL pointer guards to kvm_riscv_vcpu_aia_imsic_put(), consistent with
> the NULL checks already present in all other functions in the same file.
>
> Also add a NULL guard to kvm_riscv_vcpu_aia_imsic_release() and
> kvm_riscv_vcpu_aia_imsic_has_interrupt() for the same reason.
>
> Fixes: 4cec89db80ba ("RISC-V: KVM: Move HGEI[E|P] CSR access to IMSIC virtualization")
> Signed-off-by: Jiakai Xu <jiakaiPeanut at gmail.com>
> Signed-off-by: Jiakai Xu <xujiakai2025 at iscas.ac.cn>
> Assisted-by: YuanSheng:DeepSeek-V3.2

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this patch for Linux-7.2

Thanks,
Anup

> ---
>  arch/riscv/kvm/aia_imsic.c | 9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
> index 8786f52cf65a2..d38f5de0834c5 100644
> --- a/arch/riscv/kvm/aia_imsic.c
> +++ b/arch/riscv/kvm/aia_imsic.c
> @@ -683,6 +683,9 @@ bool kvm_riscv_vcpu_aia_imsic_has_interrupt(struct kvm_vcpu *vcpu)
>         unsigned long flags;
>         bool ret = false;
>
> +       if (!imsic)
> +               return false;
> +
>         /*
>          * The IMSIC SW-file directly injects interrupt via hvip so
>          * only check for interrupt when IMSIC VS-file is being used.
> @@ -722,6 +725,9 @@ void kvm_riscv_vcpu_aia_imsic_put(struct kvm_vcpu *vcpu)
>         struct imsic *imsic = vcpu->arch.aia_context.imsic_state;
>         unsigned long flags;
>
> +       if (!imsic)
> +               return;
> +
>         if (!kvm_vcpu_is_blocking(vcpu))
>                 return;
>
> @@ -738,6 +744,9 @@ void kvm_riscv_vcpu_aia_imsic_release(struct kvm_vcpu *vcpu)
>         int old_vsfile_hgei, old_vsfile_cpu;
>         struct imsic *imsic = vcpu->arch.aia_context.imsic_state;
>
> +       if (!imsic)
> +               return;
> +
>         /* Read and clear IMSIC VS-file details */
>         write_lock_irqsave(&imsic->vsfile_lock, flags);
>         old_vsfile_hgei = imsic->vsfile_hgei;
> --
> 2.34.1
>
> Found by fuzzing. Here is the report:
>
> Unable to handle kernel paging request at virtual address dfffffff00000006
> Modules linked in:
> CPU: 1 UID: 0 PID: 26225 Comm: syz.9.1131 Tainted: G        W           7.1.0-rc1-gb69bcb13ed70 #2 PREEMPT
> Tainted: [W]=WARN
> Hardware name: riscv-virtio,qemu (DT)
> epc : kasan_byte_accessible+0x12/0x20 mm/kasan/generic.c:210
>  ra : __kasan_check_byte+0x16/0x46 mm/kasan/common.c:573
> epc : ffffffff80beb626 ra : ffffffff80be9622 sp : ff200000016276a0
>  gp : ffffffff8a395320 tp : ff6000008f6f5040 t0 : ffffffff86a7e880
>  t1 : ffffffff8a4a4a00 t2 : 0000000000000000 s0 : ff200000016276b0
>  s1 : 0000000000000030 a0 : dfffffff00000006 a1 : ffffffff867223e4
>  a2 : 0000000000000000 a3 : 0000000000000007 a4 : 0000000000000003
>  a5 : dfffffff00000000 a6 : ffffffff8010e72c a7 : 0000000000000004
>  s2 : 0000000000000030 s3 : ffffffff867223e4 s4 : 0000000000000000
>  s5 : 0000000000000000 s6 : 0000000000000000 s7 : ffffffff8010e72c
>  s8 : ffffffff867223e4 s9 : ffffffff8a3da080 s10: 0000085c7b3d0060
>  s11: ff6000008f6f5040 t3 : ffffffff8a4a4a00 t4 : ffffffff8a4a5a80
>  t5 : 1ffffffff22ed7d1 t6 : ff600000ffa4d710 ssp : 0000000000000000
> status: 0000000200000100 badaddr: dfffffff00000006 cause: 000000000000000d
> [<ffffffff80beb626>] kasan_mem_to_shadow include/linux/kasan.h:66 [inline]
> [<ffffffff80beb626>] kasan_byte_accessible+0x12/0x20 mm/kasan/generic.c:210
> [<ffffffff80be9622>] __kasan_check_byte+0x16/0x46 mm/kasan/common.c:573
> [<ffffffff802fe7ba>] kasan_check_byte include/linux/kasan.h:402 [inline]
> [<ffffffff802fe7ba>] lock_acquire kernel/locking/lockdep.c:5842 [inline]
> [<ffffffff802fe7ba>] lock_acquire+0x198/0x50e kernel/locking/lockdep.c:5825
> [<ffffffff867223e4>] __raw_read_lock_irqsave include/linux/rwlock_api_smp.h:174 [inline]
> [<ffffffff867223e4>] _raw_read_lock_irqsave+0x76/0x82 kernel/locking/spinlock.c:240
> [<ffffffff8010e72c>] kvm_riscv_vcpu_aia_imsic_put+0x72/0x17c arch/riscv/kvm/aia_imsic.c:728
> [<ffffffff80101bda>] kvm_riscv_vcpu_aia_put+0x288/0x324 arch/riscv/kvm/aia.c:155
> [<ffffffff8011f210>] kvm_arch_vcpu_put+0x44/0x612 arch/riscv/kvm/vcpu.c:621
> [<ffffffff800d50aa>] kvm_sched_out+0xdc/0x296 virt/kvm/kvm_main.c:6405
> [<ffffffff86705faa>] __fire_sched_out_preempt_notifiers kernel/sched/core.c:4923 [inline]
> [<ffffffff86705faa>] fire_sched_out_preempt_notifiers kernel/sched/core.c:4931 [inline]
> [<ffffffff86705faa>] prepare_task_switch kernel/sched/core.c:5176 [inline]
> [<ffffffff86705faa>] context_switch kernel/sched/core.c:5332 [inline]
> [<ffffffff86705faa>] __schedule+0x10c8/0x513c kernel/sched/core.c:7188
> [<ffffffff8670a0e2>] __schedule_loop kernel/sched/core.c:7267 [inline]
> [<ffffffff8670a0e2>] schedule+0xc4/0x35e kernel/sched/core.c:7282
> [<ffffffff80121cc2>] kvm_riscv_check_vcpu_requests arch/riscv/kvm/vcpu.c:670 [inline]
> [<ffffffff80121cc2>] kvm_arch_vcpu_ioctl_run+0x1d16/0x3214 arch/riscv/kvm/vcpu.c:885
> [<ffffffff800da8ee>] kvm_vcpu_ioctl+0x532/0x13ce virt/kvm/kvm_main.c:4469
> [<ffffffff80d45c90>] vfs_ioctl fs/ioctl.c:51 [inline]
> [<ffffffff80d45c90>] __do_sys_ioctl fs/ioctl.c:597 [inline]
> [<ffffffff80d45c90>] __se_sys_ioctl fs/ioctl.c:583 [inline]
> [<ffffffff80d45c90>] __riscv_sys_ioctl+0x180/0x1e4 fs/ioctl.c:583
> [<ffffffff80078fb2>] syscall_handler+0x94/0x118 arch/riscv/include/asm/syscall.h:112
> [<ffffffff866fa94a>] do_trap_ecall_u+0x43e/0x5de arch/riscv/kernel/traps.c:342
> [<ffffffff86726756>] handle_exception+0x15e/0x16a arch/riscv/kernel/entry.S:232
> Code: 8082 07b7 e000 1141 17fd e422 810d 0800 1782 953e (4503) 0005
> ---[ end trace 0000000000000000 ]---
> ----------------
> Code disassembly (best guess):
>    0:   8082                    ret
>    2:   e00007b7                lui     a5,0xe0000
>    6:   1141                    addi    sp,sp,-16
>    8:   17fd                    addi    a5,a5,-1 # 0xffffffffdfffffff
>    a:   e422                    fsw     fs0,8(sp)
>    c:   810d                    srli    a0,a0,0x3
>    e:   0800                    addi    s0,sp,16
>   10:   1782                    slli    a5,a5,0x20
>   12:   953e                    add     a0,a0,a5
> * 14:   00054503                lbu     a0,0(a0) <-- trapping instruction
>
> <<<<<<<<<<<<<<< tail report >>>>>>>>>>>>>>>
>


From mhi at mailbox.org  Wed Jun  3 23:11:06 2026
From: mhi at mailbox.org (Maurice Hieronymus)
Date: Thu, 04 Jun 2026 08:11:06 +0200
Subject: [PATCH 0/2] rust: clk: Add ExclusiveClk and use it in pwm-th1520
In-Reply-To: <20260526-rate-exclusive-get-th1520-v1-0-34cf034e1764@mailbox.org>
References: <20260526-rate-exclusive-get-th1520-v1-0-34cf034e1764@mailbox.org>
Message-ID: <50095a4839fdaaf9522a2ccf26d19e3f7bb98866.camel@mailbox.org>

On Tue, 2026-05-26 at 19:04 +0200, Maurice Hieronymus via B4 Relay
wrote:
> Add a Rust binding for clk_rate_exclusive_get() /
> clk_rate_exclusive_put()
> and use it in pwm-th1520, which previously carried a TODO noting the
> missing binding.
> 
> Based on pwm/for-next.
> 
> Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>
> ---
> Maurice Hieronymus (2):
> ????? rust: clk: Add ExclusiveClk wrapper for clk_rate_exclusive_get
> ????? pwm: th1520: Lock clock rate with clk_rate_exclusive_get
> 
> ?drivers/pwm/pwm_th1520.rs |? 8 +++---
> ?rust/kernel/clk.rs??????? | 65
> +++++++++++++++++++++++++++++++++++++++++++++++
> ?2 files changed, 68 insertions(+), 5 deletions(-)
> ---
> base-commit: 0e5e0db3e954b32a410ab4f74a4faac7a0e8889f
> change-id: 20260526-rate-exclusive-get-th1520-764a949de18e
> 
> Best regards,

Any opinions on this patch?


From wang.yechao255 at zte.com.cn  Wed Jun  3 23:55:10 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Thu, 4 Jun 2026 14:55:10 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIXSBpb21tdS9yaXNjdjogQWRkIGRlcGVuZGVuY3kgYmV0d2VlbiBpb21tdSBhbmQgZGV2aWNlcw==?=
Message-ID: <20260604145510898G2kTwM2Pr25QE5H8T4Wh6@zte.com.cn>

From: Wang Yechao <wang.yechao255 at zte.com.cn>

Commit 9156585280f1 ("ACPI: RIMT: Add dependency between iommu and
devices") adds the dependency between iommu and devices on ACPI
systems. On devicetree systems, the incorrect removal order also
occurs.

It can be reproduced on the QEMU RISC-V machine if the kernel enables
IOMMU_DMA:

[  635.081530] e1000e: EEE TX LPI TIMER: 00000000
[  656.100306] rcu: INFO: rcu_sched self-detected stall on CPU
[  656.101374] rcu:     5-....: (5250 ticks this GP) idle=d774/1/0x4000000000000000 softirq=5173/5185 fqs=2625
[  656.102237] rcu:     (t=5251 jiffies g=36825 q=101 ncpus=16)
[  656.103801] CPU: 5 UID: 0 PID: 1958 Comm: reboot Tainted: G        W           7.1.0-rc5 #31 PREEMPTLAZY
[  656.104127] Tainted: [W]=WARN
[  656.104182] Hardware name: QEMU QEMU Virtual Machine, BIOS 2.7 02/02/2022
[  656.104339] epc : riscv_iommu_cmd_sync.constprop.0+0xb8/0x148
[  656.105352]  ra : riscv_iommu_cmd_sync.constprop.0+0xa8/0x148
[  656.105433] epc : ffffffff807ca980 ra : ffffffff807ca970 sp : ff60000085dbf960
[  656.105475]  gp : ffffffff81e0d798 tp : ff60000084b58e00 t0 : ffffffff80021048
[  656.105514]  t1 : ff60000081b18400 t2 : 45203a6530303031 s0 : ff60000085dbf9c0
[  656.105554]  s1 : 00000098c92a567c a0 : 00000098c03986f0 a1 : ff60000085dbf970
[  656.105594]  a2 : 000024bb5cac6aee a3 : ff200000004f1000 a4 : ff6000008140a040
[  656.105632]  a5 : 0000000000000669 a6 : 0000000000000000 a7 : 00000000ffffa000
[  656.105669]  s2 : 0000000000000000 s3 : 00000098c0398308 s4 : 000000000000066a
[  656.105706]  s5 : 0000000008f0d180 s6 : 000000a8d08b8de9 s7 : 0000000000001fff
[  656.105743]  s8 : ff6000008140a040 s9 : ff6000008484cb00 s10: ff200000005cc000
[  656.105781]  s11: ff600000814652a0 t3 : 000000f000000000 t4 : 0000000000000000
[  656.105845]  t5 : 0000000000000003 t6 : ff600000841666b0 ssp : 0000000000000000
[  656.105883] status: 0000000200000120 badaddr: 0000000000000000 cause: 8000000000000005
[  656.106072] riscv_iommu_cmd_sync.constprop.0+0xb8/0x148
[  656.106321] riscv_iommu_iotlb_inval+0x120/0x160
[  656.106373] riscv_iommu_iotlb_sync+0x48/0x60
[  656.106422] __iommu_dma_unmap+0xca/0xf8
[  656.106470] iommu_dma_unmap_phys+0x58/0xc8
[  656.106517] dma_unmap_phys+0x15c/0x248
[  656.106564] dma_unmap_page_attrs+0x1e/0x30
[  656.106915] e1000_clean_rx_ring+0x1d2/0x200 [e1000e]
[  656.107668] e1000e_down+0x168/0x1c8 [e1000e]
[  656.107995] e1000e_pm_freeze+0x94/0x128 [e1000e]
[  656.108328] e1000_shutdown+0x28/0x48 [e1000e]
[  656.108652] pci_device_shutdown+0x34/0x48
[  656.108706] device_shutdown+0x104/0x1e8
[  656.108752] kernel_restart+0x46/0xb8
[  656.108797] __do_sys_reboot+0xc0/0x1c8
[  656.108840] __riscv_sys_reboot+0x22/0x38
[  656.108882] do_trap_ecall_u+0x236/0x3f8
[  656.108947] handle_exception+0x15a/0x166

So move the device link into the iommu driver to fix both ACPI and
devicetree systems.

Fixes: 488ffbf18171 ("iommu/riscv: Paging domain support")
Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
---
 drivers/acpi/riscv/rimt.c   | 7 -------
 drivers/iommu/riscv/iommu.c | 7 +++++++
 2 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/acpi/riscv/rimt.c b/drivers/acpi/riscv/rimt.c
index 906282b0e63c..229c4a0d47a3 100644
--- a/drivers/acpi/riscv/rimt.c
+++ b/drivers/acpi/riscv/rimt.c
@@ -263,13 +263,6 @@ static int rimt_iommu_xlate(struct device *dev, struct acpi_rimt_node *node, u32
 	if (!rimt_fwnode)
 		return -EPROBE_DEFER;

-	/*
-	 * EPROBE_DEFER ensures IOMMU is probed before the devices that
-	 * depend on them. During shutdown, however, the IOMMU may be removed
-	 * first, leading to issues. To avoid this, a device link is added
-	 * which enforces the correct removal order.
-	 */
-	device_link_add(dev, rimt_fwnode->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
 	return acpi_iommu_fwspec_init(dev, deviceid, rimt_fwnode);
 }

diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index a31f50bbad35..f9368e977346 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -1385,6 +1385,13 @@ static struct iommu_device *riscv_iommu_probe_device(struct device *dev)

 	dev_iommu_priv_set(dev, info);

+	/*
+	 * During shutdown, however, the IOMMU may be removed first, leading
+	 * to issues. To avoid this, a device link is added which enforces
+	 * the correct removal order.
+	 */
+	device_link_add(dev, fwspec->iommu_fwnode->dev, DL_FLAG_AUTOREMOVE_CONSUMER);
+
 	return &iommu->iommu;
 }

-- 
2.43.5


From anup at brainfault.org  Thu Jun  4 00:52:49 2026
From: anup at brainfault.org (Anup Patel)
Date: Thu, 4 Jun 2026 13:22:49 +0530
Subject: [PATCH] RISC-V: KVM: Fix timer state restore
In-Reply-To: <20260526075544.796396-1-maqianga@uniontech.com>
References: <20260526075544.796396-1-maqianga@uniontech.com>
Message-ID: <CAAhSdy2GwXZ+qDdnNYe6Ykunvoa8-okQepxBNffGMFXu0U8Mig@mail.gmail.com>

On Tue, May 26, 2026 at 1:26?PM Qiang Ma <maqianga at uniontech.com> wrote:
>
> The KVM_REG_RISCV_TIMER_REG(state) one-reg write passes the value
> written by userspace to kvm_riscv_vcpu_timer_next_event() when
> re-enabling the timer.
>
> That value is the timer state, KVM_RISCV_TIMER_STATE_ON, not the
> timer compare value. During migration or state restore, userspace
> restores the compare register separately, which stores the target
> cycle in t->next_cycles. Re-arming the timer with the state value
> schedules the next event at cycle 1 instead of the restored compare
> value, causing the virtual timer to fire too early.
>
> Use the restored compare value from t->next_cycles when turning the
> timer back on.
>
> Fixes: 3a9f66cb25e1 ("RISC-V: KVM: Add timer functionality")
>
> Signed-off-by: Qiang Ma <maqianga at uniontech.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this patch for Linux-7.2

Thanks,
Anup

> ---
>  arch/riscv/kvm/vcpu_timer.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c
> index 9817ff802821..ae53133c7ab0 100644
> --- a/arch/riscv/kvm/vcpu_timer.c
> +++ b/arch/riscv/kvm/vcpu_timer.c
> @@ -231,7 +231,7 @@ int kvm_riscv_vcpu_set_reg_timer(struct kvm_vcpu *vcpu,
>                 break;
>         case KVM_REG_RISCV_TIMER_REG(state):
>                 if (reg_val == KVM_RISCV_TIMER_STATE_ON)
> -                       ret = kvm_riscv_vcpu_timer_next_event(vcpu, reg_val);
> +                       ret = kvm_riscv_vcpu_timer_next_event(vcpu, t->next_cycles);
>                 else
>                         ret = kvm_riscv_vcpu_timer_cancel(t);
>                 break;
> --
> 2.20.1
>


From conor at kernel.org  Thu Jun  4 02:41:59 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 10:41:59 +0100
Subject: [PATCH] riscv: defconfig: thead: enable PCA953X GPIO driver
In-Reply-To: <aiCC21nUsYIp1l3M@gen8>
References: <CGME20260603082156eucas1p1f44a198f7957d9d82ec0b8bc296fb03c@eucas1p1.samsung.com>
 <20260603082132.3200787-1-m.szyprowski@samsung.com>
 <aiCC21nUsYIp1l3M@gen8>
Message-ID: <20260604-moonbeam-alfalfa-6f97dd25d3f8@spud>

On Wed, Jun 03, 2026 at 12:39:07PM -0700, Drew Fustini wrote:
> On Wed, Jun 03, 2026 at 10:21:32AM +0200, Marek Szyprowski wrote:
> > Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
> > LicheePi4a board.
> > 
> > Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> > ---
> >  arch/riscv/configs/defconfig | 2 ++
> >  1 file changed, 2 insertions(+)
> > 
> > diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
> > index 08445df56006..a51a423d53f4 100644
> > --- a/arch/riscv/configs/defconfig
> > +++ b/arch/riscv/configs/defconfig
> > @@ -174,6 +174,8 @@ CONFIG_PINCTRL_SOPHGO_SG2002=y
> >  CONFIG_GPIO_DWAPB=y
> >  CONFIG_GPIO_SIFIVE=y
> >  CONFIG_GPIO_SPACEMIT_K1=y
> > +CONFIG_GPIO_PCA953X=y
> > +CONFIG_GPIO_PCA953X_IRQ=y
> >  CONFIG_POWER_RESET_GPIO_RESTART=y
> >  CONFIG_SENSORS_SFCTEMP=m
> >  CONFIG_CPU_THERMAL=y
> > -- 
> > 2.34.1
> > 
> 
> Reviewed-by: Drew Fustini <fustini at kernel.org>
> 
> Paul/Conor: what is the right tree for a arch/riscv/configs/defconfig
> patch like this?

I dunno, in arm land the various platform maintainers take care of this
kind of thing for their own platforms. That hasn't happened (yet?) for
riscv. I've probably taken most SoC support things like this recently.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/823c9d4e/attachment.sig>

From wangruikang at iscas.ac.cn  Thu Jun  4 04:11:55 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Thu, 04 Jun 2026 19:11:55 +0800
Subject: [PATCH v2 2/2] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
In-Reply-To: <20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434@iscas.ac.cn>
References: <20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434@iscas.ac.cn>
Message-ID: <20260604-mark-after-vmemmap-populate-v2-2-ab6a7d03b434@iscas.ac.cn>

section_activate() creates new mappings in the vmemmap range without
flushing TLB, which may cause faults on some RISC-V implementations that
cache non-present PTEs and crashes.

This seems to be most easily reproduced with DEBUG_VM=y and
PAGE_POISONING=y, which causes these newly mapped struct pages to be
poisoned i.e. written to immediately after mapping.

Implement the newly added hook vmemmap_populate_finalize() on RISC-V, to
arrange for the existing exception handler code to deal with these
faults if they happen.

Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
---
I put the declaration here since it's the file where vmemmap and the
vmemmap area addresses are defined.

Depends on my kfence patches for mark_new_valid_map() (see cover).
---
 arch/riscv/include/asm/pgtable.h | 4 ++++
 arch/riscv/mm/init.c             | 6 ++++++
 2 files changed, 10 insertions(+)

diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index a1a7c6520a09..aa0f50e3d534 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -1243,6 +1243,10 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
 #define TASK_SIZE	FIXADDR_START
 #endif
 
+/* Needed on SPARSEMEM_VMEMMAP */
+#define vmemmap_populate_finalize vmemmap_populate_finalize
+void __meminit vmemmap_populate_finalize(void);
+
 #else /* CONFIG_MMU */
 
 #define PAGE_SHARED		__pgprot(0)
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 706f43523935..cf9ae4099f82 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1360,6 +1360,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
 	 */
 	return vmemmap_populate_hugepages(start, end, node, altmap);
 }
+
+void __meminit vmemmap_populate_finalize(void)
+{
+	/* Avoid faults on cached non-present TLB entries. */
+	mark_new_valid_map();
+}
 #endif
 
 #if defined(CONFIG_MMU) && defined(CONFIG_64BIT)

-- 
2.54.0



From wangruikang at iscas.ac.cn  Thu Jun  4 04:11:53 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Thu, 04 Jun 2026 19:11:53 +0800
Subject: [PATCH v2 0/2] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
Message-ID: <20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434@iscas.ac.cn>

Patch 1 adds a hook and should be no functional change on its own,
whereas patch 2 is the actual fix, which depends on my earlier kfence
fixes for mark_new_valid_map() [1].

Found while testing AMD_HSA/ZONE_DEVICE on SpacemiT K3. Using
ZONE_DEVICE requires another fix [2].

[1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn
[2]: https://lore.kernel.org/linux-riscv/20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd at iscas.ac.cn

---
Changes in v2:
- Split patch in two, hook point and riscv hook 
- Explain hook necessity in patch 1 message (Mike)
- Make hook #define based (Mike)
- Call finalize hook only on populate success
- Link to v1: https://patch.msgid.link/20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16 at iscas.ac.cn

---
Vivian Wang (2):
      mm/vmemmap: Add a post-population hook for architectures
      riscv: mm: Avoid spurious fault after hotplugging vmemmap

 arch/riscv/include/asm/pgtable.h | 4 ++++
 arch/riscv/mm/init.c             | 6 ++++++
 mm/sparse-vmemmap.c              | 8 ++++++++
 3 files changed, 18 insertions(+)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260525-mark-after-vmemmap-populate-68bd790839c9
prerequisite-message-id: <20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn>
prerequisite-patch-id: fdc42f2647e21d111f44a6532887a6705cd470a9
prerequisite-patch-id: 096fa339c84c36643ae4311fd8362dc63e23d950
prerequisite-patch-id: 305c876a5f4a23a840a8142aea79b796ed297545
prerequisite-patch-id: d78cb55d6a616b1170f06a401c8fd44acd11e5d5
prerequisite-patch-id: b02b4a76e94f3e2821291d4c23b46f6e5ecf5203

Best regards,
--  
Vivian Wang <wangruikang at iscas.ac.cn>



From wangruikang at iscas.ac.cn  Thu Jun  4 04:11:54 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Thu, 04 Jun 2026 19:11:54 +0800
Subject: [PATCH v2 1/2] mm/vmemmap: Add a post-population hook for
 architectures
In-Reply-To: <20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434@iscas.ac.cn>
References: <20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434@iscas.ac.cn>
Message-ID: <20260604-mark-after-vmemmap-populate-v2-1-ab6a7d03b434@iscas.ac.cn>

section_activate() does not flush TLB after populating new vmemmap
pages. On most architectures, this is okay, however it is a problem on
RISC-V since there TLB caching non-present entries is permitted, which
causes spurious faults on some hardwares.

Add a hook vmemmap_populate_finalize() in __populate_section_memmap()
after population, to allow architectures to handle such situations as
needed.

No functional change intended for now, but a hook implementation for
RISC-V will be added in a later patch.

Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
---
 mm/sparse-vmemmap.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 6eadb9d116e4..2a8b923fabe8 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -544,6 +544,12 @@ static int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn,
 
 #endif
 
+#ifndef vmemmap_populate_finalize
+static void __meminit vmemmap_populate_finalize(void)
+{
+}
+#endif
+
 struct page * __meminit __populate_section_memmap(unsigned long pfn,
 		unsigned long nr_pages, int nid, struct vmem_altmap *altmap,
 		struct dev_pagemap *pgmap)
@@ -564,6 +570,8 @@ struct page * __meminit __populate_section_memmap(unsigned long pfn,
 	if (r < 0)
 		return NULL;
 
+	vmemmap_populate_finalize();
+
 	return pfn_to_page(pfn);
 }
 

-- 
2.54.0



From aliceryhl at google.com  Thu Jun  4 04:17:11 2026
From: aliceryhl at google.com (Alice Ryhl)
Date: Thu, 4 Jun 2026 11:17:11 +0000
Subject: [PATCH 1/2] rust: clk: Add ExclusiveClk wrapper for clk_rate_exclusive_get
In-Reply-To: <20260526-rate-exclusive-get-th1520-v1-1-34cf034e1764@mailbox.org>
References: <20260526-rate-exclusive-get-th1520-v1-0-34cf034e1764@mailbox.org> <20260526-rate-exclusive-get-th1520-v1-1-34cf034e1764@mailbox.org>
Message-ID: <aiFet_2SNAwj6o2O@google.com>

On Tue, May 26, 2026 at 07:04:57PM +0200, Maurice Hieronymus via B4 Relay wrote:
> From: Maurice Hieronymus <mhi at mailbox.org>
> 
> Add Rust bindings for clk_rate_exclusive_get() and
> clk_rate_exclusive_put().
> 
> Clk::rate_exclusive_get() consumes the Clk and returns an ExclusiveClk;
> the matching put is issued from its Drop impl. ExclusiveClk derefs to
> Clk so existing rate / prepare / enable APIs remain available on the
> locked handle.
> 
> Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>

Overall looks okay to me. With below comments fixed:
Reviewed-by: Alice Ryhl <aliceryhl at google.com>

>  rust/kernel/clk.rs | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 65 insertions(+)
> 
> diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
> index 7abbd0767d8c..8cda40cb01e4 100644
> --- a/rust/kernel/clk.rs
> +++ b/rust/kernel/clk.rs
> @@ -249,6 +249,23 @@ pub fn set_rate(&self, rate: Hertz) -> Result {
>              // [`clk_set_rate`].
>              to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_hz()) })
>          }
> +
> +        /// Acquire exclusive control over the clock's rate.
> +        ///
> +        /// Consumes the [`Clk`] and returns an [`ExclusiveClk`] that releases the exclusivity
> +        /// when dropped. While held, no other consumer may change the clock's rate.
> +        ///
> +        /// Equivalent to the kernel's [`clk_rate_exclusive_get`] API. Must not be called from
> +        /// atomic context.
> +        ///
> +        /// [`clk_rate_exclusive_get`]:
> +        /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_rate_exclusive_get

Avoid the newline here. Links are long, and it's okay that they are
long. They must be on one line.

> +        pub fn rate_exclusive_get(self) -> Result<ExclusiveClk> {
> +            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> +            // [`clk_rate_exclusive_get`].
> +            to_result(unsafe { bindings::clk_rate_exclusive_get(self.as_raw()) })?;
> +            Ok(ExclusiveClk(self))
> +        }
>      }
>  
>      impl Drop for Clk {
> @@ -329,6 +346,54 @@ fn deref(&self) -> &Clk {
>              &self.0
>          }
>      }
> +
> +    /// A [`Clk`] with exclusive control over its rate.
> +    ///
> +    /// While an [`ExclusiveClk`] exists, no other consumer of the same clock may change its rate.
> +    /// Obtained by calling [`Clk::rate_exclusive_get`]; the exclusivity is released automatically
> +    /// when the value is dropped, after which the inner [`Clk`] is dropped as usual.
> +    ///
> +    /// # Invariants
> +    ///
> +    /// An [`ExclusiveClk`] instance owns a [`Clk`] for which `clk_rate_exclusive_get` has been
> +    /// called and the matching `clk_rate_exclusive_put` has not yet been called.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// use kernel::clk::{Clk, ExclusiveClk};
> +    /// use kernel::device::Device;
> +    /// use kernel::error::Result;
> +    ///
> +    /// fn lock_rate(dev: &Device) -> Result<ExclusiveClk> {
> +    ///     let clk = Clk::get(dev, None)?;
> +    ///     clk.prepare_enable()?;
> +    ///     clk.rate_exclusive_get()
> +    /// }
> +    /// ```
> +    ///
> +    /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html

Unused link.

> +    pub struct ExclusiveClk(Clk);
> +
> +    // Make [`ExclusiveClk`] behave like [`Clk`].
> +    impl Deref for ExclusiveClk {
> +        type Target = Clk;
> +
> +        fn deref(&self) -> &Clk {
> +            &self.0
> +        }
> +    }
> +
> +    impl Drop for ExclusiveClk {
> +        fn drop(&mut self) {
> +            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> +            // [`clk_rate_exclusive_put`] and balances the [`clk_rate_exclusive_get`] call from
> +            // [`Clk::rate_exclusive_get`].
> +            unsafe {
> +                bindings::clk_rate_exclusive_put(self.as_raw());
> +            }

Nit: usually we format this with the semicolon outside the unsafe block.

unsafe { bindings::clk_rate_exclusive_put(self.as_raw()) };

Alice


From aliceryhl at google.com  Thu Jun  4 04:17:40 2026
From: aliceryhl at google.com (Alice Ryhl)
Date: Thu, 4 Jun 2026 11:17:40 +0000
Subject: [PATCH 2/2] pwm: th1520: Lock clock rate with clk_rate_exclusive_get
In-Reply-To: <20260526-rate-exclusive-get-th1520-v1-2-34cf034e1764@mailbox.org>
References: <20260526-rate-exclusive-get-th1520-v1-0-34cf034e1764@mailbox.org> <20260526-rate-exclusive-get-th1520-v1-2-34cf034e1764@mailbox.org>
Message-ID: <aiFe1NSoQDs1YOj_@google.com>

On Tue, May 26, 2026 at 07:04:58PM +0200, Maurice Hieronymus via B4 Relay wrote:
> From: Maurice Hieronymus <mhi at mailbox.org>
> 
> The driver derives period and duty cycle from the clock rate read at
> probe, so a later rate change would silently miscompute waveforms.
> Switch to the new ExclusiveClk wrapper to hold the rate for the lifetime
> of the driver data and drop the corresponding TODO.
> 
> Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>

Reviewed-by: Alice Ryhl <aliceryhl at google.com>


From lukas.schmid at netcube.li  Thu Jun  4 04:52:31 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Thu,  4 Jun 2026 13:52:31 +0200
Subject: [PATCH v1 0/3] Add support for NetCube Systems OpenNMC (dobermann)
Message-ID: <20260604115241.1358528-1-lukas.schmid@netcube.li>

This series adds support for the NetCube Systems OpenNMC

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
Lukas Schmid (3):
  dt-bindings: arm: sunxi: Add NetCube Systems OpenNMC (dobermann)
  riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube
    Systems OpenNMC
  ARM: dts: sunxi: add support for NetCube Systems OpenNMC (dobermann)

 .../devicetree/bindings/arm/sunxi.yaml        |   1 +
 .../sun8i-t113s-netcube-dobermann.dts         | 149 ++++++++++++++++++
 .../boot/dts/allwinner/sunxi-d1s-t113.dtsi    |   6 +
 3 files changed, 156 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts

-- 
2.47.3




From lukas.schmid at netcube.li  Thu Jun  4 04:52:32 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Thu,  4 Jun 2026 13:52:32 +0200
Subject: [PATCH v1 1/3] dt-bindings: arm: sunxi: Add NetCube Systems OpenNMC (dobermann)
In-Reply-To: <20260604115241.1358528-1-lukas.schmid@netcube.li>
References: <20260604115241.1358528-1-lukas.schmid@netcube.li>
Message-ID: <20260604115241.1358528-2-lukas.schmid@netcube.li>

The OpenNMC is an open replacement for APC SmartSlot management cards
based on the Nagami System-on-Module.

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 Documentation/devicetree/bindings/arm/sunxi.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
index e6443c266fa1..8e2c9b8fe121 100644
--- a/Documentation/devicetree/bindings/arm/sunxi.yaml
+++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
@@ -600,6 +600,7 @@ properties:
           - enum:
               - netcube,nagami-basic-carrier
               - netcube,nagami-keypad-carrier
+              - netcube,dobermann
           - const: netcube,nagami
           - const: allwinner,sun8i-t113s
 
-- 
2.47.3




From lukas.schmid at netcube.li  Thu Jun  4 04:52:33 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Thu,  4 Jun 2026 13:52:33 +0200
Subject: [PATCH v1 2/3] riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube Systems OpenNMC
In-Reply-To: <20260604115241.1358528-1-lukas.schmid@netcube.li>
References: <20260604115241.1358528-1-lukas.schmid@netcube.li>
Message-ID: <20260604115241.1358528-3-lukas.schmid@netcube.li>

Added the "uart4_pb_pins" pinctrl used by the OpenNMC

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
index 82cc85acccb1..00fddedfa36f 100644
--- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
+++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
@@ -191,6 +191,12 @@ uart3_pb_pins: uart3-pb-pins {
 				pins = "PB6", "PB7";
 				function = "uart3";
 			};
+
+			/omit-if-no-ref/
+			uart4_pb_pins: uart4-pb-pins {
+				pins = "PB2", "PB3";
+				function = "uart4";
+			};
 		};
 
 		ccu: clock-controller at 2001000 {
-- 
2.47.3




From lukas.schmid at netcube.li  Thu Jun  4 04:52:34 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Thu,  4 Jun 2026 13:52:34 +0200
Subject: [PATCH v1 3/3] ARM: dts: sunxi: add support for NetCube Systems OpenNMC (dobermann)
In-Reply-To: <20260604115241.1358528-1-lukas.schmid@netcube.li>
References: <20260604115241.1358528-1-lukas.schmid@netcube.li>
Message-ID: <20260604115241.1358528-4-lukas.schmid@netcube.li>

NetCube Systems OpenNMC is an open replacement for APC SmartSlot Management
Cards. It is based on the Nagami System-on-Module. It breaks out the
following interfaces:

- 10/100 Mbps Ethernet
- USB Type-C OTG using a TUSB320 (usb0)
- USB Type-C Console Port using a CH340 (uart3)
- USB Type-A Host with internal CH334 USB-Hub (usb1)
- MicroSD Slot with Card-Detect (mmc0)
- WiFi/Bluetooth using the modules built-in ESP32
- SmartSlot serial interface (uart4)
- DS3232 RTC with CR1220 Battery Backup
- Extension connector providing SPI,I2C,USB,CAN,UART for future use.

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 .../sun8i-t113s-netcube-dobermann.dts         | 149 ++++++++++++++++++
 1 file changed, 149 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts

diff --git a/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts b/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
new file mode 100644
index 000000000000..97dd4b950dd8
--- /dev/null
+++ b/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2026 Lukas Schmid <lukas.schmid at netcube.li>
+ */
+
+/dts-v1/;
+#include "sun8i-t113s-netcube-nagami.dtsi"
+
+#include <dt-bindings/leds/common.h>
+
+/ {
+	model = "NetCube Systems OpenNMC (dobermann)";
+	compatible = "netcube,dobermann", "netcube,nagami",
+		     "allwinner,sun8i-t113s";
+
+	aliases {
+		serial2 = &uart4; // UART on SmartSlot
+		rtc0 = &ds3232;
+		rtc1 = &rtc; // not battery backed
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led_heartbeat_green: led-heartbeat-green {
+			gpios = <&pio 6 14 GPIO_ACTIVE_HIGH>; /* PG14 */
+			linux,default-trigger = "heartbeat";
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_HEARTBEAT;
+		};
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+
+	tusb320: typec at 60 {
+		compatible = "ti,tusb320";
+		reg = <0x60>;
+		interrupts-extended = <&pio 3 22 IRQ_TYPE_LEVEL_LOW>;  /* PD22 */
+	};
+
+	ds3232: rtc at 68 {
+		compatible = "dallas,ds3232";
+		reg = <0x68>;
+	};
+};
+
+/* microSD Card Slot on the board */
+&mmc0 {
+	vmmc-supply = <&reg_vcc3v3>;
+	disable-wp;
+	bus-width = <4>;
+	cd-gpios = <&pio 6 15 GPIO_ACTIVE_LOW>; /* PG15 */
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&pio {
+	gpio-line-names = "", "", "", "", // PA
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "SMART_TX", "SMART_RX", // PB
+			  "EXT_IO3", "EXT_IO2", "CONSOLE_TX", "CONSOLE_RX",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "eMMC_CLK", "eMMC_CMD", // PC
+			  "eMMC_D2", "eMMC_D1", "eMMC_D0", "eMMC_D3",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "", // PD
+			  "", "", "", "",
+			  "", "USB_SEC_EN", "EXT_SPI_nCS", "EXT_SPI_SCK",
+			  "EXT_SPI_MOSI", "EXT_SPI_MISO", "EXT_IO5", "EXT_IO4",
+			  "SMART_SEL", "", "", "",
+			  "I2C3_SCL", "I2C3_SDA", "TUSB320_nINT", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "ETH_CRSDV", "ETH_RXD0", "ETH_RXD1", "ETH_TXCK", // PE
+			  "ETH_TXD0", "ETH_TXD1", "ETH_TXEN", "",
+			  "ETH_MDC", "ETH_MDIO", "I2C3_nINT", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "uSD_D1", "uSD_D0", "uSD_CLK", "uSD_CLK", // PF
+			  "uSD_D3", "uSD_D2", "TUSB320_ID", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "ESP_CLK", "ESP_CMD", "ESP_D0", "ESP_D1", // PG
+			  "ESP_D2", "ESP_D3", "ESP_TXD", "ESP_RXD",
+			  "ESP_nBOOT", "ESP_nRST", "I2C2_SCL", "I2C2_SDA",
+			  "EXT_IO1", "EXT_IO0", "LED_HEARTBEAT", "SD_DETECT",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "";
+};
+
+/* SmartSlot serial */
+&uart4 {
+	pinctrl-0 = <&uart4_pb_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usb_otg {
+	extcon = <&tusb320 0>;
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usbphy {
+	usb0_id_det-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	status = "okay";
+};
-- 
2.47.3




From krzk at kernel.org  Thu Jun  4 05:46:44 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 4 Jun 2026 14:46:44 +0200
Subject: [PATCH v1 1/3] dt-bindings: arm: sunxi: Add NetCube Systems
 OpenNMC (dobermann)
In-Reply-To: <20260604115241.1358528-2-lukas.schmid@netcube.li>
References: <20260604115241.1358528-1-lukas.schmid@netcube.li>
 <20260604115241.1358528-2-lukas.schmid@netcube.li>
Message-ID: <0967fc45-20cf-4181-a607-2474099c5291@kernel.org>

On 04/06/2026 13:52, Lukas Schmid wrote:
> The OpenNMC is an open replacement for APC SmartSlot management cards
> based on the Nagami System-on-Module.
> 
> Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
> ---
>  Documentation/devicetree/bindings/arm/sunxi.yaml | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
> index e6443c266fa1..8e2c9b8fe121 100644
> --- a/Documentation/devicetree/bindings/arm/sunxi.yaml
> +++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
> @@ -600,6 +600,7 @@ properties:
>            - enum:
>                - netcube,nagami-basic-carrier
>                - netcube,nagami-keypad-carrier
> +              - netcube,dobermann

Don't break alphabetical order.


Best regards,
Krzysztof


From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:10 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:10 +0800
Subject: [PATCH v3 1/9] riscv: kexec: Reset executable bit on the control code page in cleanup
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-2-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

machine_kexec_prepare() calls set_memory_x() on the per-image
control_code_page so the relocate stub copied into it can be executed
during a normal kexec. machine_kexec_cleanup() is empty, so when the
image is freed (via kexec -u, or because a later step in load failed)
the page is returned to the buddy allocator with its executable bit
still set. Once the page is reallocated for arbitrary kernel data,
the W^X invariant is broken: a writable page also marked executable.

Implement the architecture cleanup hook to call set_memory_nx() on
the control code page for non-crash images, mirroring the
set_memory_x() in prepare().

The crash path does not call set_memory_x() (the crash kernel is
loaded into the reserved crashkernel region whose pages are not in
the buddy allocator) and so does not need the cleanup.

Fixes: fba8a8674f68 ("RISC-V: Add kexec support")
Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/kernel/machine_kexec.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index 2306ce3e5f22..ea6794c9f4c2 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -91,6 +91,19 @@ machine_kexec_prepare(struct kimage *image)
 void
 machine_kexec_cleanup(struct kimage *image)
 {
+	void *control_code_buffer;
+
+	if (image->type == KEXEC_TYPE_CRASH || !image->control_code_page)
+		return;
+
+	/*
+	 * machine_kexec_prepare() called set_memory_x() on the control
+	 * code page for non-crash images. Revert it before kimage_free()
+	 * returns the page to the buddy allocator, so we do not leak an
+	 * executable page back into general allocation.
+	 */
+	control_code_buffer = page_address(image->control_code_page);
+	set_memory_nx((unsigned long)control_code_buffer, 1);
 }
 
 
-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:11 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:11 +0800
Subject: [PATCH v3 2/9] riscv: kexec: Bound FDT search by source buffer size, not destination
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-3-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

The FDT search loop in machine_kexec_prepare() reads sizeof(fdt) bytes
from segment[i].buf to identify the device tree, but it gates the read
on segment[i].memsz, which is the destination size in the next kernel.
kexec allows bufsz < memsz (the loaded image is zero-padded at the
destination), so a caller can craft a segment with bufsz=10 and
memsz=1MB:

	if (image->segment[i].memsz <= sizeof(fdt))   /* 1MB > 40, OK */
		continue;
	memcpy(&fdt, image->segment[i].buf, sizeof(fdt));  /* reads 40
							      from a 10-byte
							      kbuf */

For kexec_file_load (image->file_mode), the read walks 30 bytes past
the kernel-allocated kbuf. In the worst case the trailing bytes fall
in an unmapped guard page and the read faults the kernel; in the
common case the read returns garbage which fdt_check_header() rejects
and the loop continues. The plain kexec_load path is shielded by
copy_from_user(), which validates the read against the user mapping.

Replace the memsz check with the bufsz check, which is the right
bound for the read site.

Fixes: fba8a8674f68 ("RISC-V: Add kexec support")
Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/kernel/machine_kexec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index ea6794c9f4c2..e6e179cffc44 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -38,7 +38,7 @@ machine_kexec_prepare(struct kimage *image)
 
 	/* Find the Flattened Device Tree and save its physical address */
 	for (i = 0; i < image->nr_segments; i++) {
-		if (image->segment[i].memsz <= sizeof(fdt))
+		if (image->segment[i].bufsz < sizeof(fdt))
 			continue;
 
 		if (image->file_mode)
-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:12 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:12 +0800
Subject: [PATCH v3 3/9] riscv: Add kexec trampoline text section to vmlinux.lds.S
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-4-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

When CONFIG_KEXEC_CORE is enabled, add a dedicated .kexec.tramp.text
area to the RISC-V kernel linker script.

Extend vmlinux.lds.S to:
  - align both the start and the end to PAGE_SIZE
  - define __kexec_tramp_text_start/__kexec_tramp_text_end
  - KEEP all .kexec.tramp.text* input sections
  - ASSERT the trampoline text fits within one page

The end-of-section page alignment guarantees that the trampoline page,
which is later identity-mapped as PAGE_KERNEL_EXEC, contains nothing but
the trampoline code and padding (no shared neighbour data).

When kexec is disabled, the whole block is excluded via #ifdef
CONFIG_KEXEC_CORE.

Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/kernel/vmlinux.lds.S | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/riscv/kernel/vmlinux.lds.S b/arch/riscv/kernel/vmlinux.lds.S
index 1f4f8496941a..bc615f7b702f 100644
--- a/arch/riscv/kernel/vmlinux.lds.S
+++ b/arch/riscv/kernel/vmlinux.lds.S
@@ -41,6 +41,16 @@ SECTIONS
 		ENTRY_TEXT
 		IRQENTRY_TEXT
 		SOFTIRQENTRY_TEXT
+#ifdef CONFIG_KEXEC_CORE
+		. = ALIGN(PAGE_SIZE);
+		__kexec_tramp_text_start = .;
+		KEEP(*(.kexec.tramp.text))
+		KEEP(*(.kexec.tramp.text.*))
+		__kexec_tramp_text_end = .;
+		ASSERT((__kexec_tramp_text_end - __kexec_tramp_text_start) <= PAGE_SIZE,
+		       ".kexec.tramp.text exceeds PAGE_SIZE");
+		. = ALIGN(PAGE_SIZE);
+#endif
 		_etext = .;
 	}
 
-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:09 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:09 +0800
Subject: [PATCH v3 0/9] riscv: kexec: Make kexec/kdump robust under VS-mode
Message-ID: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

In a RISC-V kernel, both kexec and crashdump need to hand off execution
to the next kernel after tearing down the current kernel address space.
However, under virtualization the guest uses two-stage address
translation, and pc does not jump to stvec after setting satp to zero,
so the legacy single-step "csrw satp,0 + stvec redirect" sequence
traps with "kvm run failed Operation not supported" and the VCPU dies.

This patch set introduces a dedicated kexec trampoline text section and
builds a minimal trampoline page table for it. Both handoffs are then
reworked into a two-pass trampoline:

    1. First enter via the kernel VA, install the trampoline page table,
       and jump to the trampoline VA(=PA) of the entry stub;
    2. Continue execution with PC already on a PA, drop SATP with
       csrw satp,0 (now safe because PC re-anchoring is moot), and
       jump directly to the target -- either the crash kernel entry
       (crash path) or the per-image control_code_buffer that runs
       the relocate body with SATP=0 throughout (normal path).

With this, both kexec and crashdump in RISC-V guests become robust
against the two-stage translation.

Tested on QEMU virt under two configurations:

  * HS-mode bare (QEMU TCG) -- regression check
      - normal kexec: kexec -l/-e succeeds, second kernel boots and
                      prints the userspace SECOND BOOT marker.
      - crash kdump: panic triggers crash kernel boot, /proc/vmcore
                     opens cleanly in crash(1) and shows the panic
                     backtrace.

  * VS-mode (L0 x86 + QEMU TCG -> L1 riscv64 + KVM -> L2)
      Before this series, both paths die with
          kvm run failed Operation not supported
      and an all-zero M-mode register dump on the SATP transition.
      After this series, both paths succeed end-to-end and the
      vmcore opens cleanly in crash.

---
Changes in v3 (Sashiko AI review):
    - Add two new Fixes: patches at the start of the series:
      #1: machine_kexec_cleanup() was empty, so the set_memory_x()
          call in prepare() leaked an executable direct-map page back
          to the buddy allocator on kexec -u (W^X bypass). Fix: add
          set_memory_nx() in cleanup.
      #2: machine_kexec_prepare() FDT search checked
          memsz <= sizeof(fdt) but read sizeof(fdt) bytes from
          segment[i].buf, which can be smaller than memsz. Fix: check
          bufsz instead.
    - Inline the .kexec.tramp.text section definition directly into
      vmlinux.lds.S instead of using a macro in image-vars.h.
    - Rewrite map_tramp_page() to share a single set of lower-level
      page tables between the VA and PA mappings (5 BSS pages instead
      of 9), with a collision-safe walker that only populates entries
      still zero. Add Sv32 support.
    - Link to v2:
      https://lore.kernel.org/linux-riscv/20260526125009.2404-1-fangyu.yu at linux.alibaba.com/
    - Link to v1:
      https://lore.kernel.org/linux-riscv/20260324114527.91494-1-fangyu.yu at linux.alibaba.com/


Fangyu Yu (9):
  riscv: kexec: Reset executable bit on the control code page in cleanup
  riscv: kexec: Bound FDT search by source buffer size, not destination
  riscv: Add kexec trampoline text section to vmlinux.lds.S
  riscv: kexec: Place norelocate trampoline into .kexec.tramp.text
  riscv: kexec: Build trampoline page tables for crash kernel entry
  riscv: kexec: Switch to trampoline page table before norelocate
  riscv: kexec: Always build the trampoline page table
  riscv: kexec: Add the relocate-trampoline wrapper
  riscv: kexec: Route normal kexec through the trampoline page table

 arch/riscv/include/asm/kexec.h     |   5 +
 arch/riscv/kernel/kexec_relocate.S |  92 +++++++++++-----
 arch/riscv/kernel/machine_kexec.c  | 171 +++++++++++++++++++++++++++--
 arch/riscv/kernel/vmlinux.lds.S    |  10 ++
 4 files changed, 241 insertions(+), 37 deletions(-)

-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:13 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:13 +0800
Subject: [PATCH v3 4/9] riscv: kexec: Place norelocate trampoline into .kexec.tramp.text
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-5-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

Move riscv_kexec_norelocate out of the generic .text section and into
a dedicated executable trampoline section, .kexec.tramp.text.

Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/include/asm/kexec.h     | 4 ++++
 arch/riscv/kernel/kexec_relocate.S | 2 +-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h
index b9ee8346cc8c..6466c1f00d41 100644
--- a/arch/riscv/include/asm/kexec.h
+++ b/arch/riscv/include/asm/kexec.h
@@ -75,4 +75,8 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start,
 			unsigned long cmdline_len);
 #endif
 
+#ifndef __ASSEMBLY__
+extern char __kexec_tramp_text_start[];
+#endif
+
 #endif
diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S
index de0a4b35d01e..af6b99f5b0fd 100644
--- a/arch/riscv/kernel/kexec_relocate.S
+++ b/arch/riscv/kernel/kexec_relocate.S
@@ -147,7 +147,7 @@ riscv_kexec_relocate_end:
 
 
 /* Used for jumping to crashkernel */
-.section ".text"
+.section ".kexec.tramp.text", "ax"
 SYM_CODE_START(riscv_kexec_norelocate)
 	/*
 	 * s0: (const) Phys address to jump to
-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:16 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:16 +0800
Subject: [PATCH v3 7/9] riscv: kexec: Always build the trampoline page table
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-8-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

The trampoline page table and the kexec_tramp_satp value are
currently built only on the crash path. A follow-up patch needs
the same infrastructure for the normal kexec path.

Pull the trampoline build and the WRITE_ONCE() that publishes the
SATP value out of the crash-only else branch in
machine_kexec_prepare(). The crash path keeps recording its own
riscv_kexec_norelocate_pa; the normal path keeps its existing
control_code_buffer copy.

No functional change.

Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/kernel/machine_kexec.c | 21 ++++++++++-----------
 1 file changed, 10 insertions(+), 11 deletions(-)

diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index 72817bba5d3b..d82f45fb44b6 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -139,6 +139,16 @@ machine_kexec_prepare(struct kimage *image)
 		return -EINVAL;
 	}
 
+	/*
+	 * Build the trampoline page table and capture its SATP value.
+	 * The crash path consumes it today; the non-crash kexec path
+	 * will use the same setup as well.
+	 */
+	riscv_kexec_build_tramp((unsigned long)__kexec_tramp_text_start,
+				__pa_symbol(__kexec_tramp_text_start));
+	WRITE_ONCE(kexec_tramp_satp,
+		   PFN_DOWN(__pa_symbol(kexec_tramp_pgd)) | satp_mode);
+
 	/* Copy the assembler code for relocation to the control page */
 	if (image->type != KEXEC_TYPE_CRASH) {
 		control_code_buffer = page_address(image->control_code_page);
@@ -155,19 +165,8 @@ machine_kexec_prepare(struct kimage *image)
 		/* Mark the control page executable */
 		set_memory_x((unsigned long) control_code_buffer, 1);
 	} else {
-		/*
-		 * Crash kexec uses riscv_kexec_norelocate as a trampoline.
-		 * Pre-build the trampoline page tables and capture the
-		 * trampoline SATP value plus the physical address of
-		 * riscv_kexec_norelocate so that the panic path only has
-		 * to switch satp and jump.
-		 */
-		riscv_kexec_build_tramp((unsigned long)__kexec_tramp_text_start,
-					__pa_symbol(__kexec_tramp_text_start));
 		WRITE_ONCE(riscv_kexec_norelocate_pa,
 			   __pa_symbol(&riscv_kexec_norelocate));
-		WRITE_ONCE(kexec_tramp_satp,
-			   PFN_DOWN(__pa_symbol(kexec_tramp_pgd)) | satp_mode);
 	}
 
 	return 0;
-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:14 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:14 +0800
Subject: [PATCH v3 5/9] riscv: kexec: Build trampoline page tables for crash kernel entry
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-6-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

Crash kexec uses riscv_kexec_norelocate as a trampoline to jump into
the crashkernel. Pre-build dedicated 4 KB page tables in
machine_kexec_prepare() that map the trampoline page as executable,
so the panic path only has to switch satp and jump.

Two mappings are installed into a shared pgd:
  - VA(__kexec_tramp_text_start) -> PA(__kexec_tramp_text_start)
  - PA(__kexec_tramp_text_start) -> PA(__kexec_tramp_text_start)

The lower-level tables (p4d/pud/pmd/pte) are shared between both
mappings; map_tramp_page() walks the existing tree and only
populates entries that are still zero, so the two installs coexist
even when their indices happen to collide at any level.

Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/kernel/machine_kexec.c | 87 +++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index e6e179cffc44..1947b7bdf5c4 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -18,6 +18,85 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 
+/*
+ * Trampoline page tables. Both the VA(trampoline)->PA and the
+ * PA(trampoline)->PA identity mapping are installed in this single
+ * pgd; the lower-level tables are shared so the two mappings can
+ * coexist even if they happen to collide at any level (the walker
+ * only populates entries that are still zero).
+ *
+ * Pre-allocate for the largest paging mode (Sv57). Levels that the
+ * runtime mode does not use simply waste a page or two of BSS, in
+ * exchange for a builder that is infallible and safe to run from
+ * the panic path.
+ */
+static pgd_t kexec_tramp_pgd[PTRS_PER_PGD] __aligned(PAGE_SIZE);
+#ifdef CONFIG_64BIT
+static p4d_t kexec_tramp_p4d[PTRS_PER_P4D] __aligned(PAGE_SIZE);
+static pud_t kexec_tramp_pud[PTRS_PER_PUD] __aligned(PAGE_SIZE);
+static pmd_t kexec_tramp_pmd[PTRS_PER_PMD] __aligned(PAGE_SIZE);
+#endif
+static pte_t kexec_tramp_pte[PTRS_PER_PTE] __aligned(PAGE_SIZE);
+
+static void map_tramp_page(unsigned long va, unsigned long pa)
+{
+	pgd_t *pgd = kexec_tramp_pgd + pgd_index(va);
+
+#ifdef CONFIG_64BIT
+	p4d_t *p4d;
+	pud_t *pud;
+	pmd_t *pmd;
+
+	if (pgtable_l5_enabled) {
+		if (pgd_val(*pgd) == 0)
+			set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa_symbol(kexec_tramp_p4d)),
+					     PAGE_TABLE));
+		p4d = kexec_tramp_p4d + p4d_index(va);
+	} else {
+		p4d = (p4d_t *)pgd;
+	}
+
+	if (pgtable_l4_enabled) {
+		if (p4d_val(*p4d) == 0)
+			set_p4d(p4d, pfn_p4d(PFN_DOWN(__pa_symbol(kexec_tramp_pud)),
+					     PAGE_TABLE));
+		pud = kexec_tramp_pud + pud_index(va);
+	} else {
+		pud = (pud_t *)p4d;
+	}
+
+	if (pud_val(*pud) == 0)
+		set_pud(pud, pfn_pud(PFN_DOWN(__pa_symbol(kexec_tramp_pmd)),
+				     PAGE_TABLE));
+	pmd = kexec_tramp_pmd + pmd_index(va);
+
+	if (pmd_val(*pmd) == 0)
+		set_pmd(pmd, pfn_pmd(PFN_DOWN(__pa_symbol(kexec_tramp_pte)),
+				     PAGE_TABLE));
+#else
+	/* Sv32: PGD points directly to the PTE table. */
+	if (pgd_val(*pgd) == 0)
+		set_pgd(pgd, pfn_pgd(PFN_DOWN(__pa_symbol(kexec_tramp_pte)),
+				     PAGE_TABLE));
+#endif
+
+	set_pte(kexec_tramp_pte + pte_index(va),
+		pfn_pte(PFN_DOWN(pa), PAGE_KERNEL_EXEC));
+}
+
+static void riscv_kexec_build_tramp(unsigned long va, unsigned long pa)
+{
+	/* VA -> PA: map the trampoline page via its kernel VA. */
+	map_tramp_page(va, pa);
+
+	/*
+	 * PA -> PA: identity-map the same page so the second-pass code
+	 * can keep executing after the kernel VA mapping is dropped.
+	 */
+	map_tramp_page(pa, pa);
+}
+
+
 /*
  * machine_kexec_prepare - Initialize kexec
  *
@@ -73,6 +152,14 @@ machine_kexec_prepare(struct kimage *image)
 
 		/* Mark the control page executable */
 		set_memory_x((unsigned long) control_code_buffer, 1);
+	} else {
+		/*
+		 * Crash kexec uses riscv_kexec_norelocate as a trampoline.
+		 * Pre-build the trampoline page tables here so the panic
+		 * path only has to switch satp and jump.
+		 */
+		riscv_kexec_build_tramp((unsigned long)__kexec_tramp_text_start,
+					__pa_symbol(__kexec_tramp_text_start));
 	}
 
 	return 0;
-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:15 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:15 +0800
Subject: [PATCH v3 6/9] riscv: kexec: Switch to trampoline page table before norelocate
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-7-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

Make riscv_kexec_norelocate a two-pass trampoline so it can
drop the kernel page tables while still executing from a
mapped address.

On the first entry, t3 is initialized to 0 by machine_kexec().
Loads the physical address of riscv_kexec_norelocate and the
trampoline SATP value, switches to the trampoline page table,
and jumps to the trampoline VA(=PA).

On the second entry, t3 contains the physical address of
riscv_kexec_norelocate, so the PC comparison matches and
execution continues under trampoline VA(=PA).

Since the trampoline page table is already active, replace the
previous stvec-based handoff with a direct jump to the target
entry (jr a2).

Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/kernel/kexec_relocate.S | 30 +++++++++++++++-----
 arch/riscv/kernel/machine_kexec.c  | 44 +++++++++++++++++++++++++++---
 2 files changed, 63 insertions(+), 11 deletions(-)

diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S
index af6b99f5b0fd..8cfdf6f4032a 100644
--- a/arch/riscv/kernel/kexec_relocate.S
+++ b/arch/riscv/kernel/kexec_relocate.S
@@ -147,13 +147,35 @@ riscv_kexec_relocate_end:
 
 
 /* Used for jumping to crashkernel */
+.extern kexec_tramp_satp
+.extern riscv_kexec_norelocate_pa
 .section ".kexec.tramp.text", "ax"
 SYM_CODE_START(riscv_kexec_norelocate)
+	/*
+	 * Two-pass entry:
+	 *   - 1st entry: t3 == 0 (initialized by machine_kexec()).
+	 *
+	 *   - 2nd entry: t3 holds the physical address of
+	 *     riscv_kexec_norelocate, so auipc matches t3 and we fall through
+	 *     to label 1 to continue execution under trampoline VA(=PA).
+	 */
+	auipc   t0, 0
+	beq     t0, t3, 1f
+
+	la      t0, riscv_kexec_norelocate_pa
+	REG_L   t3, 0(t0)
+	la      t0, kexec_tramp_satp
+	REG_L   t1, 0(t0)
+	csrw	CSR_SATP, t1
+	sfence.vma x0, x0
+
+	jr      t3
 	/*
 	 * s0: (const) Phys address to jump to
 	 * s1: (const) Phys address of the FDT image
 	 * s2: (const) The hartid of the current hart
 	 */
+1:
 	mv	s0, a1
 	mv	s1, a2
 	mv	s2, a3
@@ -198,14 +220,8 @@ SYM_CODE_START(riscv_kexec_norelocate)
 	csrw	CSR_SCAUSE, zero
 	csrw	CSR_SSCRATCH, zero
 
-	/*
-	 * Switch to physical addressing
-	 * This will also trigger a jump to CSR_STVEC
-	 * which in this case is the address of the new
-	 * kernel.
-	 */
-	csrw	CSR_STVEC, a2
 	csrw	CSR_SATP, zero
+	jr	a2
 
 SYM_CODE_END(riscv_kexec_norelocate)
 
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index 1947b7bdf5c4..72817bba5d3b 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -18,6 +18,8 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 
+unsigned long kexec_tramp_satp;
+unsigned long riscv_kexec_norelocate_pa;
 /*
  * Trampoline page tables. Both the VA(trampoline)->PA and the
  * PA(trampoline)->PA identity mapping are installed in this single
@@ -155,11 +157,17 @@ machine_kexec_prepare(struct kimage *image)
 	} else {
 		/*
 		 * Crash kexec uses riscv_kexec_norelocate as a trampoline.
-		 * Pre-build the trampoline page tables here so the panic
-		 * path only has to switch satp and jump.
+		 * Pre-build the trampoline page tables and capture the
+		 * trampoline SATP value plus the physical address of
+		 * riscv_kexec_norelocate so that the panic path only has
+		 * to switch satp and jump.
 		 */
 		riscv_kexec_build_tramp((unsigned long)__kexec_tramp_text_start,
 					__pa_symbol(__kexec_tramp_text_start));
+		WRITE_ONCE(riscv_kexec_norelocate_pa,
+			   __pa_symbol(&riscv_kexec_norelocate));
+		WRITE_ONCE(kexec_tramp_satp,
+			   PFN_DOWN(__pa_symbol(kexec_tramp_pgd)) | satp_mode);
 	}
 
 	return 0;
@@ -276,7 +284,35 @@ machine_kexec(struct kimage *image)
 
 	/* Jump to the relocation code */
 	pr_notice("Bye...\n");
-	kexec_method(first_ind_entry, jump_addr, fdt_addr,
-		     this_hart_id, kernel_map.va_pa_offset);
+	/*
+	 * Hand off to the trampoline. For KEXEC_TYPE_CRASH we go into
+	 * riscv_kexec_norelocate, which uses t3 as the 1st/2nd-pass
+	 * discriminator (must be 0 on first entry). A bare
+	 *   asm volatile ("li t3, 0" ::: "t3")
+	 * before the C call only declares t3 *modified*; the compiler is
+	 * free to use t3 as scratch when materialising args. Pin t3 = 0
+	 * (and the args) via local register variables and perform the
+	 * indirect jump inside the same inline asm so t3 == 0 is
+	 * guaranteed at the moment control leaves machine_kexec().
+	 */
+	{
+		register unsigned long a0_val asm("a0") = first_ind_entry;
+		register unsigned long a1_val asm("a1") = jump_addr;
+		register unsigned long a2_val asm("a2") = fdt_addr;
+		register unsigned long a3_val asm("a3") = this_hart_id;
+		register unsigned long a4_val asm("a4") = kernel_map.va_pa_offset;
+		register unsigned long t3_zero asm("t3") = 0;
+		register riscv_kexec_method m asm("t6") = kexec_method;
+
+		asm volatile (
+			"jr %[m]"
+			:
+			: "r" (a0_val), "r" (a1_val), "r" (a2_val),
+			  "r" (a3_val), "r" (a4_val),
+			  "r" (t3_zero),
+			  [m] "r" (m)
+			: "memory"
+		);
+	}
 	unreachable();
 }
-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:17 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:17 +0800
Subject: [PATCH v3 8/9] riscv: kexec: Add the relocate-trampoline wrapper
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-9-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

Add riscv_kexec_relocate_entry to .kexec.tramp.text and the two
asm-visible globals (riscv_kexec_relocate_entry_pa and
riscv_kexec_cc_buffer_pa) that the wrapper consumes.

The wrapper performs the same two-step transition used by the crash
path: switch to the trampoline pgd, jump to the PA of self, then drop
the MMU with PC already on a PA. It finally jumps to the PA of
control_code_buffer.

machine_kexec_prepare() publishes the wrapper PA via WRITE_ONCE for
non-crash images. The per-image control_code_buffer PA is published
later, at dispatch time, so a load failure between prepare() and the
kexec_image swap cannot leave the global pointing at a freed page.
Nothing routes to the wrapper yet; the switchover happens in the
follow-up patch.

Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/include/asm/kexec.h     |  1 +
 arch/riscv/kernel/kexec_relocate.S | 36 ++++++++++++++++++++++++++++++
 arch/riscv/kernel/machine_kexec.c  |  5 +++++
 3 files changed, 42 insertions(+)

diff --git a/arch/riscv/include/asm/kexec.h b/arch/riscv/include/asm/kexec.h
index 6466c1f00d41..b75cab959e53 100644
--- a/arch/riscv/include/asm/kexec.h
+++ b/arch/riscv/include/asm/kexec.h
@@ -53,6 +53,7 @@ typedef void (*riscv_kexec_method)(unsigned long first_ind_entry,
 				   unsigned long va_pa_off);
 
 extern riscv_kexec_method riscv_kexec_norelocate;
+extern riscv_kexec_method riscv_kexec_relocate_entry;
 
 #ifdef CONFIG_KEXEC_FILE
 extern const struct kexec_file_ops elf_kexec_ops;
diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S
index 8cfdf6f4032a..6c624560c9ac 100644
--- a/arch/riscv/kernel/kexec_relocate.S
+++ b/arch/riscv/kernel/kexec_relocate.S
@@ -225,6 +225,42 @@ SYM_CODE_START(riscv_kexec_norelocate)
 
 SYM_CODE_END(riscv_kexec_norelocate)
 
+.extern riscv_kexec_relocate_entry_pa
+.extern riscv_kexec_cc_buffer_pa
+.section ".kexec.tramp.text", "ax"
+SYM_CODE_START(riscv_kexec_relocate_entry)
+	/*
+	 * Two-pass entry, identical in shape to riscv_kexec_norelocate:
+	 *   - 1st entry: t3 == 0 (initialized by machine_kexec()).
+	 *   - 2nd entry: t3 == PA of riscv_kexec_relocate_entry, so auipc
+	 *                matches t3 and we fall through to label 1.
+	 * Args a0..a4 are passed through unchanged to riscv_kexec_relocate.
+	 */
+	auipc	t0, 0
+	beq	t0, t3, 1f
+
+	la	t0, riscv_kexec_relocate_entry_pa
+	REG_L	t3, 0(t0)
+	la	t0, kexec_tramp_satp
+	REG_L	t1, 0(t0)
+	csrw	CSR_SATP, t1
+	sfence.vma x0, x0
+
+	jr	t3
+1:
+	/*
+	 * Now executing at the PA of this wrapper with the trampoline pgd
+	 * installed (identity-mapped). Drop the MMU; PC stays valid because
+	 * it is already a PA.
+	 */
+	csrw	CSR_SATP, zero
+
+	/* Jump to the PA of control_code_buffer to run the relocate body. */
+	la	t0, riscv_kexec_cc_buffer_pa
+	REG_L	t0, 0(t0)
+	jr	t0
+SYM_CODE_END(riscv_kexec_relocate_entry)
+
 .section ".rodata"
 SYM_DATA(riscv_kexec_relocate_size,
 	.long riscv_kexec_relocate_end - riscv_kexec_relocate)
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index d82f45fb44b6..71688c63af65 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -20,6 +20,8 @@
 
 unsigned long kexec_tramp_satp;
 unsigned long riscv_kexec_norelocate_pa;
+unsigned long riscv_kexec_relocate_entry_pa;
+unsigned long riscv_kexec_cc_buffer_pa;
 /*
  * Trampoline page tables. Both the VA(trampoline)->PA and the
  * PA(trampoline)->PA identity mapping are installed in this single
@@ -164,6 +166,9 @@ machine_kexec_prepare(struct kimage *image)
 
 		/* Mark the control page executable */
 		set_memory_x((unsigned long) control_code_buffer, 1);
+
+		WRITE_ONCE(riscv_kexec_relocate_entry_pa,
+			   __pa_symbol(&riscv_kexec_relocate_entry));
 	} else {
 		WRITE_ONCE(riscv_kexec_norelocate_pa,
 			   __pa_symbol(&riscv_kexec_norelocate));
-- 
2.50.1



From fangyu.yu at linux.alibaba.com  Thu Jun  4 06:24:18 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Thu,  4 Jun 2026 21:24:18 +0800
Subject: [PATCH v3 9/9] riscv: kexec: Route normal kexec through the trampoline page table
In-Reply-To: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
References: <20260604132418.15725-1-fangyu.yu@linux.alibaba.com>
Message-ID: <20260604132418.15725-10-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

riscv_kexec_relocate (copied into control_code_buffer) uses an stvec
trick to drop the MMU and land on the PA of the next loop label.
Under VS-mode KVM cannot emulate this single-step transition and the
VCPU dies with "kvm run failed Operation not supported".

Route normal kexec through riscv_kexec_relocate_entry, the trampoline
wrapper added in the previous patch. It drops SATP with PC already on
a PA, then hands off to control_code_buffer where the relocate body
runs with SATP=0.

Drop the stvec trick from the relocate body and pass first_ind_entry
as a physical address since the body now starts with SATP=0. The
".align 2" plus filler "nop" that ensured the PA of the loop top was
4-byte aligned -- required because the legacy stvec trick wrote that
PA into stvec.BASE, whose low two bits are MODE and are discarded by
the hardware -- is no longer load-bearing and is removed as well.

Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/kernel/kexec_relocate.S | 26 ++++++--------------------
 arch/riscv/kernel/machine_kexec.c  | 27 +++++++++++++++++++--------
 2 files changed, 25 insertions(+), 28 deletions(-)

diff --git a/arch/riscv/kernel/kexec_relocate.S b/arch/riscv/kernel/kexec_relocate.S
index 6c624560c9ac..7ffb83ea45fc 100644
--- a/arch/riscv/kernel/kexec_relocate.S
+++ b/arch/riscv/kernel/kexec_relocate.S
@@ -34,27 +34,13 @@ SYM_CODE_START(riscv_kexec_relocate)
 	csrw	CSR_SIP, zero
 
 	/*
-	 * When we switch SATP.MODE to "Bare" we'll only
-	 * play with physical addresses. However the first time
-	 * we try to jump somewhere, the offset on the jump
-	 * will be relative to pc which will still be on VA. To
-	 * deal with this we set stvec to the physical address at
-	 * the start of the loop below so that we jump there in
-	 * any case.
+	 * The trampoline wrapper (riscv_kexec_relocate_entry) has already
+	 * dropped the MMU and handed control to us at this PA copy of the
+	 * relocate code. From here on the entire loop runs with SATP=0 and
+	 * every address (s0, s5, source/dest pointers) is a physical one.
 	 */
-	la	s6, 1f
-	sub	s6, s6, s4
-	csrw	CSR_STVEC, s6
-
-	/*
-	 * With C-extension, here we get 42 Bytes and the next
-	 * .align directive would pad zeros here up to 44 Bytes.
-	 * So manually put a nop here to avoid zeros padding.
-	*/
-	nop
 
 	/* Process entries in a loop */
-.align 2
 1:
 	REG_L	t0, 0(s0)		/* t0 = *image->entry */
 	addi	s0, s0, RISCV_SZPTR	/* image->entry++ */
@@ -70,8 +56,8 @@ SYM_CODE_START(riscv_kexec_relocate)
 	andi	t1, t0, 0x2
 	beqz	t1, 2f
 	andi	s0, t0, ~0x2
-	csrw	CSR_SATP, zero
-	jr	s6
+	/* MMU is already off; the entry wrapper handled the transition. */
+	j	1b
 
 2:
 	/* IND_DONE entry ? -> jump to done label */
diff --git a/arch/riscv/kernel/machine_kexec.c b/arch/riscv/kernel/machine_kexec.c
index 71688c63af65..82fcb84a03ec 100644
--- a/arch/riscv/kernel/machine_kexec.c
+++ b/arch/riscv/kernel/machine_kexec.c
@@ -164,9 +164,6 @@ machine_kexec_prepare(struct kimage *image)
 		memcpy(control_code_buffer, riscv_kexec_relocate,
 			riscv_kexec_relocate_size);
 
-		/* Mark the control page executable */
-		set_memory_x((unsigned long) control_code_buffer, 1);
-
 		WRITE_ONCE(riscv_kexec_relocate_entry_pa,
 			   __pa_symbol(&riscv_kexec_relocate_entry));
 	} else {
@@ -262,11 +259,15 @@ machine_kexec(struct kimage *image)
 {
 	struct kimage_arch *internal = &image->arch;
 	unsigned long jump_addr = (unsigned long) image->start;
-	unsigned long first_ind_entry = (unsigned long) &image->head;
+	/*
+	 * The relocate body runs entirely with the MMU off (the wrapper
+	 * drops SATP before jumping into control_code_buffer), so the very
+	 * first entry must be a physical address.
+	 */
+	unsigned long first_ind_entry = __pa(&image->head);
 	unsigned long this_cpu_id = __smp_processor_id();
 	unsigned long this_hart_id = cpuid_to_hartid_map(this_cpu_id);
 	unsigned long fdt_addr = internal->fdt_addr;
-	void *control_code_buffer = page_address(image->control_code_page);
 	riscv_kexec_method kexec_method = NULL;
 
 #ifdef CONFIG_SMP
@@ -274,10 +275,20 @@ machine_kexec(struct kimage *image)
 		"Some CPUs may be stale, kdump will be unreliable.\n");
 #endif
 
-	if (image->type != KEXEC_TYPE_CRASH)
-		kexec_method = control_code_buffer;
-	else
+	if (image->type != KEXEC_TYPE_CRASH) {
+		kexec_method = (riscv_kexec_method) &riscv_kexec_relocate_entry;
+		/*
+		 * Publish the per-image control_code_buffer PA at dispatch
+		 * time rather than in machine_kexec_prepare(). machine_kexec()
+		 * only runs once the image has been fully loaded and committed
+		 * as kexec_image, so the global cannot be left pointing at a
+		 * page freed by a failed load.
+		 */
+		WRITE_ONCE(riscv_kexec_cc_buffer_pa,
+			   __pa(page_address(image->control_code_page)));
+	} else {
 		kexec_method = (riscv_kexec_method) &riscv_kexec_norelocate;
+	}
 
 	pr_notice("Will call new kernel at %08lx from hart id %lx\n",
 		  jump_addr, this_hart_id);
-- 
2.50.1



From tjytimi at 163.com  Thu Jun  4 07:26:01 2026
From: tjytimi at 163.com (Jinyu Tang)
Date: Thu,  4 Jun 2026 22:26:01 +0800
Subject: [PATCH v2 1/2] KVM: riscv: Check hugetlb block mappings against memslot bounds
In-Reply-To: <20260604142602.3582602-1-tjytimi@163.com>
References: <20260604142602.3582602-1-tjytimi@163.com>
Message-ID: <20260604142602.3582602-2-tjytimi@163.com>

RISC-V KVM has used the hugetlb VMA size directly as the G-stage
mapping size since stage-2 page table support was added. That is safe
only if the block covered by the fault is fully contained in the
memslot and the userspace address has the same offset as the GPA
within that block.

The THP path already checks those constraints before installing a PMD
block mapping. The hugetlb path did not, so an unaligned memslot could
make KVM install a PMD or PUD sized G-stage block that covers memory
outside the slot or maps the wrong host pages.

Pass the target mapping size into fault_supports_gstage_huge_mapping().
The same helper can be used for both THP PMD mappings and hugetlb
PMD/PUD mappings.

Select hugetlb mapping sizes through the same memslot-boundary check,
falling back from PUD to PMD to PAGE_SIZE. When a smaller hugetlb
mapping size is selected, fault the GFN aligned to that selected size
instead of the original VMA size.

Also keep hugetlb mappings out of transparent_hugepage_adjust(). Once
the hugetlb path has chosen PAGE_SIZE, promoting it again through the
THP helper would miss the hugetlb fallback decision.

Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming")
Signed-off-by: Jinyu Tang <tjytimi at 163.com>
Reviewed-by: Nutty Liu <nutty.liu at hotmail.com>
---
v1 -> v2:
  - Squash the helper parameterization into this hugetlb fix.
  - Use the ALIGN()/ALIGN_DOWN() form suggested by Nutty Liu and Anup
    for the memslot boundary check.

 arch/riscv/kvm/mmu.c | 54 ++++++++++++++++++++++++++++++++++++--------
 1 file changed, 44 insertions(+), 10 deletions(-)

diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 2d3def024..0adf017a2 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -286,7 +286,8 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
 }
 
 static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
-					       unsigned long hva)
+					       unsigned long hva,
+					       unsigned long map_size)
 {
 	hva_t uaddr_start, uaddr_end;
 	gpa_t gpa_start;
@@ -300,8 +301,8 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
 
 	/*
 	 * Pages belonging to memslots that don't have the same alignment
-	 * within a PMD for userspace and GPA cannot be mapped with g-stage
-	 * PMD entries, because we'll end up mapping the wrong pages.
+	 * within a huge page for userspace and GPA cannot be mapped with
+	 * g-stage block entries, because we'll end up mapping the wrong pages.
 	 *
 	 * Consider a layout like the following:
 	 *
@@ -321,7 +322,7 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
 	 *   e -> g
 	 *   f -> h
 	 */
-	if ((gpa_start & (PMD_SIZE - 1)) != (uaddr_start & (PMD_SIZE - 1)))
+	if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1)))
 		return false;
 
 	/*
@@ -336,7 +337,8 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
 	 * userspace_addr or the base_gfn, as both are equally aligned (per
 	 * the check above) and equally sized.
 	 */
-	return (hva >= ALIGN(uaddr_start, PMD_SIZE)) && (hva < ALIGN_DOWN(uaddr_end, PMD_SIZE));
+	return (hva >= ALIGN(uaddr_start, map_size)) &&
+	       (hva < ALIGN_DOWN(uaddr_end, map_size));
 }
 
 static int get_hva_mapping_size(struct kvm *kvm,
@@ -404,7 +406,7 @@ static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
 	 * sure that the HVA and GPA are sufficiently aligned and that the
 	 * block map is contained within the memslot.
 	 */
-	if (fault_supports_gstage_huge_mapping(memslot, hva)) {
+	if (fault_supports_gstage_huge_mapping(memslot, hva, PMD_SIZE)) {
 		int sz;
 
 		sz = get_hva_mapping_size(kvm, hva);
@@ -421,12 +423,33 @@ static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
 	return PAGE_SIZE;
 }
 
+static unsigned long hugetlb_mapping_size(struct kvm_memory_slot *memslot,
+					  unsigned long hva,
+					  unsigned long map_size)
+{
+	switch (map_size) {
+	case PUD_SIZE:
+		if (fault_supports_gstage_huge_mapping(memslot, hva, PUD_SIZE))
+			return PUD_SIZE;
+		fallthrough;
+	case PMD_SIZE:
+		if (fault_supports_gstage_huge_mapping(memslot, hva, PMD_SIZE))
+			return PMD_SIZE;
+		fallthrough;
+	case PAGE_SIZE:
+		return PAGE_SIZE;
+	default:
+		return map_size;
+	}
+}
+
 int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
 		      gpa_t gpa, unsigned long hva, bool is_write,
 		      struct kvm_gstage_mapping *out_map)
 {
 	int ret;
 	kvm_pfn_t hfn;
+	bool is_hugetlb;
 	bool writable;
 	short vma_pageshift;
 	gfn_t gfn = gpa >> PAGE_SHIFT;
@@ -460,16 +483,23 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
 		return -EFAULT;
 	}
 
-	if (is_vm_hugetlb_page(vma))
+	is_hugetlb = is_vm_hugetlb_page(vma);
+	if (is_hugetlb)
 		vma_pageshift = huge_page_shift(hstate_vma(vma));
 	else
 		vma_pageshift = PAGE_SHIFT;
 	vma_pagesize = 1ULL << vma_pageshift;
 	if (logging || (vma->vm_flags & VM_PFNMAP))
 		vma_pagesize = PAGE_SIZE;
+	else if (is_hugetlb)
+		vma_pagesize = hugetlb_mapping_size(memslot, hva, vma_pagesize);
 
+	/*
+	 * For hugetlb mappings, vma_pagesize might have been reduced from the
+	 * VMA size to a smaller safe mapping size.
+	 */
 	if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE)
-		gfn = (gpa & huge_page_mask(hstate_vma(vma))) >> PAGE_SHIFT;
+		gfn = ALIGN_DOWN(gpa, vma_pagesize) >> PAGE_SHIFT;
 
 	/*
 	 * Read mmu_invalidate_seq so that KVM can detect if the results of
@@ -511,8 +541,12 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
 	if (mmu_invalidate_retry(kvm, mmu_seq))
 		goto out_unlock;
 
-	/* Check if we are backed by a THP and thus use block mapping if possible */
-	if (!logging && (vma_pagesize == PAGE_SIZE))
+	/*
+	 * Check if we are backed by a THP and thus use block mapping if
+	 * possible. Hugetlb mappings already selected their target size above,
+	 * so do not promote them through the THP helper.
+	 */
+	if (!logging && !is_hugetlb && vma_pagesize == PAGE_SIZE)
 		vma_pagesize = transparent_hugepage_adjust(kvm, memslot, hva, &hfn, &gpa);
 
 	if (writable) {
-- 
2.43.0



From tjytimi at 163.com  Thu Jun  4 07:26:00 2026
From: tjytimi at 163.com (Jinyu Tang)
Date: Thu,  4 Jun 2026 22:26:00 +0800
Subject: [PATCH v2 0/2] KVM: riscv: Fix hugetlb G-stage block mapping eligibility
Message-ID: <20260604142602.3582602-1-tjytimi@163.com>

RISC-V KVM checks memslot alignment and head/tail coverage before
installing THP-backed PMD G-stage block mappings, but the hugetlb path
has used the hugetlb VMA size directly. That can be wrong for memslots
whose HVA and GPA have different offsets within the target block, or for
partial head/tail blocks.

Generalize the existing block eligibility helper so it can check a
caller-provided target size, use it to select hugetlb mappings with a
PUD -> PMD -> PAGE_SIZE fallback, and add a selftest mode that creates a
hugetlb memslot with a deliberate HVA/GPA offset mismatch.

Tested on a QEMU RISC-V host with 8 pre-allocated 2MB hugepages:

  # ./kvm_page_table_test -m 19 -s anonymous -b 4M -v 1
  # ./kvm_page_table_test -m 19 -s anonymous_hugetlb_2mb -b 4M -v 1
  # timeout 30s ./kvm_page_table_test \
        -m 19 -s anonymous_hugetlb_2mb -b 4M -v 1 -u

  base + selftest:
    anonymous:                 PASS
    aligned hugetlb:           PASS
    misaligned hugetlb:        timeout

  patched:
    anonymous:                 PASS
    aligned hugetlb:           PASS
    misaligned hugetlb:        PASS

v1 -> v2:
  - Squash the helper parameterization into the hugetlb fix
  - Use the ALIGN()/ALIGN_DOWN() form suggested by Nutty Liu and Anup
    for the memslot boundary check.

Jinyu Tang (2):
  KVM: riscv: Check hugetlb block mappings against memslot bounds
  KVM: selftests: Add a hugetlb memslot alignment test mode

 arch/riscv/kvm/mmu.c                          | 54 +++++++++++++++----
 .../selftests/kvm/kvm_page_table_test.c       | 28 +++++++---
 2 files changed, 66 insertions(+), 16 deletions(-)

-- 
2.43.0



From tjytimi at 163.com  Thu Jun  4 07:26:02 2026
From: tjytimi at 163.com (Jinyu Tang)
Date: Thu,  4 Jun 2026 22:26:02 +0800
Subject: [PATCH v2 2/2] KVM: selftests: Add a hugetlb memslot alignment test mode
In-Reply-To: <20260604142602.3582602-1-tjytimi@163.com>
References: <20260604142602.3582602-1-tjytimi@163.com>
Message-ID: <20260604142602.3582602-3-tjytimi@163.com>

kvm_page_table_test can already exercise hugetlb-backed guest memory,
but it always creates the test memslot with GPA alignment matching the
hugetlb backing size. That misses the case where a valid hugetlb
memslot is later moved so that the memslot GPA and HVA no longer have
the same offset within the backing huge page.

Add a -u option that moves the test memslot GPA by one guest page after
creating the hugetlb memslot. The memslot is created through the normal
helper first, so the backing allocation remains valid and hugetlb aligned.
Moving the memslot then creates a deliberate HVA/GPA offset mismatch
before the guest mapping is installed.

This mode is useful for checking that architecture MMUs do not install
a block mapping when the block would map the wrong host pages or cover
memory outside the memslot. The option is restricted to hugetlb-backed
test memory because it's specifically about hugetlb block mapping 
eligibility.

Signed-off-by: Jinyu Tang <tjytimi at 163.com>
---
v1 -> v2:
  - Keep the selftest change unchanged from v1

 .../selftests/kvm/kvm_page_table_test.c       | 28 +++++++++++++++----
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c
index fc5242fb9..a910e3abb 100644
--- a/tools/testing/selftests/kvm/kvm_page_table_test.c
+++ b/tools/testing/selftests/kvm/kvm_page_table_test.c
@@ -230,6 +230,7 @@ struct test_params {
 	u64 phys_offset;
 	u64 test_mem_size;
 	enum vm_mem_backing_src_type src_type;
+	bool misalign_slot_gpa;
 };
 
 static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg)
@@ -244,6 +245,7 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg)
 	u64 guest_num_pages;
 	u64 alignment;
 	void *host_test_mem;
+	struct userspace_mem_region *region;
 	struct kvm_vm *vm;
 
 	/* Align up the test memory size */
@@ -276,13 +278,22 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg)
 	/* Add an extra memory slot with specified backing src type */
 	vm_userspace_mem_region_add(vm, src_type, guest_test_phys_mem,
 				    TEST_MEM_SLOT_INDEX, guest_num_pages, 0);
+	region = memslot2region(vm, TEST_MEM_SLOT_INDEX);
+	host_test_mem = region->host_mem;
+
+	if (p->misalign_slot_gpa) {
+		TEST_ASSERT(is_backing_src_hugetlb(src_type),
+			    "Memslot GPA misalignment requires hugetlb backing");
+		TEST_ASSERT(guest_num_pages > 1,
+			    "Need at least two guest pages to misalign memslot GPA");
+
+		guest_test_phys_mem += guest_page_size;
+		vm_mem_region_move(vm, TEST_MEM_SLOT_INDEX, guest_test_phys_mem);
+	}
 
 	/* Do mapping(GVA->GPA) for the testing memory slot */
 	virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages);
 
-	/* Cache the HVA pointer of the region */
-	host_test_mem = addr_gpa2hva(vm, (gpa_t)guest_test_phys_mem);
-
 	/* Export shared structure test_args to guest */
 	sync_global_to_guest(vm, test_args);
 
@@ -417,8 +428,8 @@ static void run_test(enum vm_guest_mode mode, void *arg)
 static void help(char *name)
 {
 	puts("");
-	printf("usage: %s [-h] [-p offset] [-m mode] "
-	       "[-b mem-size] [-v vcpus] [-s mem-type]\n", name);
+	printf("usage: %s [-h] [-p offset] [-m mode] [-b mem-size]\n", name);
+	printf("          [-v vcpus] [-s mem-type] [-u]\n");
 	puts("");
 	printf(" -p: specify guest physical test memory offset\n"
 	       "     Warning: a low offset can conflict with the loaded test code.\n");
@@ -428,6 +439,8 @@ static void help(char *name)
 	printf(" -v: specify the number of vCPUs to run\n"
 	       "     (default: 1)\n");
 	backing_src_help("-s");
+	printf(" -u: move the test memslot GPA by one guest page after creating\n"
+	       "     the memslot, forcing a hugetlb HVA/GPA offset mismatch\n");
 	puts("");
 }
 
@@ -442,7 +455,7 @@ int main(int argc, char *argv[])
 
 	guest_modes_append_default();
 
-	while ((opt = getopt(argc, argv, "hp:m:b:v:s:")) != -1) {
+	while ((opt = getopt(argc, argv, "hp:m:b:v:s:u")) != -1) {
 		switch (opt) {
 		case 'p':
 			p.phys_offset = strtoull(optarg, NULL, 0);
@@ -461,6 +474,9 @@ int main(int argc, char *argv[])
 		case 's':
 			p.src_type = parse_backing_src_type(optarg);
 			break;
+		case 'u':
+			p.misalign_slot_gpa = true;
+			break;
 		case 'h':
 		default:
 			help(argv[0]);
-- 
2.43.0



From joel at jms.id.au  Thu Jun  4 07:39:06 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri, 5 Jun 2026 00:09:06 +0930
Subject: [PATCH 4/7] dt-bindings: timer: Add RISC-V ACLINT bindings
In-Reply-To: <20260603-tadpole-slept-8b6eeae9cd47@spud>
References: <20260603074222.593243-1-joel@jms.id.au> <20260603074222.593243-5-joel@jms.id.au>
 <20260603-tadpole-slept-8b6eeae9cd47@spud>
Message-ID: <CACPK8Xf=Ec16jR+J399Pqi=O=2GgFjkZOPFo0AKaAA+58R6-gQ@mail.gmail.com>

On Wed, 3 Jun 2026 at 18:53, Conor Dooley <conor at kernel.org> wrote:
>
> On Wed, Jun 03, 2026 at 05:12:16PM +0930, Joel Stanley wrote:
> > Document the bindings for the RISC-V ACLINT.
> >
> > Signed-off-by: Drew Fustini <fustini at kernel.org>
> > Signed-off-by: Joel Stanley <joel at jms.id.au>
> > ---
> >  MAINTAINERS                                   |  1 +
> >  .../bindings/timer/riscv,aclint-mtimer.yaml   | 52 +++++++++++++++++++
> >  2 files changed, 53 insertions(+)
> >  create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> >
> > diff --git a/MAINTAINERS b/MAINTAINERS
> > index 2fb1c75afd16..43dd9873bbc5 100644
> > --- a/MAINTAINERS
> > +++ b/MAINTAINERS
> > @@ -23005,6 +23005,7 @@ M:    Joel Stanley <jms at oss.tenstorrent.com>
> >  L:   linux-riscv at lists.infradead.org
> >  S:   Maintained
> >  T:   git https://github.com/tenstorrent/linux.git
> > +F:   Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> >  F:   Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
> >  F:   Documentation/devicetree/bindings/riscv/tenstorrent.yaml
> >  F:   arch/riscv/boot/dts/tenstorrent/
> > diff --git a/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> > new file mode 100644
> > index 000000000000..192ff3fcf79f
> > --- /dev/null
> > +++ b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> > @@ -0,0 +1,52 @@
> > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > +%YAML 1.2
> > +---
> > +$id: http://devicetree.org/schemas/timer/riscv,aclint-mtimer.yaml#
> > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > +
> > +title: RISC-V Advanced Core Local Interruptor (ACLINT)
> > +
> > +maintainers:
> > +  - Joel Stanley <jms at oss.tenstorrent.com>
> > +
> > +description:
> > +  This RISC-V ACLINT specification defines a set of memory mapped devices which
> > +  provide inter-processor interrupts (IPI) and timer functionalities for each
> > +  HART on a multi-HART RISC-V platform. The specification can be found at
> > +  https://github.com/riscvarchive/riscv-aclint/
>
> This is a draft specification, so having a "riscv,aclint-mtimer"
> compatible is not appropriate. Ordinarily I would say that you should be
> able to do this once frozen, but this spec is archived and unlikely to
> have that happen.

I've reworked the binding to reference the privileged spec, which is
ratified and has a section on the timer registers:

 https://docs.riscv.org/reference/isa/priv/machine.html#3-1-2-1-machine-timer-mtime-and-mtimecmp-registers

I'll post a v2 now for review.

Cheers,

Joel


From joel at jms.id.au  Thu Jun  4 07:39:46 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri,  5 Jun 2026 00:09:46 +0930
Subject: [PATCH v2 0/7] riscv: dts: tenstorrent: Add Atlantis platform 
Message-ID: <20260604143957.668047-1-joel@jms.id.au>

Add initial support for the Tenstorrent Atlantis platform, based on the
Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.

The series adds a bare bones device tree with the CPU, interrupt
controllers and a UART. This will be replaced in time with a full
featured machine once details are available.

Patches 1, 2, 3, 5, and 6 add compatibles or extensions to existing
bindings.

Patch 4 adds a new binding document for the aclint timer device.

The series has been boot tested on QEMU[1] and internal development
platforms.

[1] https://lore.kernel.org/qemu-riscv/20260603065859.592063-1-joel at jms.id.au/

Thanks to Anup and Connor for the reviews on v1.

v1:
https://lore.kernel.org/linux-riscv/20260603074222.593243-1-joel at jms.id.au/

Changes since v1:
- Rework mtimer bindings, fix reg property, update compatible and use
  priv spec as reference
- Drop Drew's sob from bindings patches I wrote
- Add Drew's co-developed-by to dts patch
- Correct aplic num-sources

Drew Fustini (1):
  dt-bindings: riscv: add Smrnmi extension description

Joel Stanley (6):
  dt-bindings: aplic: Add Tenstorrent Atlantis compatible
  dt-bindings: imsics: Add Tenstorrent Atlantis compatible
  dt-bindings: riscv: cpus: Add Tenstorrent Ascalon
  dt-bindings: timer: Add RISC-V ACLINT mtimer bindings
  dt-bindings: riscv: Add Tenstorrent Atlantis platform
  riscv: dts: tenstorrent: Add Atlantis platform

 MAINTAINERS                                   |   1 +
 .../interrupt-controller/riscv,aplic.yaml     |   1 +
 .../interrupt-controller/riscv,imsics.yaml    |   1 +
 .../devicetree/bindings/riscv/cpus.yaml       |   5 +
 .../devicetree/bindings/riscv/extensions.yaml |   6 +
 .../bindings/riscv/tenstorrent.yaml           |   4 +
 .../bindings/timer/riscv,aclint-mtimer.yaml   |  56 +++
 arch/riscv/boot/dts/tenstorrent/Makefile      |   1 +
 .../boot/dts/tenstorrent/atlantis-evb.dts     |  33 ++
 .../boot/dts/tenstorrent/atlantis-soc.dtsi    | 471 ++++++++++++++++++
 10 files changed, 579 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
 create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
 create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi

-- 
2.47.3



From joel at jms.id.au  Thu Jun  4 07:39:47 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri,  5 Jun 2026 00:09:47 +0930
Subject: [PATCH v2 1/7] dt-bindings: aplic: Add Tenstorrent Atlantis compatible
In-Reply-To: <20260604143957.668047-1-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
Message-ID: <20260604143957.668047-2-joel@jms.id.au>

Add compatible for APLIC in Tenstorrent Atlantis SoC.

Reviewed-by: Anup Patel <anup at brainfault.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 .../devicetree/bindings/interrupt-controller/riscv,aplic.yaml    | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
index 0718071444d2..d4e17861eda4 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,aplic.yaml
@@ -29,6 +29,7 @@ properties:
       - enum:
           - qemu,aplic
           - spacemit,k3-aplic
+          - tenstorrent,atlantis-aplic
       - const: riscv,aplic
 
   reg:
-- 
2.47.3



From joel at jms.id.au  Thu Jun  4 07:39:48 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri,  5 Jun 2026 00:09:48 +0930
Subject: [PATCH v2 2/7] dt-bindings: imsics: Add Tenstorrent Atlantis compatible
In-Reply-To: <20260604143957.668047-1-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
Message-ID: <20260604143957.668047-3-joel@jms.id.au>

Add compatible for IMSICS in Tenstorrent Atlantis SoC.

Reviewed-by: Anup Patel <anup at brainfault.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 .../devicetree/bindings/interrupt-controller/riscv,imsics.yaml   | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
index feec122bddde..442b8870f9c5 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
+++ b/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml
@@ -49,6 +49,7 @@ properties:
       - enum:
           - qemu,imsics
           - spacemit,k3-imsics
+          - tenstorrent,atlantis-imsics
       - const: riscv,imsics
 
   reg:
-- 
2.47.3



From joel at jms.id.au  Thu Jun  4 07:39:49 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri,  5 Jun 2026 00:09:49 +0930
Subject: [PATCH v2 3/7] dt-bindings: riscv: cpus: Add Tenstorrent Ascalon
In-Reply-To: <20260604143957.668047-1-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
Message-ID: <20260604143957.668047-4-joel@jms.id.au>

Add Tenstorrent Ascalon microarchitecture and the Tenstorrent Ascalon-XG
core.

Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 Documentation/devicetree/bindings/riscv/cpus.yaml | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/cpus.yaml b/Documentation/devicetree/bindings/riscv/cpus.yaml
index 5feeb2203050..2a57bd14569e 100644
--- a/Documentation/devicetree/bindings/riscv/cpus.yaml
+++ b/Documentation/devicetree/bindings/riscv/cpus.yaml
@@ -75,6 +75,11 @@ properties:
               - sifive,x280
           - const: sifive,rocket0
           - const: riscv
+      - items:
+          - enum:
+              - tenstorrent,ascalon-xg
+          - const: tenstorrent,ascalon
+          - const: riscv
       - const: riscv    # Simulator only
     description:
       Identifies that the hart uses the RISC-V instruction set
-- 
2.47.3



From joel at jms.id.au  Thu Jun  4 07:39:50 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri,  5 Jun 2026 00:09:50 +0930
Subject: [PATCH v2 4/7] dt-bindings: timer: Add RISC-V ACLINT mtimer bindings
In-Reply-To: <20260604143957.668047-1-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
Message-ID: <20260604143957.668047-5-joel@jms.id.au>

The mtimer hardware is described in The RISC-V Instruction Set Manual,
Volume II Privileged Architecture, 3.2.1. Machine Timer (mtime and
mtimecmp) Registers.

The ACLINT was a standalone spec that made it to v1.0-rc4, but was never
ratified. As explained by Anup:

> Only the timer defined by ACLINT specification is relevant but the
> RISC-V privileged specification already provides a high-level
> definition of mtime and mtimecmp MMIO registers (see section "Machine
> Timer (mtime and mtimecmp) Registers").
>
> Due to the above reasons, we dropped our plans to ratify ACLINT
> specification in-favor of AIA IMSIC and RISC-V Privileged
> specification.

Link: https://lists.riscv.org/g/tech-aia/topic/connections_between_aia_and/107177435
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
v2:
 - Use priv spec as reference
 - Add soc name to tenstorrent compatible
 - Fix reg property description
---
 MAINTAINERS                                   |  1 +
 .../bindings/timer/riscv,aclint-mtimer.yaml   | 56 +++++++++++++++++++
 2 files changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml

diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..43dd9873bbc5 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23005,6 +23005,7 @@ M:	Joel Stanley <jms at oss.tenstorrent.com>
 L:	linux-riscv at lists.infradead.org
 S:	Maintained
 T:	git https://github.com/tenstorrent/linux.git
+F:	Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
 F:	Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
 F:	Documentation/devicetree/bindings/riscv/tenstorrent.yaml
 F:	arch/riscv/boot/dts/tenstorrent/
diff --git a/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
new file mode 100644
index 000000000000..1d645570b191
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
@@ -0,0 +1,56 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/riscv,aclint-mtimer.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: RISC-V Advanced Core Local Interruptor (ACLINT) Machine-level Timer
+
+maintainers:
+  - Joel Stanley <jms at oss.tenstorrent.com>
+
+description:
+  The RISC-V machine-level timer exposes the memory-mapped mtime and per-hart
+  mtimecmp registers defined in The RISC-V Instruction Set Manual, Volume II
+  Privileged Architecture, 3.2.1. Machine Timer (mtime and mtimecmp) Registers.
+
+properties:
+  compatible:
+    items:
+      - enum:
+          - tenstorrent,atlantis-aclint-mtimer
+          - qemu,aclint-mtimer
+      - const: riscv,aclint-mtimer
+
+  reg:
+    items:
+      - description: MTIMECMP registers, one per hart
+      - description: MTIME register
+
+  reg-names:
+    items:
+      - const: mtimecmp
+      - const: mtime
+
+  interrupts-extended:
+    minItems: 1
+    maxItems: 4095
+
+required:
+  - compatible
+  - reg
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    timer at ac000000 {
+      compatible = "tenstorrent,atlantis-aclint-mtimer", "riscv,aclint-mtimer";
+      reg = <0xac000000 0x8000>, <0xac008000 0x8000>;
+      reg-names = "mtimecmp", "mtime";
+      interrupts-extended = <&cpu1intc 7>,
+                            <&cpu2intc 7>,
+                            <&cpu3intc 7>,
+                            <&cpu4intc 7>;
+    };
+...
-- 
2.47.3



From joel at jms.id.au  Thu Jun  4 07:39:51 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri,  5 Jun 2026 00:09:51 +0930
Subject: [PATCH v2 5/7] dt-bindings: riscv: add Smrnmi extension description
In-Reply-To: <20260604143957.668047-1-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
Message-ID: <20260604143957.668047-6-joel@jms.id.au>

From: Drew Fustini <fustini at kernel.org>

Add description for the Smrnmi extension (Resumable Non-Maskable
Interrupts) as ratified in 35eb3948bf0b ("Merge pull request #1492 from
riscv/smrnmi-ratified") of the riscv-isa-manual.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 Documentation/devicetree/bindings/riscv/extensions.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb21..3e3b4481724f 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -193,6 +193,12 @@ properties:
             ratified at commit d70011dde6c2 ("Update to ratified state")
             of riscv-j-extension.
 
+        - const: smrnmi
+          description: |
+            The standard Smrnmi extension for Resumable Non-Maskable Interrupts
+            as ratified in commit 35eb3948bf0b ("Merge pull request #1492 from
+            riscv/smrnmi-ratified") of the riscv-isa-manual.
+
         - const: smstateen
           description: |
             The standard Smstateen extension for controlling access to CSRs
-- 
2.47.3



From joel at jms.id.au  Thu Jun  4 07:39:52 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri,  5 Jun 2026 00:09:52 +0930
Subject: [PATCH v2 6/7] dt-bindings: riscv: Add Tenstorrent Atlantis platform
In-Reply-To: <20260604143957.668047-1-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
Message-ID: <20260604143957.668047-7-joel@jms.id.au>

Add compatible for the Tenstorrent Atlantis platform.

Signed-off-by: Joel Stanley <joel at jms.id.au>
---
 Documentation/devicetree/bindings/riscv/tenstorrent.yaml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/tenstorrent.yaml b/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
index e15359b2aab6..7fb640e38455 100644
--- a/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
+++ b/Documentation/devicetree/bindings/riscv/tenstorrent.yaml
@@ -22,6 +22,10 @@ properties:
         items:
           - const: tenstorrent,blackhole-card
           - const: tenstorrent,blackhole
+      - description: Tenstorrent Atlantis
+        items:
+          - const: tenstorrent,atlantis-evb
+          - const: tenstorrent,atlantis
 
 additionalProperties: true
 
-- 
2.47.3



From joel at jms.id.au  Thu Jun  4 07:39:53 2026
From: joel at jms.id.au (Joel Stanley)
Date: Fri,  5 Jun 2026 00:09:53 +0930
Subject: [PATCH v2 7/7] riscv: dts: tenstorrent: Add Atlantis platform
In-Reply-To: <20260604143957.668047-1-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
Message-ID: <20260604143957.668047-8-joel@jms.id.au>

Add initial support for the Tenstorrent Atlantis platform, based on the
Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.

The evb machine represents an internal bringup vehicle with just the
interrupt controllers and a UART. This will be replaced in time with a
full featured machine once details are available.

Co-developed-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Drew Fustini <fustini at kernel.org>
Signed-off-by: Joel Stanley <joel at jms.id.au>
---
v2:
 - Update mtimer compatible
 - Add Drew's co-developed-by
 - Correct aplic num-sources count
---
 arch/riscv/boot/dts/tenstorrent/Makefile      |   1 +
 .../boot/dts/tenstorrent/atlantis-evb.dts     |  33 ++
 .../boot/dts/tenstorrent/atlantis-soc.dtsi    | 471 ++++++++++++++++++
 3 files changed, 505 insertions(+)
 create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
 create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi

diff --git a/arch/riscv/boot/dts/tenstorrent/Makefile b/arch/riscv/boot/dts/tenstorrent/Makefile
index 2c81faaba462..92d8bb1a683f 100644
--- a/arch/riscv/boot/dts/tenstorrent/Makefile
+++ b/arch/riscv/boot/dts/tenstorrent/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_TENSTORRENT) += blackhole-card.dtb
+dtb-$(CONFIG_ARCH_TENSTORRENT) += atlantis-evb.dtb
diff --git a/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
new file mode 100644
index 000000000000..06259cca8357
--- /dev/null
+++ b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
@@ -0,0 +1,33 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/dts-v1/;
+
+#include "atlantis-soc.dtsi"
+
+/ {
+	model = "Tenstorrent Atlantis development platform";
+	compatible = "tenstorrent,atlantis-evb", "tenstorrent,atlantis";
+
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	memory at 0 {
+		device_type = "memory";
+		reg = <0x0 0x00000000 0x0 0x80000000>,
+		      <0x1 0x80000000 0x0 0x80000000>;
+	};
+
+	aliases {
+		serial0 = &uart1;
+	};
+
+	chosen {
+		bootargs = "earlycon console=ttyS0";
+		stdout-path = "serial0";
+	};
+};
+
+&uart1 {
+	/delete-property/ clocks;
+	clock-frequency = <5000000>;
+	status = "okay";
+};
diff --git a/arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi b/arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi
new file mode 100644
index 000000000000..2513f0dcc62e
--- /dev/null
+++ b/arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi
@@ -0,0 +1,471 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/tenstorrent,atlantis-prcm-rcpu.h>
+
+/ {
+	model = "Tenstorrent Atlantis";
+	compatible = "tenstorrent,atlantis";
+
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	cpus {
+		#address-cells = <1>;
+		#size-cells = <0>;
+		timebase-frequency = <1000000000>;
+
+		cpu0: cpu at 0 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <0>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu0_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu1: cpu at 1 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <1>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu1_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu2: cpu at 2 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <2>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu2_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu3: cpu at 3 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <3>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu3_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu4: cpu at 4 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <4>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu4_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu5: cpu at 5 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <5>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu5_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu6: cpu at 6 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <6>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu6_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		cpu7: cpu at 7 {
+			compatible = "tenstorrent,ascalon-xg", "tenstorrent,ascalon", "riscv";
+			device_type = "cpu";
+			reg = <7>;
+			riscv,isa-base = "rv64i";
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "h",
+					       "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif",
+					       "zicclsm", "ziccrse", "zicntr", "zicond", "zicsr",
+					       "zifencei", "zihintntl", "zihintpause", "zihpm",
+					       "zimop", "za64rs", "zawrs", "zfa", "zfbfmin", "zfh",
+					       "zfhmin", "zca", "zcb", "zcmop", "zba", "zbb",
+					       "zbs", "zkr", "zkt", "zvbb", "zvbc", "zvfbfmin",
+					       "zvfbfwma", "zvfh", "zvfhmin", "zvkt", "sha",
+					       "shcounterenw", "shgatpa", "shtvala", "shvsatpa",
+					       "shvstvala", "shvstvecd", "smaia", "smmpm", "smnpm",
+					       "smrnmi", "smstateen", "ssaia", "ssccptr",
+					       "sscofpmf", "sscounterenw", "ssnpm", "ssstateen",
+					       "sstc", "sstvala", "sstvecd", "ssu64xl", "svade",
+					       "svinval", "svnapot", "svpbmt";
+			riscv,cbom-block-size = <64>;
+			riscv,cbop-block-size = <64>;
+			riscv,cboz-block-size = <64>;
+			i-cache-block-size = <64>;
+			i-cache-size = <0x10000>;
+			i-cache-sets = <128>;
+			d-cache-block-size = <64>;
+			d-cache-size = <0x40000>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2_cache>;
+			mmu-type = "riscv,sv57";
+
+			cpu7_intc: interrupt-controller {
+				compatible = "riscv,cpu-intc";
+				#interrupt-cells = <1>;
+				interrupt-controller;
+			};
+		};
+
+		l2_cache: l2-cache {
+			compatible = "cache";
+			cache-block-size = <64>;
+			cache-level = <2>;
+			cache-size = <0xc00000>;
+			cache-sets = <512>;
+			cache-unified;
+		};
+	};
+
+	clocks {
+		osc_24m: clock-24m {
+			compatible = "fixed-clock";
+			clock-frequency = <24000000>;
+			clock-output-names = "osc_24m";
+			#clock-cells = <0>;
+		};
+	};
+
+	soc {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		compatible = "simple-bus";
+		interrupt-parent = <&aplic_s>;
+		ranges;
+
+		imsic_m: interrupt-controller at a0000000 {
+			compatible = "tenstorrent,atlantis-imsics", "riscv,imsics";
+			riscv,num-ids = <255>;
+			riscv,guest-index-bits = <6>;
+			reg = <0x0 0xa0000000 0x0 0x200000>;
+			interrupts-extended = <&cpu0_intc 11>, <&cpu1_intc 11>,
+					      <&cpu2_intc 11>, <&cpu3_intc 11>,
+					      <&cpu4_intc 11>, <&cpu5_intc 11>,
+					      <&cpu6_intc 11>, <&cpu7_intc 11>;
+			msi-controller;
+			#msi-cells = <0>;
+			interrupt-controller;
+			#interrupt-cells = <0>;
+		};
+
+		mtimer: timer at a2180000 {
+			compatible = "tenstorrent,atlantis-aclint-mtimer", "riscv,aclint-mtimer";
+			interrupts-extended = <&cpu0_intc 7>, <&cpu1_intc 7>,
+					      <&cpu2_intc 7>, <&cpu3_intc 7>,
+					      <&cpu4_intc 7>, <&cpu5_intc 7>,
+					      <&cpu6_intc 7>, <&cpu7_intc 7>;
+			reg = <0x0 0xa2180000 0x0 0x8000 0x0 0xa2188000 0x0 0x8000>;
+		};
+
+		imsic_s: interrupt-controller at a4000000 {
+			compatible = "tenstorrent,atlantis-imsics", "riscv,imsics";
+			riscv,num-ids = <255>;
+			riscv,guest-index-bits = <6>;
+			reg = <0x0 0xa4000000 0x0 0x200000>;
+			interrupts-extended = <&cpu0_intc 9>, <&cpu1_intc 9>,
+					      <&cpu2_intc 9>, <&cpu3_intc 9>,
+					      <&cpu4_intc 9>, <&cpu5_intc 9>,
+					      <&cpu6_intc 9>, <&cpu7_intc 9>;
+			msi-controller;
+			#msi-cells = <0>;
+			interrupt-controller;
+			#interrupt-cells = <0>;
+		};
+
+		aplic_m: interrupt-controller at cc000000 {
+			compatible = "tenstorrent,atlantis-aplic", "riscv,aplic";
+			msi-parent = <&imsic_m>;
+			riscv,delegation = <&aplic_s 1 96>;
+			riscv,children = <&aplic_s>;
+			reg = <0x0 0xcc000000 0x0 0x4000000>;
+			riscv,num-sources = <128>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			#address-cells = <0>;
+		};
+
+		prcm_rcpu: clock-controller at d0000000 {
+			compatible = "tenstorrent,atlantis-prcm-rcpu";
+			reg = <0x00 0xd0000000 0x00 0x10000>;
+			clocks = <&osc_24m>;
+			#clock-cells = <1>;
+			#reset-cells = <1>;
+			assigned-clocks = <&prcm_rcpu CLK_RCPU_ROOT>, <&prcm_rcpu CLK_NOCC_CLK>;
+			assigned-clock-parents = <&prcm_rcpu CLK_RCPU_ROOT>,
+						 <&prcm_rcpu CLK_NOC_PLL>;
+		};
+
+		uart0: serial at d4100000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <38 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART0_PCLK>;
+			reg = <0x0 0xd4100000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		uart1: serial at d4110000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <39 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART1_PCLK>;
+			reg = <0x0 0xd4110000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		uart2: serial at d4120000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <40 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART2_PCLK>;
+			reg = <0x0 0xd4120000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		uart3: serial at d4130000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <41 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART3_PCLK>;
+			reg = <0x0 0xd4130000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		uart4: serial at d4140000 {
+			compatible = "snps,dw-apb-uart";
+			interrupts = <42 IRQ_TYPE_LEVEL_HIGH>;
+			clocks = <&prcm_rcpu CLK_UART4_PCLK>;
+			reg = <0x0 0xd4140000 0x0 0x10000>;
+			reg-shift = <2>;
+			reg-io-width = <4>;
+			status = "disabled";
+		};
+
+		aplic_s: interrupt-controller at e8000000 {
+			compatible = "tenstorrent,atlantis-aplic", "riscv,aplic";
+			msi-parent = <&imsic_s>;
+			riscv,num-sources = <128>;
+			reg = <0x0 0xe8000000 0x0 0x4000000>;
+			interrupt-controller;
+			#interrupt-cells = <2>;
+			#address-cells = <0>;
+		};
+	};
+};
-- 
2.47.3



From rppt at kernel.org  Thu Jun  4 07:59:33 2026
From: rppt at kernel.org (Mike Rapoport)
Date: Thu, 4 Jun 2026 17:59:33 +0300
Subject: [PATCH v2 0/2] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
In-Reply-To: <20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434@iscas.ac.cn>
References: <20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434@iscas.ac.cn>
Message-ID: <aiGS1e6wMwcwC-sC@kernel.org>

On Thu, Jun 04, 2026 at 07:11:53PM +0800, Vivian Wang wrote:
> Patch 1 adds a hook and should be no functional change on its own,
> whereas patch 2 is the actual fix, which depends on my earlier kfence
> fixes for mark_new_valid_map() [1].
> 
> Found while testing AMD_HSA/ZONE_DEVICE on SpacemiT K3. Using
> ZONE_DEVICE requires another fix [2].
> 
> [1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn
> [2]: https://lore.kernel.org/linux-riscv/20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd at iscas.ac.cn
> 
> ---
> Changes in v2:
> - Split patch in two, hook point and riscv hook 

I don't think it should be split. You can add a hook and it's riscv
implementation in one patch, anyway this should go upstream via the same
tree.

> - Explain hook necessity in patch 1 message (Mike)
> - Make hook #define based (Mike)
> - Call finalize hook only on populate success
> - Link to v1: https://patch.msgid.link/20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16 at iscas.ac.cn
> 
> ---
> Vivian Wang (2):
>       mm/vmemmap: Add a post-population hook for architectures
>       riscv: mm: Avoid spurious fault after hotplugging vmemmap
> 
>  arch/riscv/include/asm/pgtable.h | 4 ++++
>  arch/riscv/mm/init.c             | 6 ++++++
>  mm/sparse-vmemmap.c              | 8 ++++++++
>  3 files changed, 18 insertions(+)
> ---
> base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
> change-id: 20260525-mark-after-vmemmap-populate-68bd790839c9
> prerequisite-message-id: <20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn>
> prerequisite-patch-id: fdc42f2647e21d111f44a6532887a6705cd470a9
> prerequisite-patch-id: 096fa339c84c36643ae4311fd8362dc63e23d950
> prerequisite-patch-id: 305c876a5f4a23a840a8142aea79b796ed297545
> prerequisite-patch-id: d78cb55d6a616b1170f06a401c8fd44acd11e5d5
> prerequisite-patch-id: b02b4a76e94f3e2821291d4c23b46f6e5ecf5203
> 
> Best regards,
> --  
> Vivian Wang <wangruikang at iscas.ac.cn>
> 

-- 
Sincerely yours,
Mike.


From conor at kernel.org  Thu Jun  4 08:21:42 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 16:21:42 +0100
Subject: [PATCH 4/7] dt-bindings: timer: Add RISC-V ACLINT bindings
In-Reply-To: <CACPK8Xf=Ec16jR+J399Pqi=O=2GgFjkZOPFo0AKaAA+58R6-gQ@mail.gmail.com>
References: <20260603074222.593243-1-joel@jms.id.au>
 <20260603074222.593243-5-joel@jms.id.au>
 <20260603-tadpole-slept-8b6eeae9cd47@spud>
 <CACPK8Xf=Ec16jR+J399Pqi=O=2GgFjkZOPFo0AKaAA+58R6-gQ@mail.gmail.com>
Message-ID: <20260604-phonics-venue-48a4f241aed0@spud>

On Fri, Jun 05, 2026 at 12:09:06AM +0930, Joel Stanley wrote:
> On Wed, 3 Jun 2026 at 18:53, Conor Dooley <conor at kernel.org> wrote:
> >
> > On Wed, Jun 03, 2026 at 05:12:16PM +0930, Joel Stanley wrote:
> > > Document the bindings for the RISC-V ACLINT.
> > >
> > > Signed-off-by: Drew Fustini <fustini at kernel.org>
> > > Signed-off-by: Joel Stanley <joel at jms.id.au>
> > > ---
> > >  MAINTAINERS                                   |  1 +
> > >  .../bindings/timer/riscv,aclint-mtimer.yaml   | 52 +++++++++++++++++++
> > >  2 files changed, 53 insertions(+)
> > >  create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> > >
> > > diff --git a/MAINTAINERS b/MAINTAINERS
> > > index 2fb1c75afd16..43dd9873bbc5 100644
> > > --- a/MAINTAINERS
> > > +++ b/MAINTAINERS
> > > @@ -23005,6 +23005,7 @@ M:    Joel Stanley <jms at oss.tenstorrent.com>
> > >  L:   linux-riscv at lists.infradead.org
> > >  S:   Maintained
> > >  T:   git https://github.com/tenstorrent/linux.git
> > > +F:   Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> > >  F:   Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
> > >  F:   Documentation/devicetree/bindings/riscv/tenstorrent.yaml
> > >  F:   arch/riscv/boot/dts/tenstorrent/
> > > diff --git a/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> > > new file mode 100644
> > > index 000000000000..192ff3fcf79f
> > > --- /dev/null
> > > +++ b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> > > @@ -0,0 +1,52 @@
> > > +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> > > +%YAML 1.2
> > > +---
> > > +$id: http://devicetree.org/schemas/timer/riscv,aclint-mtimer.yaml#
> > > +$schema: http://devicetree.org/meta-schemas/core.yaml#
> > > +
> > > +title: RISC-V Advanced Core Local Interruptor (ACLINT)
> > > +
> > > +maintainers:
> > > +  - Joel Stanley <jms at oss.tenstorrent.com>
> > > +
> > > +description:
> > > +  This RISC-V ACLINT specification defines a set of memory mapped devices which
> > > +  provide inter-processor interrupts (IPI) and timer functionalities for each
> > > +  HART on a multi-HART RISC-V platform. The specification can be found at
> > > +  https://github.com/riscvarchive/riscv-aclint/
> >
> > This is a draft specification, so having a "riscv,aclint-mtimer"
> > compatible is not appropriate. Ordinarily I would say that you should be
> > able to do this once frozen, but this spec is archived and unlikely to
> > have that happen.
> 
> I've reworked the binding to reference the privileged spec, which is
> ratified and has a section on the timer registers:
> 
>  https://docs.riscv.org/reference/isa/priv/machine.html#3-1-2-1-machine-timer-mtime-and-mtimecmp-registers
> 
> I'll post a v2 now for review.

To be clear, the problem isn't referencing the draft spec (that is what
you implemented after all). It's the "riscv,aclint-mtimer" compatible
that's the problem.

Cheers,
Conor.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/90ab16f1/attachment.sig>

From andrew.jones at oss.qualcomm.com  Thu Jun  4 08:29:19 2026
From: andrew.jones at oss.qualcomm.com (Andrew Jones)
Date: Thu, 4 Jun 2026 10:29:19 -0500
Subject: [PATCH v2 08/10] riscv: cpufeature: Introduce ISA bases bitmap
 and rva23u64 detection
In-Reply-To: <CAH1PCMa-5W9PsX8cDLUk6-MkcM53HOz2QtaxCHd+XOr7DgH5+w@mail.gmail.com>
References: <20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc@riscstar.com>
 <20260511-rva23u64-hwprobe-v2-v2-8-21c5a544f1dc@riscstar.com>
 <5tjmypgyxbhgxfjub5q6ne475uysse6yl473sxisjoammkdvbu@yebejqbiy6e3>
 <CAH1PCMa-5W9PsX8cDLUk6-MkcM53HOz2QtaxCHd+XOr7DgH5+w@mail.gmail.com>
Message-ID: <ug2cipududshcbv24ruicqpugzinujnamvdcuy6pubkwh67bfp@2fysrplz3nr4>

On Sat, May 30, 2026 at 08:42:29AM +0800, Guodong Xu wrote:
> On Thu, May 28, 2026 at 12:35?AM Andrew Jones
> > Sashiko points out a few things about this patch which I think I
> > agree with
> >
> > https://sashiko.dev/#/patchset/20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc%40riscstar.com?part=8
> 
> Quote the following from Sashiko.dev:
> > Should this mask specify the individual subset extensions required by the
> > profile instead of the superset extensions like RISCV_ISA_EXT_B,
> > RISCV_ISA_EXT_C, and RISCV_ISA_EXT_V?
> 
> My preference is to leave the mask on B/C/V (and A) as-is. I'd prefer to
> keep matching on the single-letter, rather than expanding them. Here is why:
> 
> - The RVA23 profile lists A, B, C and V as single-letter mandatory
>   extensions; it doesn't enumerate Zaamo/Zalrsc, Zba/Zbb/Zbs, Zc* or the
>   Zve*/Zvl* subsets in the mandatory set.
> 
> - In current merged code, hwprobe_isa_ext0() is already using
>   riscv_isa_extension_available() signle letter checking for C and V.
> 
> PS:
> B maybe a special one, just in case anybody raise it. As the community
> discussed when I adding it into the bindings, because B comes later than
> its sub-components zba/zbb/zbs, so, when I added B, I cleaned up all
> in-tree dts files which declared zba/zbb/zbs but not B and made them declare
> both.
> 
> Link: https://lore.kernel.org/linux-riscv/20260115-adding-b-dtsi-v2-0-254dd61cf947 at riscstar.com/
> [1]
> 
> Also, in the bindings: extensions.yaml, a schema rule is added which requires
> a node listing zba, zbb and zbs to also list b (and the reverse). Moving on,
> new dtsi/dts fils, a node with only the subsets fails dtbs_check.
> 
> One may argue that the schema check doesn't cover ACPI path. But again,
> shouldn't the vendor who publishs RVA23 hardware be conformant to the
> extensions wording in RVA23 v1.0 spec?
> 
> What do you think?
>

I certainly see a case for the kernel staying out of the extension
dependency validation game. I think it makes sense for an ISA string
validation tool to exist for vendors to do sanity checks on their
ISA strings, but that's not the kernel's role. OTOH, whether or not
the kernel wants to try and detect inconsistencies with the ISA
string in order to build confidence in using what it sees there
and publishing what it sees there to usermode, through hwprobe, might
still be worth debating.

Without CPUID / ID_* registers for Linux to be able to check an
authoritative source of truth about what is and isn't supported by
the CPU, riscv Linux has to decide to either blindly trust the
hardware description or do sanity checks / probes in order to
confirm what it sees there. Maybe we can assume that any extension
used by the kernel will trip over itself quickly, alerting vendors
to fix their ISA strings, but I'm not sure we can make that assumption
for usermode extensions that Linux doesn't use, but does expose
through hwprobe. What apps need to run in testing to exercise them?
How long will those apps need to run before they trip over something?

The more I think I about it, the more I think the lack of CPUID / ID_*
registers puts Linux in a tight spot. If Linux trustingly publishes
what firmware tells it to to userspace and userspace blows up, Linux
will have to share some of the blame for having misled it. So, should
Linux validate everything it publishes somehow? Or, should it at least
do relatively cheap sanity checks on everything it publishes in order
to build some confidence?

Thanks,
drew


From andrew.jones at oss.qualcomm.com  Thu Jun  4 08:48:30 2026
From: andrew.jones at oss.qualcomm.com (Andrew Jones)
Date: Thu, 4 Jun 2026 10:48:30 -0500
Subject: [PATCH v3 08/15] riscv: Add Zic64b to cpufeature and hwprobe
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-8-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
 <20260603-rva23u64-hwprobe-v2-v3-8-5529a7b28384@gmail.com>
Message-ID: <4dh7hewwdowucpcz7wpg55wruh2ze4afjkk2nwxfm6pfucfnzt@pujmvbwax4ot>

On Wed, Jun 03, 2026 at 07:12:03AM -0400, Guodong Xu wrote:
> Zic64b mandates 64-byte naturally aligned cache blocks and is a
> mandatory extension of the RVA22 and RVA23 profiles.  Allocate a
> RISCV_ISA_EXT_ZIC64B id, parse "zic64b" from the ISA string with a
> validate callback that requires cbom/cbop/cboz cache block sizes of 64
> bytes, and export it through hwprobe.
> 
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> ---
> v3: New patch.
> ---
>  Documentation/arch/riscv/hwprobe.rst  |  3 +++
>  arch/riscv/include/asm/hwcap.h        |  1 +
>  arch/riscv/include/uapi/asm/hwprobe.h |  1 +
>  arch/riscv/kernel/cpufeature.c        | 18 ++++++++++++++++++
>  arch/riscv/kernel/sys_hwprobe.c       |  1 +
>  5 files changed, 24 insertions(+)
> 
> diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
> index 002d5046ab689..601e81f561421 100644
> --- a/Documentation/arch/riscv/hwprobe.rst
> +++ b/Documentation/arch/riscv/hwprobe.rst
> @@ -425,3 +425,6 @@ The following keys are defined:
>    * :c:macro:`RISCV_HWPROBE_EXT_B`: The B extension is supported, as defined
>      in version 1.0 of the Bit-Manipulation ISA extensions, and implies the
>      presence of the Zba, Zbb, and Zbs sub-extensions.

Need a blank line here.

> +  * :c:macro:`RISCV_HWPROBE_EXT_ZIC64B`: The Zic64b extension is supported,
> +    as defined in the RISC-V Profiles specification starting from commit
> +    b1d80660 ("Updated to ratified state.")
> diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
> index 58523b3a1998a..36572c1ff438a 100644
> --- a/arch/riscv/include/asm/hwcap.h
> +++ b/arch/riscv/include/asm/hwcap.h
> @@ -117,6 +117,7 @@
>  #define RISCV_ISA_EXT_ZICCAMOA		107
>  #define RISCV_ISA_EXT_ZICCIF		108
>  #define RISCV_ISA_EXT_ZA64RS		109
> +#define RISCV_ISA_EXT_ZIC64B		110
>  
>  #define RISCV_ISA_EXT_XLINUXENVCFG	127
>  
> diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
> index 430dc49a82863..36ec8ab470423 100644
> --- a/arch/riscv/include/uapi/asm/hwprobe.h
> +++ b/arch/riscv/include/uapi/asm/hwprobe.h
> @@ -122,6 +122,7 @@ struct riscv_hwprobe {
>  #define		RISCV_HWPROBE_EXT_ZICCRSE	(1ULL << 4)
>  #define		RISCV_HWPROBE_EXT_ZA64RS	(1ULL << 5)
>  #define		RISCV_HWPROBE_EXT_B		(1ULL << 6)
> +#define		RISCV_HWPROBE_EXT_ZIC64B	(1ULL << 7)
>  
>  /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
>  
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index e0197160af6dd..79ff431768139 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -154,6 +154,23 @@ static int riscv_ext_zicbop_validate(const struct riscv_isa_ext_data *data,
>  	return 0;
>  }
>  
> +static int riscv_ext_zic64b_validate(const struct riscv_isa_ext_data *data,
> +				     const unsigned long *isa_bitmap)
> +{
> +	/*
> +	 * Zic64b mandates 64-byte naturally aligned cache blocks; cross-check the
> +	 * cbom/cbop/cboz block-size device-tree properties to avoid inconsistency.
> +	 */
> +	if (riscv_cbom_block_size != 64 ||
> +	    riscv_cbop_block_size != 64 ||
> +	    riscv_cboz_block_size != 64) {
> +		pr_err("Zic64b detected in ISA string, disabling as the cache block size is not 64 bytes\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
>  static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data,
>  				const unsigned long *isa_bitmap)
>  {
> @@ -524,6 +541,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
>  	__RISCV_ISA_EXT_SUPERSET(b, RISCV_ISA_EXT_B, riscv_b_exts),
>  	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate),
>  	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H),
> +	__RISCV_ISA_EXT_DATA_VALIDATE(zic64b, RISCV_ISA_EXT_ZIC64B, riscv_ext_zic64b_validate),
>  	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
>  	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
>  	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
> diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
> index dcc102bf8f183..3e80e5551ae0d 100644
> --- a/arch/riscv/kernel/sys_hwprobe.c
> +++ b/arch/riscv/kernel/sys_hwprobe.c
> @@ -211,6 +211,7 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
>  		EXT_KEY(isainfo->isa, ZICCRSE, pair->value, missing);
>  		EXT_KEY(isainfo->isa, ZA64RS, pair->value, missing);
>  		EXT_KEY(isainfo->isa, B, pair->value, missing);
> +		EXT_KEY(isainfo->isa, ZIC64B, pair->value, missing);
>  	}
>  
>  	/* Now turn off reporting features if any CPU is missing it. */
> 
> -- 
> 2.43.0
>

Other than the missing blank line,

Reviewed-by: Andrew Jones <andrew.jones at oss.qualcomm.com>


From andrew.jones at oss.qualcomm.com  Thu Jun  4 09:01:47 2026
From: andrew.jones at oss.qualcomm.com (Andrew Jones)
Date: Thu, 4 Jun 2026 11:01:47 -0500
Subject: [PATCH v3 02/15] riscv: hwprobe.rst: Document EXT_ZICFISS and
 EXT_ZICFILP
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-2-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
 <20260603-rva23u64-hwprobe-v2-v3-2-5529a7b28384@gmail.com>
Message-ID: <vazr6kop3pbga22p5wbn3oursuic4thh4aeogkndyuskrncgta@cpk6igb7cr6a>

On Wed, Jun 03, 2026 at 07:11:57AM -0400, Guodong Xu wrote:
> Commit 30c3099036a9 ("riscv/hwprobe: add zicfilp / zicfiss
> enumeration in hwprobe") added RISCV_HWPROBE_EXT_ZICFISS and
> RISCV_HWPROBE_EXT_ZICFILP, but did not add matching entries to
> Documentation/arch/riscv/hwprobe.rst.  Add them now.
> 
> Fixes: 30c3099036a9 ("riscv/hwprobe: add zicfilp / zicfiss enumeration in hwprobe")
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> ---
> v3:
> - Also document RISCV_HWPROBE_EXT_ZICFILP (bit 63 of IMA_EXT_0), the
>   sibling enumeration added by the same commit (Andrew).
> v2: New patch.
> ---
>  Documentation/arch/riscv/hwprobe.rst | 10 ++++++++++
>  1 file changed, 10 insertions(+)
> 
> diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
> index a09a8f16bd16f..3cedaaa53f331 100644
> --- a/Documentation/arch/riscv/hwprobe.rst
> +++ b/Documentation/arch/riscv/hwprobe.rst
> @@ -289,6 +289,11 @@ The following keys are defined:
>      defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
>      load/store pair for RV32 with the main manual") of the riscv-isa-manual.
>  
> +  * :c:macro:`RISCV_HWPROBE_EXT_ZICFILP`: The Zicfilp extension is supported,
> +    as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
> +    extensions specification, ratified in commit ff03d8485a04 ("Update to

Can we use commit 302a2d45c243 instead since that one has the v1.0 tag?

> +    ratified state") of riscv-cfi.
> +
>  * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated.  Returns similar values to
>    :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
>    mistakenly classified as a bitmask rather than a value.
> @@ -391,3 +396,8 @@ The following keys are defined:
>  * :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_1`: A bitmask containing additional
>    extensions that are compatible with the
>    :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
> +
> +  * :c:macro:`RISCV_HWPROBE_EXT_ZICFISS`: The Zicfiss extension is supported,
> +    as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
> +    extensions specification, ratified in commit ff03d8485a04 ("Update to
> +    ratified state") of riscv-cfi.
> 
> -- 
> 2.43.0
>

Otherwise,

Reviewed-by: Andrew Jones <andrew.jones at oss.qualcomm.com>


From andrew.jones at oss.qualcomm.com  Thu Jun  4 09:03:19 2026
From: andrew.jones at oss.qualcomm.com (Andrew Jones)
Date: Thu, 4 Jun 2026 11:03:19 -0500
Subject: [PATCH v3 00/15] riscv: hwprobe: Expose RVA23U64 base behavior
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
Message-ID: <dyafwgy6wgahizpld2vfuk56nzhueh727u6vzblmasmw24vb23@uw46cc5sxpb2>

On Wed, Jun 03, 2026 at 07:11:55AM -0400, Guodong Xu wrote:
> This series builds on Andrew Jones's earlier RFC [1]. It lets
> userspace check for RVA23U64 conformance in one call, instead of
> walking hwprobe + prctl across every mandatory extension.
> 
> The series adds a small framework that resolves profile-class
> bases (IMA and RVA23U64) from the kernel's ISA extension bitmap at
> init time, and surfaces the result through both /proc/cpuinfo and
> hwprobe. Later patches can add RVA23S64, and backward RVA22 / RVA20
> detection, to riscv_set_isa_bases() without changes to the
> surrounding code.
>

Hi Guodong,

The series looks good to me. Thanks a lot for picking up this work!

drew


From conor at kernel.org  Thu Jun  4 09:22:15 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 17:22:15 +0100
Subject: [PATCH v2 08/10] riscv: cpufeature: Introduce ISA bases bitmap
 and rva23u64 detection
In-Reply-To: <ug2cipududshcbv24ruicqpugzinujnamvdcuy6pubkwh67bfp@2fysrplz3nr4>
References: <20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc@riscstar.com>
 <20260511-rva23u64-hwprobe-v2-v2-8-21c5a544f1dc@riscstar.com>
 <5tjmypgyxbhgxfjub5q6ne475uysse6yl473sxisjoammkdvbu@yebejqbiy6e3>
 <CAH1PCMa-5W9PsX8cDLUk6-MkcM53HOz2QtaxCHd+XOr7DgH5+w@mail.gmail.com>
 <ug2cipududshcbv24ruicqpugzinujnamvdcuy6pubkwh67bfp@2fysrplz3nr4>
Message-ID: <20260604-decency-salaried-4cb69e1c9fa9@spud>

On Thu, Jun 04, 2026 at 10:29:19AM -0500, Andrew Jones wrote:
> On Sat, May 30, 2026 at 08:42:29AM +0800, Guodong Xu wrote:
> > On Thu, May 28, 2026 at 12:35?AM Andrew Jones
> > > Sashiko points out a few things about this patch which I think I
> > > agree with
> > >
> > > https://sashiko.dev/#/patchset/20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc%40riscstar.com?part=8
> > 
> > Quote the following from Sashiko.dev:
> > > Should this mask specify the individual subset extensions required by the
> > > profile instead of the superset extensions like RISCV_ISA_EXT_B,
> > > RISCV_ISA_EXT_C, and RISCV_ISA_EXT_V?
> > 
> > My preference is to leave the mask on B/C/V (and A) as-is. I'd prefer to
> > keep matching on the single-letter, rather than expanding them. Here is why:
> > 
> > - The RVA23 profile lists A, B, C and V as single-letter mandatory
> >   extensions; it doesn't enumerate Zaamo/Zalrsc, Zba/Zbb/Zbs, Zc* or the
> >   Zve*/Zvl* subsets in the mandatory set.
> > 
> > - In current merged code, hwprobe_isa_ext0() is already using
> >   riscv_isa_extension_available() signle letter checking for C and V.
> > 
> > PS:
> > B maybe a special one, just in case anybody raise it. As the community
> > discussed when I adding it into the bindings, because B comes later than
> > its sub-components zba/zbb/zbs, so, when I added B, I cleaned up all
> > in-tree dts files which declared zba/zbb/zbs but not B and made them declare
> > both.
> > 
> > Link: https://lore.kernel.org/linux-riscv/20260115-adding-b-dtsi-v2-0-254dd61cf947 at riscstar.com/
> > [1]
> > 
> > Also, in the bindings: extensions.yaml, a schema rule is added which requires
> > a node listing zba, zbb and zbs to also list b (and the reverse). Moving on,
> > new dtsi/dts fils, a node with only the subsets fails dtbs_check.
> > 
> > One may argue that the schema check doesn't cover ACPI path. But again,
> > shouldn't the vendor who publishs RVA23 hardware be conformant to the
> > extensions wording in RVA23 v1.0 spec?
> > 
> > What do you think?
> >
> 
> I certainly see a case for the kernel staying out of the extension
> dependency validation game. I think it makes sense for an ISA string
> validation tool to exist for vendors to do sanity checks on their
> ISA strings, but that's not the kernel's role. OTOH, whether or not
> the kernel wants to try and detect inconsistencies with the ISA
> string in order to build confidence in using what it sees there
> and publishing what it sees there to usermode, through hwprobe, might
> still be worth debating.

On the dt front, our policy is that it is not the kernel's job to
check that the dt matches the hardware. It is the firmware's job to
accurately report what the hardware is. There's definitely some
exceptions to that already (*cough thead vector cough*) but that's in
part because we failed to come up with concrete descriptions in the
first place.

Yesterday I commented on a patch that was adding this kind of thing:
| The point of validate callbacks is twofold: checking that the kernel
| configuration supports the extension and that extensions that the kernel
| depends on to support the one in question are present.

The latter is because you could depend on an extension that is affected
by the former.
Looking at the list of validate callbacks, I think there are some that
actually don't follow this policy (I saw riscv_ext_zca_depends() that
has no real purpose, but didn't look much further).
I'm not even sure that the validate callback added in this series for
zic64b should be added, it's borderline for me. I'm only really not
objecting to it because it outputs a warning if someone has the
retroactively added extension without the relevant dt/acpi properties
and expects things to work.

> Without CPUID / ID_* registers for Linux to be able to check an
> authoritative source of truth about what is and isn't supported by
> the CPU, riscv Linux has to decide to either blindly trust the
> hardware description or do sanity checks / probes in order to
> confirm what it sees there. Maybe we can assume that any extension
> used by the kernel will trip over itself quickly, alerting vendors
> to fix their ISA strings, but I'm not sure we can make that assumption
> for usermode extensions that Linux doesn't use, but does expose
> through hwprobe. What apps need to run in testing to exercise them?
> How long will those apps need to run before they trip over something?
> 
> The more I think I about it, the more I think the lack of CPUID / ID_*
> registers puts Linux in a tight spot. If Linux trustingly publishes
> what firmware tells it to to userspace and userspace blows up, Linux
> will have to share some of the blame for having misled it. So, should
> Linux validate everything it publishes somehow? Or, should it at least
> do relatively cheap sanity checks on everything it publishes in order
> to build some confidence?

Part of me wants to know why we should be going to a bunch of effort to
cover up for inaccurate devicetrees etc. Garbage in -> garbage out and let
them keep the pieces.
That said, if we were to do something with checks, we can't actually
even check everything and my opinion is that either we certify that
everything is VerifiedTM or we don't certify at all.

Cheers,
Conor.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/263c8be1/attachment.sig>

From conor at kernel.org  Thu Jun  4 09:43:38 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 17:43:38 +0100
Subject: [PATCH v2 4/7] dt-bindings: timer: Add RISC-V ACLINT mtimer
 bindings
In-Reply-To: <20260604143957.668047-5-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-5-joel@jms.id.au>
Message-ID: <20260604-refill-atonable-efa4867a6e89@spud>

On Fri, Jun 05, 2026 at 12:09:50AM +0930, Joel Stanley wrote:
> The mtimer hardware is described in The RISC-V Instruction Set Manual,
> Volume II Privileged Architecture, 3.2.1. Machine Timer (mtime and
> mtimecmp) Registers.
> 
> The ACLINT was a standalone spec that made it to v1.0-rc4, but was never
> ratified. As explained by Anup:
> 
> > Only the timer defined by ACLINT specification is relevant but the
> > RISC-V privileged specification already provides a high-level
> > definition of mtime and mtimecmp MMIO registers (see section "Machine
> > Timer (mtime and mtimecmp) Registers").
> >
> > Due to the above reasons, we dropped our plans to ratify ACLINT
> > specification in-favor of AIA IMSIC and RISC-V Privileged
> > specification.
> 
> Link: https://lists.riscv.org/g/tech-aia/topic/connections_between_aia_and/107177435
> Signed-off-by: Joel Stanley <joel at jms.id.au>
> ---
> v2:
>  - Use priv spec as reference
>  - Add soc name to tenstorrent compatible
>  - Fix reg property description
> ---
>  MAINTAINERS                                   |  1 +
>  .../bindings/timer/riscv,aclint-mtimer.yaml   | 56 +++++++++++++++++++
>  2 files changed, 57 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2fb1c75afd16..43dd9873bbc5 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -23005,6 +23005,7 @@ M:	Joel Stanley <jms at oss.tenstorrent.com>
>  L:	linux-riscv at lists.infradead.org
>  S:	Maintained
>  T:	git https://github.com/tenstorrent/linux.git
> +F:	Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
>  F:	Documentation/devicetree/bindings/clock/tenstorrent,atlantis-prcm-rcpu.yaml
>  F:	Documentation/devicetree/bindings/riscv/tenstorrent.yaml
>  F:	arch/riscv/boot/dts/tenstorrent/
> diff --git a/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> new file mode 100644
> index 000000000000..1d645570b191
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/timer/riscv,aclint-mtimer.yaml
> @@ -0,0 +1,56 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/timer/riscv,aclint-mtimer.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: RISC-V Advanced Core Local Interruptor (ACLINT) Machine-level Timer
> +
> +maintainers:
> +  - Joel Stanley <jms at oss.tenstorrent.com>
> +
> +description:
> +  The RISC-V machine-level timer exposes the memory-mapped mtime and per-hart
> +  mtimecmp registers defined in The RISC-V Instruction Set Manual, Volume II
> +  Privileged Architecture, 3.2.1. Machine Timer (mtime and mtimecmp) Registers.
> +
> +properties:
> +  compatible:
> +    items:
> +      - enum:
> +          - tenstorrent,atlantis-aclint-mtimer
> +          - qemu,aclint-mtimer
> +      - const: riscv,aclint-mtimer

Guess your v3 beat my reply to v2, but what I didn't want was the
riscv,aclint-mtimer compatible not the reference to the spec that you
actually implemented.
pw-bot: changes-requested

And that reminded me, there's a thead,c900-aclint-mtimer binding already
in the kernel, can't you piggy-back off that file instead of making a
new one?

Cheers,
Conor.

> +
> +  reg:
> +    items:
> +      - description: MTIMECMP registers, one per hart
> +      - description: MTIME register
> +
> +  reg-names:
> +    items:
> +      - const: mtimecmp
> +      - const: mtime
> +
> +  interrupts-extended:
> +    minItems: 1
> +    maxItems: 4095
> +
> +required:
> +  - compatible
> +  - reg
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    timer at ac000000 {
> +      compatible = "tenstorrent,atlantis-aclint-mtimer", "riscv,aclint-mtimer";
> +      reg = <0xac000000 0x8000>, <0xac008000 0x8000>;
> +      reg-names = "mtimecmp", "mtime";
> +      interrupts-extended = <&cpu1intc 7>,
> +                            <&cpu2intc 7>,
> +                            <&cpu3intc 7>,
> +                            <&cpu4intc 7>;
> +    };
> +...
> -- 
> 2.47.3
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/b666c387/attachment.sig>

From conor at kernel.org  Thu Jun  4 09:43:56 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 17:43:56 +0100
Subject: [PATCH v2 6/7] dt-bindings: riscv: Add Tenstorrent Atlantis
 platform
In-Reply-To: <20260604143957.668047-7-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-7-joel@jms.id.au>
Message-ID: <20260604-vengeful-revert-f3a6bf41c2f4@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/be8235e6/attachment.sig>

From conor at kernel.org  Thu Jun  4 09:44:12 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 17:44:12 +0100
Subject: [PATCH v2 3/7] dt-bindings: riscv: cpus: Add Tenstorrent Ascalon
In-Reply-To: <20260604143957.668047-4-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-4-joel@jms.id.au>
Message-ID: <20260604-ravioli-expansion-cf5215234bab@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/33a8a913/attachment.sig>

From conor at kernel.org  Thu Jun  4 09:44:29 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 17:44:29 +0100
Subject: [PATCH v2 2/7] dt-bindings: imsics: Add Tenstorrent Atlantis
 compatible
In-Reply-To: <20260604143957.668047-3-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-3-joel@jms.id.au>
Message-ID: <20260604-preview-cofounder-a9e6cd24a106@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/f9d7edf2/attachment.sig>

From conor at kernel.org  Thu Jun  4 09:47:49 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 17:47:49 +0100
Subject: [PATCH v2 7/7] riscv: dts: tenstorrent: Add Atlantis platform
In-Reply-To: <20260604143957.668047-8-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-8-joel@jms.id.au>
Message-ID: <20260604-pacifier-sludge-196f47ab3c11@spud>

On Fri, Jun 05, 2026 at 12:09:53AM +0930, Joel Stanley wrote:
> Add initial support for the Tenstorrent Atlantis platform, based on the
> Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.
> 
> The evb machine represents an internal bringup vehicle with just the
> interrupt controllers and a UART. This will be replaced in time with a
> full featured machine once details are available.
> 
> Co-developed-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>
> ---
> v2:
>  - Update mtimer compatible
>  - Add Drew's co-developed-by
>  - Correct aplic num-sources count
> ---
>  arch/riscv/boot/dts/tenstorrent/Makefile      |   1 +
>  .../boot/dts/tenstorrent/atlantis-evb.dts     |  33 ++
>  .../boot/dts/tenstorrent/atlantis-soc.dtsi    | 471 ++++++++++++++++++
>  3 files changed, 505 insertions(+)
>  create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
>  create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi
> 
> diff --git a/arch/riscv/boot/dts/tenstorrent/Makefile b/arch/riscv/boot/dts/tenstorrent/Makefile
> index 2c81faaba462..92d8bb1a683f 100644
> --- a/arch/riscv/boot/dts/tenstorrent/Makefile
> +++ b/arch/riscv/boot/dts/tenstorrent/Makefile
> @@ -1,2 +1,3 @@
>  # SPDX-License-Identifier: GPL-2.0
>  dtb-$(CONFIG_ARCH_TENSTORRENT) += blackhole-card.dtb
> +dtb-$(CONFIG_ARCH_TENSTORRENT) += atlantis-evb.dtb
> diff --git a/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
> new file mode 100644
> index 000000000000..06259cca8357
> --- /dev/null
> +++ b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
> @@ -0,0 +1,33 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/dts-v1/;
> +
> +#include "atlantis-soc.dtsi"
> +
> +/ {
> +	model = "Tenstorrent Atlantis development platform";
> +	compatible = "tenstorrent,atlantis-evb", "tenstorrent,atlantis";
> +
> +	#address-cells = <2>;
> +	#size-cells = <2>;
> +
> +	memory at 0 {
> +		device_type = "memory";
> +		reg = <0x0 0x00000000 0x0 0x80000000>,
> +		      <0x1 0x80000000 0x0 0x80000000>;
> +	};
> +
> +	aliases {
> +		serial0 = &uart1;
> +	};
> +
> +	chosen {
> +		bootargs = "earlycon console=ttyS0";

FYI, this should not be in here.

> +		stdout-path = "serial0";
> +	};
> +};
> +
> +&uart1 {
> +	/delete-property/ clocks;

Why are you doing this? Looks kinda suspect!

> +	clock-frequency = <5000000>;
> +	status = "okay";
> +};
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/dc7df0b2/attachment.sig>

From conor at kernel.org  Thu Jun  4 10:06:35 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 18:06:35 +0100
Subject: [PATCH v3 03/21] dt-bindings: pinctrl: Add
 starfive,jhb100-sys0-pinctrl
In-Reply-To: <ZQ4PR01MB12022B5C460A34260ABFCE9FF2102@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-4-changhuang.liang@starfivetech.com>
 <20260603-groin-valid-a1d4445f7a6b@spud>
 <ZQ4PR01MB12022B5C460A34260ABFCE9FF2102@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>
Message-ID: <20260604-sprout-zips-c2c29e26fe1d@spud>

On Thu, Jun 04, 2026 at 01:37:00AM +0000, Changhuang Liang wrote:
> Hi, Conor
> 
> Thanks for the review.
> 
> > On Tue, Jun 02, 2026 at 10:53:29PM -0700, Changhuang Liang wrote:
> > 
> > > +          slew-rate:
> > > +            enum: [ 0, 1 ]
> > > +            default: 0
> > > +            description: |
> > > +                0: slow (half frequency)
> > 
> > Half frequency? Slew rates are usually measured in volts per second, not hertz.
> > Do you know what the slew rates actually are and could put them in here as
> > the real units? Or is it just "slow" and "fast" in your docs with no precise
> > numbers?
> 
> Yes, there are no precise numbers in our documentation. I will remove "(half frequency)" in the next version.

If the rate is actually half, then you can say that. It's just
"frequency" I was objecting to.

> 
> > I've got no questions other than this, so once this question is sorted, I'll be
> > happy to ack all the bindings provided they're effectively the same.
> > 
> > > +                1: fast
> 
> Best Regards,
> Changhuang
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/976e934f/attachment.sig>

From conor at kernel.org  Thu Jun  4 10:13:19 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 4 Jun 2026 18:13:19 +0100
Subject: [PATCH v3 09/21] dt-bindings: pinctrl: Add
 starfive,jhb100-sys2-pinctrl
In-Reply-To: <20260603055347.66845-10-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-10-changhuang.liang@starfivetech.com>
Message-ID: <20260604-veggie-constrain-16a72066e82f@spud>

On Tue, Jun 02, 2026 at 10:53:35PM -0700, Changhuang Liang wrote:
> +          power-source:
> +            enum: [ 0, 2 ]
> +            description: |
> +                0: power supply of 3.3V
> +                2: power supply of 1.8V

I'd rather these were given in e.g. microvolts, rather than what look
like register values, that have no meaning when looking at the dts.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260604/6b1f7c02/attachment.sig>

From pjw at kernel.org  Thu Jun  4 13:56:21 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Thu, 4 Jun 2026 14:56:21 -0600 (MDT)
Subject: [PATCH] riscv: defconfig: Enable Eswin SoCs
In-Reply-To: <20260603-eswin_defconfig-v1-1-8471691d3153@oss.tenstorrent.com>
References: <20260603-eswin_defconfig-v1-1-8471691d3153@oss.tenstorrent.com>
Message-ID: <99cbc9ab-41ae-3b82-779e-bced60181ac5@kernel.org>

On Wed, 3 Jun 2026, Anirudh Srinivasan wrote:

> Enable support for Eswin SoCs in the default configuration, so that
> defconfig kernel/DTs are bootable on Hifive Premier P550 Board.
> 
> Signed-off-by: Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>

Thanks, queued for v7.2.

- Paul


From pjw at kernel.org  Thu Jun  4 15:34:49 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Thu, 4 Jun 2026 16:34:49 -0600 (MDT)
Subject: [PATCH 2/2] riscv: mm: Define DIRECT_MAP_PHYSMEM_END
In-Reply-To: <20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd@iscas.ac.cn>
References: <20260309-riscv-sparsemem-vmemmap-limits-v1-0-f40efe18e3cd@iscas.ac.cn> <20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd@iscas.ac.cn>
Message-ID: <533b4094-e97c-1661-1ad2-4e7aea683f4f@kernel.org>

On Mon, 9 Mar 2026, Vivian Wang wrote:

> On RISC-V, the actual mappable range of physical address space is
> dependent on the current MMU mode i.e. satp_mode (See
> Documentation/arch/riscv/vm-layout.rst).
> 
> Define the DIRECT_MAP_PHYSMEM_END macro based on the existing virtual
> address space layout macros to expose this information to
> get_free_mem_region(). Otherwise, it returns a region that couldn't be
> mapped, which breaks ZONE_DEVICE.
> 
> Cc: <stable at vger.kernel.org> # v6.13+
> Tested-by: Han Gao <gaohan at iscas.ac.cn> # SG2044
> Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>

Thanks, queued for v7.2.


- Paul


From pjw at kernel.org  Thu Jun  4 15:40:31 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Thu, 4 Jun 2026 16:40:31 -0600 (MDT)
Subject: [PATCH] riscv: cfi: reject unknown flags in PR_SET_CFI
In-Reply-To: <20260518183918.322545-1-ripatel@wii.dev>
References: <20260518183918.322545-1-ripatel@wii.dev>
Message-ID: <3f2d4628-a95d-89c3-2fd7-3e1a407d698a@kernel.org>

Hi,

On Mon, 18 May 2026, Richard Patel wrote:

> prctl(PR_SET_CFI,PR_CFI_BRANCH_LANDING_PADS) silently ignored
> unknown control values. Only PR_CFI_{ENABLE,DISABLE,LOCK} should
> be permitted.
<
> This is a uABI breaking change (fails previously accepted bits
> with EINVAL).

Thanks for the patch.  However, I'm not convinced that this actually 
breaks anything.  The behavior of the interface changes when unknown flags 
are specified, but I'm not aware of anything that relies on this specific 
behavior.

Does that match your understanding?


- Paul



From atwufei at 163.com  Thu Jun  4 16:03:13 2026
From: atwufei at 163.com (atwufei at 163.com)
Date: Fri,  5 Jun 2026 07:03:13 +0800
Subject: [PATCH v2 0/2] RISC-V: KVM: Fix skip of valid pages in gstage ops
Message-ID: <20260604230317.30501-1-atwufei@163.com>

From: Wu Fei <wu.fei9 at sanechips.com.cn>

The current gstage range walker unconditionally advances by 'page_size'
when a leaf PTE is not found, e.g. when the range to wp is
[0xfffff01fc000, 0xfffff023c000) , if found_leaf of 0xfffff01fc000
returns false and page_size is 2MB, it skips the whole range, but it's
possible to have valid entries in [0xfffff0200000, 0xfffff023c000), so
only [0xfffff01fc000, 0xfffff0200000) can be skipped safely. Both
wp/unamp have the same pattern.

dirty_log_test intentionally sets up the unaligned guest physical
address, after riscv kvm enabling KVM_DIRTY_LOG_INITIALLY_SET, it's easy
to trigger this bug if there is a larger window for guest to write more
pages before first collect_dirty_pages.

v2:
* reformat
* drop the patch to dirty_log_test, which is replaced by the one from
  Sean: https://github.com/kvm-x86/linux/commit/4e0fdd9b0d7d

Wu Fei (2):
  RISC-V: KVM: Fix skip of valid pages in kvm_riscv_gstage_wp_range
  RISC-V: KVM: Fix skip of valid pages in kvm_riscv_gstage_unmap_range

 arch/riscv/kvm/gstage.c | 38 +++++++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 17 deletions(-)

-- 
2.51.0



From atwufei at 163.com  Thu Jun  4 16:03:14 2026
From: atwufei at 163.com (atwufei at 163.com)
Date: Fri,  5 Jun 2026 07:03:14 +0800
Subject: [PATCH v2 1/2] RISC-V: KVM: Fix skip of valid pages in kvm_riscv_gstage_wp_range
In-Reply-To: <20260604230317.30501-1-atwufei@163.com>
References: <20260604230317.30501-1-atwufei@163.com>
Message-ID: <20260604230317.30501-2-atwufei@163.com>

From: Wu Fei <wu.fei9 at sanechips.com.cn>

The current gstage range walker unconditionally advances by 'page_size'
when a leaf PTE is not found, e.g. when the range to wp is
[0xfffff01fc000, 0xfffff023c000) and page_size is 2MB, if found_leaf of
0xfffff01fc000 returns false, it skip the whole range, but it's possible
to have valid entries in [0xfffff0200000, 0xfffff023c000).

Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
---
 arch/riscv/kvm/gstage.c | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index d9fe8be2a151..2b141a78ecac 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -429,14 +429,14 @@ void kvm_riscv_gstage_wp_range(struct kvm_gstage *gstage, gpa_t start, gpa_t end
 		if (ret)
 			break;
 
-		if (!found_leaf)
-			goto next;
-
-		addr = ALIGN_DOWN(addr, page_size);
-		kvm_riscv_gstage_op_pte(gstage, addr, ptep,
-					ptep_level, GSTAGE_OP_WP);
-next:
-		addr += page_size;
+		if (!found_leaf) {
+			addr = ALIGN(addr + 1, page_size);
+		} else {
+			addr = ALIGN_DOWN(addr, page_size);
+			kvm_riscv_gstage_op_pte(gstage, addr, ptep,
+						ptep_level, GSTAGE_OP_WP);
+			addr += page_size;
+		}
 	}
 }
 
-- 
2.51.0



From atwufei at 163.com  Thu Jun  4 16:03:15 2026
From: atwufei at 163.com (atwufei at 163.com)
Date: Fri,  5 Jun 2026 07:03:15 +0800
Subject: [PATCH v2 2/2] RISC-V: KVM: Fix skip of valid pages in kvm_riscv_gstage_unmap_range
In-Reply-To: <20260604230317.30501-1-atwufei@163.com>
References: <20260604230317.30501-1-atwufei@163.com>
Message-ID: <20260604230317.30501-3-atwufei@163.com>

From: Wu Fei <wu.fei9 at sanechips.com.cn>

Same as kvm_riscv_gstage_wp_range, the possible valid pages should not
be skipped if !found_leaf. Different from wp case, which can
write-protect more than asked, unmap can't do that, no splitting is
added right now but a warning is logged instead.

Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>
---
 arch/riscv/kvm/gstage.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)

diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
index 2b141a78ecac..d78f5aeb8b40 100644
--- a/arch/riscv/kvm/gstage.c
+++ b/arch/riscv/kvm/gstage.c
@@ -395,15 +395,19 @@ void kvm_riscv_gstage_unmap_range(struct kvm_gstage *gstage,
 		if (ret)
 			break;
 
-		if (!found_leaf)
-			goto next;
-
-		if (!(addr & (page_size - 1)) && ((end - addr) >= page_size))
-			kvm_riscv_gstage_op_pte(gstage, addr, ptep,
-						ptep_level, GSTAGE_OP_CLEAR);
+		if (!found_leaf) {
+			addr = ALIGN(addr + 1, page_size);
+		} else {
+			if (!(addr & (page_size - 1)) && ((end - addr) >= page_size))
+				kvm_riscv_gstage_op_pte(gstage, addr, ptep,
+							ptep_level, GSTAGE_OP_CLEAR);
+			else {
+				WARN_ONCE(1, "Skip unmap range addr: %#llx, end: %#llx, page_size: %#lx\n",
+						addr, end, page_size);
+			}
 
-next:
-		addr += page_size;
+			addr += page_size;
+		}
 
 		/*
 		 * If the range is too large, release the kvm->mmu_lock
-- 
2.51.0



From pjw at kernel.org  Thu Jun  4 16:41:10 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Thu, 4 Jun 2026 17:41:10 -0600 (MDT)
Subject: [PATCH v1 1/2] riscv: stacktrace: Remove bogus -0x4 offset in
 non-FP walk_stackframe
In-Reply-To: <20260603115329.791603-2-qirui.001@bytedance.com>
References: <20260603115329.791603-1-qirui.001@bytedance.com> <20260603115329.791603-2-qirui.001@bytedance.com>
Message-ID: <f04aa9b7-9118-d9f6-6431-75234dc2a207@kernel.org>

On Wed, 3 Jun 2026, Rui Qi wrote:

> In the non-frame-pointer version of walk_stackframe, each value read
> from the stack is treated as a potential return address and has 0x4
> subtracted before being used as the program counter. This was intended
> to convert the return address (the instruction after a call) back to
> the call site, but it is incorrect:
> 
> 1. RISC-V has variable-length instructions due to the RVC (compressed
>    instruction) extension. A call instruction can be either 4 bytes
>    (regular) or 2 bytes (compressed, e.g. c.jal). Subtracting a fixed
>    0x4 assumes all call instructions are 4 bytes, which is wrong for
>    compressed instructions.
> 
> 2. Stack traces conventionally report return addresses, not call sites.
>    Other architectures (ARM64, x86, ARM) do not subtract instruction
>    size from return addresses in their stack unwinding code.
> 
> 3. The frame-pointer version of walk_stackframe already dropped the
>    -0x4 offset. Commit b785ec129bd9 ("riscv/ftrace: Add
>    HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support") replaced "pc =
>    frame->ra - 0x4" with ftrace_graph_ret_addr(), and the commit
>    message explicitly noted that "the original calculation, pc =
>    frame->ra - 4, is buggy when the instruction at the return address
>    happened to be a compressed inst." The non-FP version was simply
>    overlooked.
> 
> Remove the bogus -0x4 offset to match the FP version and the
> conventions used by other architectures.

Thanks for the very clear commit message and for the fix.  Queued for 
v7.1-rc.


- Paul


From pjw at kernel.org  Thu Jun  4 17:33:13 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Thu, 4 Jun 2026 18:33:13 -0600 (MDT)
Subject: [PATCH v1 2/2] riscv: stacktrace: Use %pB for backtrace
 display
In-Reply-To: <20260603115329.791603-3-qirui.001@bytedance.com>
References: <20260603115329.791603-1-qirui.001@bytedance.com> <20260603115329.791603-3-qirui.001@bytedance.com>
Message-ID: <4197ee54-6c69-cb72-5966-c60ba321a6fa@kernel.org>

On Wed, 3 Jun 2026, Rui Qi wrote:

> The print_trace_address callback uses print_ip_sym which formats
> addresses with %pS. This does not adjust the address before symbol
> lookup, so when a noreturn function (e.g. panic, do_exit) is the last
> call in a function, the saved return address can point to the start of
> the next function, and kallsyms resolves it to the wrong symbol.
> 
> The kernel provides %pB (sprint_backtrace) specifically for this
> purpose: it subtracts 1 from the address before symbol lookup, which
> is sufficient to fall back into the calling function range. x86 uses
> %pB in its printk_stack_address for the same reason.
> 
> Replace print_ip_sym with a direct printk using %pB, matching the
> pattern used by x86.
> 
> Signed-off-by: Rui Qi <qirui.001 at bytedance.com>

The Sashiko review mentions that the x86 backtrace code uses %pS for exact 
instruction pointers coming from registers (show_regs_if_on_stack()), vs. 
%pB for return addresses on the stack (printk_stack_address()):

    https://sashiko.dev/#/patchset/20260603115329.791603-1-qirui.001%40bytedance.com

Do we need to incorporate similar logic?


- Paul


From troy.mitchell at linux.spacemit.com  Thu Jun  4 18:35:37 2026
From: troy.mitchell at linux.spacemit.com (Troy Mitchell)
Date: Fri, 05 Jun 2026 09:35:37 +0800
Subject: [PATCH v7 0/2] i2c: spacemit: improve clock handling and
 cleanups
In-Reply-To: <20260508-k1-i2c-ilcr-v7-0-8c2dde5c3ed5@linux.spacemit.com>
References: <20260508-k1-i2c-ilcr-v7-0-8c2dde5c3ed5@linux.spacemit.com>
Message-ID: <DJ0QAKGJE2SQ.DKPXWGPGC161@linux.spacemit.com>

On Fri May 8, 2026 at 3:25 PM CST, Troy Mitchell wrote:
> This patch series contains a set of small improvements and cleanups for
> the SpacemiT I2C controller driver.
>
> The main change in this series is to improve SCL frequency accuracy by
> configuring the ILCR register based on the requested clock rate, rather
> than relying on the hardware reset defaults.
>
> The ILCR is exposed as a managed clock via the Common Clock Framework,
> allowing the driver to program appropriate divider values for standard
> and fast modes.
>
> In addition, the series removes a spurious warning when the optional
> clock-frequency DT property is absent.
>
> Signed-off-by: Troy Mitchell <troy.mitchell at linux.spacemit.com>
Just a gentle ping on this series. 

Please let me know if anyone has any feedback or if there is anything 
I should update.

                                  - Troy


From asrinivasan at oss.tenstorrent.com  Thu Jun  4 20:15:59 2026
From: asrinivasan at oss.tenstorrent.com (Anirudh Srinivasan)
Date: Thu, 4 Jun 2026 22:15:59 -0500
Subject: [PATCH v2 7/7] riscv: dts: tenstorrent: Add Atlantis platform
In-Reply-To: <20260604143957.668047-8-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au> <20260604143957.668047-8-joel@jms.id.au>
Message-ID: <CAEev2e-OuutFYQUo2mtzvM5z_brneR+qn_WrPbp5_DeNq-7Fmg@mail.gmail.com>

On Thu, Jun 4, 2026 at 9:41?AM Joel Stanley <joel at jms.id.au> wrote:
>
> Add initial support for the Tenstorrent Atlantis platform, based on the
> Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.
>
> The evb machine represents an internal bringup vehicle with just the
> interrupt controllers and a UART. This will be replaced in time with a
> full featured machine once details are available.
>
> Co-developed-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Drew Fustini <fustini at kernel.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>
> ---
> v2:
>  - Update mtimer compatible
>  - Add Drew's co-developed-by
>  - Correct aplic num-sources count
> ---
>  arch/riscv/boot/dts/tenstorrent/Makefile      |   1 +
>  .../boot/dts/tenstorrent/atlantis-evb.dts     |  33 ++
>  .../boot/dts/tenstorrent/atlantis-soc.dtsi    | 471 ++++++++++++++++++
>  3 files changed, 505 insertions(+)
>  create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
>  create mode 100644 arch/riscv/boot/dts/tenstorrent/atlantis-soc.dtsi

> +
> +               prcm_rcpu: clock-controller at d0000000 {
> +                       compatible = "tenstorrent,atlantis-prcm-rcpu";
> +                       reg = <0x00 0xd0000000 0x00 0x10000>;
> +                       clocks = <&osc_24m>;
> +                       #clock-cells = <1>;
> +                       #reset-cells = <1>;
> +                       assigned-clocks = <&prcm_rcpu CLK_RCPU_ROOT>, <&prcm_rcpu CLK_NOCC_CLK>;
> +                       assigned-clock-parents = <&prcm_rcpu CLK_RCPU_ROOT>,
> +                                                <&prcm_rcpu CLK_NOC_PLL>;

This should be
assigned-clock-parents = <&prcm_rcpu CLK_RCPU_PLL>,
                                <&prcm_rcpu CLK_NOC_PLL>;


From inochiama at gmail.com  Thu Jun  4 20:50:08 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Fri, 5 Jun 2026 11:50:08 +0800
Subject: [PATCH v3 11/15] riscv: dts: sophgo: sg2044: Add Zic64b ISA
 extension
In-Reply-To: <20260603-rva23u64-hwprobe-v2-v3-11-5529a7b28384@gmail.com>
References: <20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384@gmail.com>
 <20260603-rva23u64-hwprobe-v2-v3-11-5529a7b28384@gmail.com>
Message-ID: <aiJG85NxiVQWOAQt@inochi.infowork>

On Wed, Jun 03, 2026 at 07:12:06AM -0400, Guodong Xu wrote:
> The SG2044 cores have 64-byte cache blocks, described by their
> cbom/cbop/cboz-block-size of 64, so they implement Zic64b.  Declare it in
> each core's riscv,isa-extensions.
> 
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>

I have confirmed SG2044 supports this features.

Acked-by: Inochi Amaoto <inochiama at gmail.com>

Regards,
Inochi

> ---
> v3: New patch.
> ---
>  arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi | 128 ++++++++++++++--------------
>  1 file changed, 64 insertions(+), 64 deletions(-)
> 
> diff --git a/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi b/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
> index 3135409c21492..2ac4a41bbc3a7 100644
> --- a/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
> +++ b/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
> @@ -31,7 +31,7 @@ cpu0: cpu at 0 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -67,7 +67,7 @@ cpu1: cpu at 1 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -103,7 +103,7 @@ cpu2: cpu at 2 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -139,7 +139,7 @@ cpu3: cpu at 3 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -175,7 +175,7 @@ cpu4: cpu at 4 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -211,7 +211,7 @@ cpu5: cpu at 5 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -247,7 +247,7 @@ cpu6: cpu at 6 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -283,7 +283,7 @@ cpu7: cpu at 7 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -319,7 +319,7 @@ cpu8: cpu at 8 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -355,7 +355,7 @@ cpu9: cpu at 9 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -391,7 +391,7 @@ cpu10: cpu at 10 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -427,7 +427,7 @@ cpu11: cpu at 11 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -463,7 +463,7 @@ cpu12: cpu at 12 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -499,7 +499,7 @@ cpu13: cpu at 13 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -535,7 +535,7 @@ cpu14: cpu at 14 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -571,7 +571,7 @@ cpu15: cpu at 15 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -607,7 +607,7 @@ cpu16: cpu at 16 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -643,7 +643,7 @@ cpu17: cpu at 17 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -679,7 +679,7 @@ cpu18: cpu at 18 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -715,7 +715,7 @@ cpu19: cpu at 19 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -751,7 +751,7 @@ cpu20: cpu at 20 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -787,7 +787,7 @@ cpu21: cpu at 21 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -823,7 +823,7 @@ cpu22: cpu at 22 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -859,7 +859,7 @@ cpu23: cpu at 23 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -895,7 +895,7 @@ cpu24: cpu at 24 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -931,7 +931,7 @@ cpu25: cpu at 25 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -967,7 +967,7 @@ cpu26: cpu at 26 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1003,7 +1003,7 @@ cpu27: cpu at 27 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1039,7 +1039,7 @@ cpu28: cpu at 28 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1075,7 +1075,7 @@ cpu29: cpu at 29 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1111,7 +1111,7 @@ cpu30: cpu at 30 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1147,7 +1147,7 @@ cpu31: cpu at 31 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1183,7 +1183,7 @@ cpu32: cpu at 32 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1219,7 +1219,7 @@ cpu33: cpu at 33 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1255,7 +1255,7 @@ cpu34: cpu at 34 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1291,7 +1291,7 @@ cpu35: cpu at 35 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1327,7 +1327,7 @@ cpu36: cpu at 36 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1363,7 +1363,7 @@ cpu37: cpu at 37 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1399,7 +1399,7 @@ cpu38: cpu at 38 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1435,7 +1435,7 @@ cpu39: cpu at 39 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1471,7 +1471,7 @@ cpu40: cpu at 40 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1507,7 +1507,7 @@ cpu41: cpu at 41 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1543,7 +1543,7 @@ cpu42: cpu at 42 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1579,7 +1579,7 @@ cpu43: cpu at 43 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1615,7 +1615,7 @@ cpu44: cpu at 44 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1651,7 +1651,7 @@ cpu45: cpu at 45 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1687,7 +1687,7 @@ cpu46: cpu at 46 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1723,7 +1723,7 @@ cpu47: cpu at 47 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1759,7 +1759,7 @@ cpu48: cpu at 48 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1795,7 +1795,7 @@ cpu49: cpu at 49 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1831,7 +1831,7 @@ cpu50: cpu at 50 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1867,7 +1867,7 @@ cpu51: cpu at 51 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1903,7 +1903,7 @@ cpu52: cpu at 52 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1939,7 +1939,7 @@ cpu53: cpu at 53 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -1975,7 +1975,7 @@ cpu54: cpu at 54 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2011,7 +2011,7 @@ cpu55: cpu at 55 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2047,7 +2047,7 @@ cpu56: cpu at 56 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2083,7 +2083,7 @@ cpu57: cpu at 57 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2119,7 +2119,7 @@ cpu58: cpu at 58 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2155,7 +2155,7 @@ cpu59: cpu at 59 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2191,7 +2191,7 @@ cpu60: cpu at 60 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2227,7 +2227,7 @@ cpu61: cpu at 61 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2263,7 +2263,7 @@ cpu62: cpu at 62 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> @@ -2299,7 +2299,7 @@ cpu63: cpu at 63 {
>  					       "svinval", "svnapot", "svpbmt",
>  					       "zawrs", "zba", "zbb", "zbc",
>  					       "zbs", "zca", "zcb", "zcd",
> -					       "zfa", "zfbfmin", "zfh", "zfhmin",
> +					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
>  					       "zicbom", "zicbop", "zicboz", "ziccrse",
>  					       "zicntr", "zicond","zicsr", "zifencei",
>  					       "zihintntl", "zihintpause", "zihpm",
> 
> -- 
> 2.43.0
> 
> 
> -- 
> kvm-riscv mailing list
> kvm-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kvm-riscv


From cuiyunhui at bytedance.com  Thu Jun  4 21:03:57 2026
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Fri, 5 Jun 2026 12:03:57 +0800
Subject: [External] Re: [PATCH] riscv: mm: exclude invalid THP PMDs from
 page table check
In-Reply-To: <252be770-4d9f-954a-9388-8f7b52a92d90@kernel.org>
References: <20260515065048.94564-1-cuiyunhui@bytedance.com> <252be770-4d9f-954a-9388-8f7b52a92d90@kernel.org>
Message-ID: <CAEEQ3wmnZnoDm_YvHTwSdTs1RJTt009tVFQM-TtS+6O8TJpG2w@mail.gmail.com>

Hi Paul,

On Sat, May 23, 2026 at 7:10?AM Paul Walmsley <pjw at kernel.org> wrote:
>
> On Fri, 15 May 2026, Yunhui Cui wrote:
>
> > RISC-V THP splitting uses a temporary invalid PMD state where
> > pmd_mkinvalid() clears _PAGE_PRESENT and _PAGE_PROT_NONE but leaves
> > _PAGE_LEAF set so the MM code can still recognize the PMD as a THP split
> > in-progress entry.
> >
> > That temporary state no longer describes a user-accessible mapping, but
> > page_table_check currently treats it as one because the RISC-V PMD
> > user-accessibility test only checks whether the PMD is a leaf and has
> > user permissions.
> >
> > As a result, when a PMD-sized anonymous THP is split during a COW fault,
> > page_table_check can account the invalid intermediate PMD as a live PMD
> > mapping, and then account the replacement PTE mappings again when the
> > split installs the PTE table. This leaves stale PMD accounting behind and
> > later triggers page_table_check failures such as a non-zero
> > anon_map_count when the folio is freed.
> >
> > Fix this by tightening pmd_user_accessible_page() so PMD page-table-check
> > accounting only considers leaf PMDs that still carry either
> > _PAGE_PRESENT or _PAGE_PROT_NONE. This preserves the THP split semantics
> > required by the MM code while preventing page_table_check from treating
> > invalid split PMDs as live user mappings.
> >
> > With CONFIG_PAGE_TABLE_CHECK=y and CONFIG_PAGE_TABLE_CHECK_ENFORCED=y,
> > tools/testing/selftests/mm/cow completes successfully on RISC-V after
> > this change.
> >
> > Fixes: 3fee229a8eb9 ("riscv/mm: enable ARCH_SUPPORTS_PAGE_TABLE_CHECK")
> > Cc: stable at vger.kernel.org
> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
>
> Thanks for the patch, but it doesn't apply as-is.  Could you fix it and
> resend?

Thanks for the heads-up. I have fixed the apply issue and resent it here:
https://lore.kernel.org/all/20260523042052.35476-1-cuiyunhui at bytedance.com/

>
>
> - Paul

 Thanks,
 Yunhui


From mpe at kernel.org  Thu Jun  4 21:50:54 2026
From: mpe at kernel.org (Michael Ellerman)
Date: Fri, 5 Jun 2026 14:50:54 +1000
Subject: [PATCH] riscv: defconfig: thead: enable PCA953X GPIO driver
In-Reply-To: <20260603082132.3200787-1-m.szyprowski@samsung.com>
References: <CGME20260603082156eucas1p1f44a198f7957d9d82ec0b8bc296fb03c@eucas1p1.samsung.com>
 <20260603082132.3200787-1-m.szyprowski@samsung.com>
Message-ID: <7ffb4a7c-ea74-431a-8be9-1a1d7418b467@kernel.org>

On 3/6/26 6:21 pm, Marek Szyprowski wrote:
> Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
> LicheePi4a board.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> ---
>   arch/riscv/configs/defconfig | 2 ++
>   1 file changed, 2 insertions(+)
> 
> diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
> index 08445df56006..a51a423d53f4 100644
> --- a/arch/riscv/configs/defconfig
> +++ b/arch/riscv/configs/defconfig
> @@ -174,6 +174,8 @@ CONFIG_PINCTRL_SOPHGO_SG2002=y
>   CONFIG_GPIO_DWAPB=y
>   CONFIG_GPIO_SIFIVE=y
>   CONFIG_GPIO_SPACEMIT_K1=y
> +CONFIG_GPIO_PCA953X=y
> +CONFIG_GPIO_PCA953X_IRQ=y
Does it need to be built-in, or would a module work?

It's not a huge driver (~20KB), but it all adds up.

cheers


From changhuang.liang at starfivetech.com  Thu Jun  4 22:13:38 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Fri, 5 Jun 2026 05:13:38 +0000
Subject: [PATCH v3 03/21] dt-bindings: pinctrl: Add
 starfive,jhb100-sys0-pinctrl
In-Reply-To: <20260604-sprout-zips-c2c29e26fe1d@spud>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-4-changhuang.liang@starfivetech.com>
 <20260603-groin-valid-a1d4445f7a6b@spud>
 <ZQ4PR01MB12022B5C460A34260ABFCE9FF2102@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>
 <20260604-sprout-zips-c2c29e26fe1d@spud>
Message-ID: <ZQ4PR01MB12021C09262AEBEC976D7642F2112@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>

Hi, Conor

> On Thu, Jun 04, 2026 at 01:37:00AM +0000, Changhuang Liang wrote:
> > Hi, Conor
> >
> > Thanks for the review.
> >
> > > On Tue, Jun 02, 2026 at 10:53:29PM -0700, Changhuang Liang wrote:
> > >
> > > > +          slew-rate:
> > > > +            enum: [ 0, 1 ]
> > > > +            default: 0
> > > > +            description: |
> > > > +                0: slow (half frequency)
> > >
> > > Half frequency? Slew rates are usually measured in volts per second, not
> hertz.
> > > Do you know what the slew rates actually are and could put them in
> > > here as the real units? Or is it just "slow" and "fast" in your docs
> > > with no precise numbers?
> >
> > Yes, there are no precise numbers in our documentation. I will remove "(half
> frequency)" in the next version.
> 
> If the rate is actually half, then you can say that. It's just "frequency" I was
> objecting to.

I checked the documentation. It doesn't explicitly mention "half"; it only describes "slow" and "fast"

> 
> >
> > > I've got no questions other than this, so once this question is
> > > sorted, I'll be happy to ack all the bindings provided they're effectively the
> same.
> > >
> > > > +                1: fast
> >

Best Regards,
Changhuang



From changhuang.liang at starfivetech.com  Thu Jun  4 22:14:48 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Fri, 5 Jun 2026 05:14:48 +0000
Subject: [PATCH v3 09/21] dt-bindings: pinctrl: Add
 starfive,jhb100-sys2-pinctrl
In-Reply-To: <20260604-veggie-constrain-16a72066e82f@spud>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-10-changhuang.liang@starfivetech.com>
 <20260604-veggie-constrain-16a72066e82f@spud>
Message-ID: <ZQ4PR01MB12020AA4421025B25132CF01F2112@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>

Hi, Conor

Thanks for the review.

> On Tue, Jun 02, 2026 at 10:53:35PM -0700, Changhuang Liang wrote:
> > +          power-source:
> > +            enum: [ 0, 2 ]
> > +            description: |
> > +                0: power supply of 3.3V
> > +                2: power supply of 1.8V
> 
> I'd rather these were given in e.g. microvolts, rather than what look like
> register values, that have no meaning when looking at the dts.

OK, I will try this method.

Best Regards,
Changhuang


From wangruikang at iscas.ac.cn  Thu Jun  4 22:23:22 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Fri, 05 Jun 2026 13:23:22 +0800
Subject: [PATCH v3] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
Message-ID: <20260605-mark-after-vmemmap-populate-v3-1-a06001ac9264@iscas.ac.cn>

section_activate() does not flush TLB after populating new vmemmap
pages. On most architectures, this is okay. However it is a problem on
RISC-V since there the TLB caching non-present entries is permitted,
which causes spurious faults on some hardwares.

This seems to be most easily reproduced with DEBUG_VM=y and
PAGE_POISONING=y, which causes these newly mapped struct pages to be
poisoned i.e. written to immediately after mapping.

Add a hook vmemmap_populate_finalize() in __populate_section_memmap()
after population, to allow architectures to handle such situations as
needed. Then implement it on RISC-V to arrange for the existing
exception handler code to deal with these faults if they happen.

Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
---
Depends on my earlier kfence fixes for mark_new_valid_map() [1].

Found while testing AMD_HSA/ZONE_DEVICE on SpacemiT K3. Using
ZONE_DEVICE requires another fix [2].

[1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn
[2]: https://lore.kernel.org/linux-riscv/20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd at iscas.ac.cn
---
Changes in v3:
- Merged back into one patch (Mike)
- (No code changes otherwise.)
- Link to v2: https://patch.msgid.link/20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434 at iscas.ac.cn

Changes in v2:
- Split patch in two, hook point and riscv hook 
- Explain hook necessity in patch 1 message (Mike)
- Make hook #define based (Mike)
- Call finalize hook only on populate success
- Link to v1: https://patch.msgid.link/20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16 at iscas.ac.cn
---
 arch/riscv/include/asm/pgtable.h | 4 ++++
 arch/riscv/mm/init.c             | 6 ++++++
 mm/sparse-vmemmap.c              | 8 ++++++++
 3 files changed, 18 insertions(+)

diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index a1a7c6520a09..aa0f50e3d534 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -1243,6 +1243,10 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
 #define TASK_SIZE	FIXADDR_START
 #endif
 
+/* Needed on SPARSEMEM_VMEMMAP */
+#define vmemmap_populate_finalize vmemmap_populate_finalize
+void __meminit vmemmap_populate_finalize(void);
+
 #else /* CONFIG_MMU */
 
 #define PAGE_SHARED		__pgprot(0)
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index 706f43523935..cf9ae4099f82 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1360,6 +1360,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
 	 */
 	return vmemmap_populate_hugepages(start, end, node, altmap);
 }
+
+void __meminit vmemmap_populate_finalize(void)
+{
+	/* Avoid faults on cached non-present TLB entries. */
+	mark_new_valid_map();
+}
 #endif
 
 #if defined(CONFIG_MMU) && defined(CONFIG_64BIT)
diff --git a/mm/sparse-vmemmap.c b/mm/sparse-vmemmap.c
index 6eadb9d116e4..2a8b923fabe8 100644
--- a/mm/sparse-vmemmap.c
+++ b/mm/sparse-vmemmap.c
@@ -544,6 +544,12 @@ static int __meminit vmemmap_populate_compound_pages(unsigned long start_pfn,
 
 #endif
 
+#ifndef vmemmap_populate_finalize
+static void __meminit vmemmap_populate_finalize(void)
+{
+}
+#endif
+
 struct page * __meminit __populate_section_memmap(unsigned long pfn,
 		unsigned long nr_pages, int nid, struct vmem_altmap *altmap,
 		struct dev_pagemap *pgmap)
@@ -564,6 +570,8 @@ struct page * __meminit __populate_section_memmap(unsigned long pfn,
 	if (r < 0)
 		return NULL;
 
+	vmemmap_populate_finalize();
+
 	return pfn_to_page(pfn);
 }
 

---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260525-mark-after-vmemmap-populate-68bd790839c9
prerequisite-message-id: <20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn>
prerequisite-patch-id: fdc42f2647e21d111f44a6532887a6705cd470a9
prerequisite-patch-id: 096fa339c84c36643ae4311fd8362dc63e23d950
prerequisite-patch-id: 305c876a5f4a23a840a8142aea79b796ed297545
prerequisite-patch-id: d78cb55d6a616b1170f06a401c8fd44acd11e5d5
prerequisite-patch-id: b02b4a76e94f3e2821291d4c23b46f6e5ecf5203

Best regards,
--  
Vivian Wang <wangruikang at iscas.ac.cn>



From anup at brainfault.org  Thu Jun  4 23:49:03 2026
From: anup at brainfault.org (Anup Patel)
Date: Fri, 5 Jun 2026 12:19:03 +0530
Subject: [PATCH] RISC-V: KVM: Enhance the logging check for mmu mapping
In-Reply-To: <20260528113840.2629186-1-inochiama@gmail.com>
References: <20260528113840.2629186-1-inochiama@gmail.com>
Message-ID: <CAAhSdy096z4SdwQKBxM0ZtE5=i3UZrhMD-BcES9UdP5OgajqEA@mail.gmail.com>

On Thu, May 28, 2026 at 5:08?PM Inochi Amaoto <inochiama at gmail.com> wrote:
>
> When enabling dirty ring, the dirty bitmap is disable, and the logging
> check is always false as the RISC-V architecture does not select
> "NEED_KVM_DIRTY_RING_WITH_BITMAP". Although the dirty log is recorded
> since the write path already trying to add the dirty log, the logic for
> logging check is broken and some side effect will occurs.
>
> Enhance the logging check for mmu mapping so it can check both the dirty
> ring and the dirty bitmap.
>
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> ---
>  arch/riscv/kvm/mmu.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 2d3def024270..b5873bca9dce 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -142,9 +142,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
>                                 enum kvm_mr_change change)
>  {
>         /*
> -        * At this point memslot has been committed and there is an
> -        * allocated dirty_bitmap[], dirty pages will be tracked while
> -        * the memory slot is write protected.
> +        * At this point memslot has been committed and dirty pages will be
> +        * tracked while the memory slot is write protected.
>          */
>         if (change != KVM_MR_DELETE && new->flags & KVM_MEM_LOG_DIRTY_PAGES) {
>                 if (kvm_dirty_log_manual_protect_and_init_set(kvm))
> @@ -433,8 +432,8 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
>         struct vm_area_struct *vma;
>         struct kvm *kvm = vcpu->kvm;
>         struct kvm_mmu_memory_cache *pcache = &vcpu->arch.mmu_page_cache;
> -       bool logging = (memslot->dirty_bitmap &&
> -                       !(memslot->flags & KVM_MEM_READONLY)) ? true : false;

Why is this not correct approach to determine whether logging is enabled ?

KVM ARM64 does a very similar thing (Refer, memslot_is_logging() in
arch/arm64/kvm/mmu.c).

> +       bool logging = kvm_slot_dirty_track_enabled(memslot) &&
> +                      !(memslot->flags & KVM_MEM_READONLY);
>         unsigned long vma_pagesize, mmu_seq;
>         struct kvm_gstage gstage;
>         struct page *page;
> --
> 2.54.0
>

Regards,
Anup


From mhi at mailbox.org  Thu Jun  4 23:59:58 2026
From: mhi at mailbox.org (Maurice Hieronymus)
Date: Fri, 05 Jun 2026 08:59:58 +0200
Subject: [PATCH v2 0/2] rust: clk: Add ExclusiveClk and use it in
 pwm-th1520
Message-ID: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>

Add a Rust binding for clk_rate_exclusive_get() / clk_rate_exclusive_put()
and use it in pwm-th1520, which previously carried a TODO noting the
missing binding.

Based on pwm/for-next.

Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>
---
Changes in v2:
- Rebase on pwm/for-next
- Remove newline after [`clk_rate_exclusive_get`] comment
- Remove unused [`struct clk`] link
- Put semicolon outside of unsafe block
- Link to v1: https://lore.kernel.org/r/20260526-rate-exclusive-get-th1520-v1-0-34cf034e1764 at mailbox.org

---
Maurice Hieronymus (2):
      rust: clk: Add ExclusiveClk wrapper for clk_rate_exclusive_get
      pwm: th1520: Lock clock rate with clk_rate_exclusive_get

 drivers/pwm/pwm_th1520.rs |  8 +++----
 rust/kernel/clk.rs        | 60 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 63 insertions(+), 5 deletions(-)
---
base-commit: 5b5e33c44a491d5b5e019f527e028bd567a226fa
change-id: 20260526-rate-exclusive-get-th1520-764a949de18e

Best regards,
-- 
Maurice Hieronymus <mhi at mailbox.org>



From mhi at mailbox.org  Thu Jun  4 23:59:59 2026
From: mhi at mailbox.org (Maurice Hieronymus)
Date: Fri, 05 Jun 2026 08:59:59 +0200
Subject: [PATCH v2 1/2] rust: clk: Add ExclusiveClk wrapper for
 clk_rate_exclusive_get
In-Reply-To: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>
References: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>
Message-ID: <20260605-rate-exclusive-get-th1520-v2-1-695640bf7249@mailbox.org>

Add Rust bindings for clk_rate_exclusive_get() and
clk_rate_exclusive_put().

Clk::rate_exclusive_get() consumes the Clk and returns an ExclusiveClk;
the matching put is issued from its Drop impl. ExclusiveClk derefs to
Clk so existing rate / prepare / enable APIs remain available on the
locked handle.

Reviewed-by: Alice Ryhl <aliceryhl at google.com>
Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>
---
 rust/kernel/clk.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 60 insertions(+)

diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index 7abbd0767d8c..f834f4833f18 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -249,6 +249,22 @@ pub fn set_rate(&self, rate: Hertz) -> Result {
             // [`clk_set_rate`].
             to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_hz()) })
         }
+
+        /// Acquire exclusive control over the clock's rate.
+        ///
+        /// Consumes the [`Clk`] and returns an [`ExclusiveClk`] that releases the exclusivity
+        /// when dropped. While held, no other consumer may change the clock's rate.
+        ///
+        /// Equivalent to the kernel's [`clk_rate_exclusive_get`] API. Must not be called from
+        /// atomic context.
+        ///
+        /// [`clk_rate_exclusive_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_rate_exclusive_get
+        pub fn rate_exclusive_get(self) -> Result<ExclusiveClk> {
+            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
+            // [`clk_rate_exclusive_get`].
+            to_result(unsafe { bindings::clk_rate_exclusive_get(self.as_raw()) })?;
+            Ok(ExclusiveClk(self))
+        }
     }
 
     impl Drop for Clk {
@@ -329,6 +345,50 @@ fn deref(&self) -> &Clk {
             &self.0
         }
     }
+
+    /// A [`Clk`] with exclusive control over its rate.
+    ///
+    /// While an [`ExclusiveClk`] exists, no other consumer of the same clock may change its rate.
+    /// Obtained by calling [`Clk::rate_exclusive_get`]; the exclusivity is released automatically
+    /// when the value is dropped, after which the inner [`Clk`] is dropped as usual.
+    ///
+    /// # Invariants
+    ///
+    /// An [`ExclusiveClk`] instance owns a [`Clk`] for which `clk_rate_exclusive_get` has been
+    /// called and the matching `clk_rate_exclusive_put` has not yet been called.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use kernel::clk::{Clk, ExclusiveClk};
+    /// use kernel::device::Device;
+    /// use kernel::error::Result;
+    ///
+    /// fn lock_rate(dev: &Device) -> Result<ExclusiveClk> {
+    ///     let clk = Clk::get(dev, None)?;
+    ///     clk.prepare_enable()?;
+    ///     clk.rate_exclusive_get()
+    /// }
+    /// ```
+    pub struct ExclusiveClk(Clk);
+
+    // Make [`ExclusiveClk`] behave like [`Clk`].
+    impl Deref for ExclusiveClk {
+        type Target = Clk;
+
+        fn deref(&self) -> &Clk {
+            &self.0
+        }
+    }
+
+    impl Drop for ExclusiveClk {
+        fn drop(&mut self) {
+            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
+            // [`clk_rate_exclusive_put`] and balances the [`clk_rate_exclusive_get`] call from
+            // [`Clk::rate_exclusive_get`].
+            unsafe { bindings::clk_rate_exclusive_put(self.as_raw()) };
+        }
+    }
 }
 
 #[cfg(CONFIG_COMMON_CLK)]

-- 
2.51.2



From mhi at mailbox.org  Fri Jun  5 00:00:00 2026
From: mhi at mailbox.org (Maurice Hieronymus)
Date: Fri, 05 Jun 2026 09:00:00 +0200
Subject: [PATCH v2 2/2] pwm: th1520: Lock clock rate with
 clk_rate_exclusive_get
In-Reply-To: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>
References: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>
Message-ID: <20260605-rate-exclusive-get-th1520-v2-2-695640bf7249@mailbox.org>

The driver derives period and duty cycle from the clock rate read at
probe, so a later rate change would silently miscompute waveforms.
Switch to the new ExclusiveClk wrapper to hold the rate for the lifetime
of the driver data and drop the corresponding TODO.

Reviewed-by: Alice Ryhl <aliceryhl at google.com>
Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>
---
 drivers/pwm/pwm_th1520.rs | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
index ddd44a5ce497..19e8621bc52c 100644
--- a/drivers/pwm/pwm_th1520.rs
+++ b/drivers/pwm/pwm_th1520.rs
@@ -22,7 +22,7 @@
 
 use core::ops::Deref;
 use kernel::{
-    clk::Clk,
+    clk::{Clk, ExclusiveClk},
     device::{Bound, Core, Device},
     devres,
     io::{
@@ -93,7 +93,7 @@ struct Th1520WfHw {
 struct Th1520PwmDriverData {
     #[pin]
     iomem: devres::Devres<IoMem<TH1520_PWM_REG_SIZE>>,
-    clk: Clk,
+    clk: ExclusiveClk,
 }
 
 impl pwm::PwmOps for Th1520PwmDriverData {
@@ -328,10 +328,8 @@ fn probe(
         let clk = Clk::get(dev, None)?;
 
         clk.prepare_enable()?;
+        let clk = clk.rate_exclusive_get()?;
 
-        // TODO: Get exclusive ownership of the clock to prevent rate changes.
-        // The Rust equivalent of `clk_rate_exclusive_get()` is not yet available.
-        // This should be updated once it is implemented.
         let rate_hz = clk.rate().as_hz();
         if rate_hz == 0 {
             dev_err!(dev, "Clock rate is zero\n");

-- 
2.51.2



From mhi at mailbox.org  Fri Jun  5 00:03:59 2026
From: mhi at mailbox.org (Maurice Hieronymus)
Date: Fri, 05 Jun 2026 09:03:59 +0200
Subject: [PATCH v2] pwm: th1520: Remove requirement for
 mul_u64_u64_div_u64_roundup
Message-ID: <20260605-pwm-th1520-fix-v2-1-5921e3a595f7@mailbox.org>

The cycle register is always u32, so cycles_to_ns() can take a u32
instead of a u64. With that narrowing, cycles * NSEC_PER_SEC is at most
u32::MAX * 1e9 (~4.3e18), which fits in u64 without overflow. The
saturating arithmetic is therefore no longer needed, and the ceiling
division can use Rust's u64::div_ceil() directly instead of the
open-coded numerator/denominator form.

This also drops the TODO referring to a future
mul_u64_u64_div_u64_roundup kernel helper, which is no longer required.

Reviewed-by: Michal Wilczynski <m.wilczynski at samsung.com>
Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>
---
Changes in v2:
- Rebase on pwm/for-next
- Add Reviewed-by trailers
- Link to v1: https://lore.kernel.org/r/20260521-pwm-th1520-fix-v1-1-df9cd956dab4 at mailbox.org
---
 drivers/pwm/pwm_th1520.rs | 16 +++++-----------
 1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
index ddd44a5ce497..933c1ec59c2a 100644
--- a/drivers/pwm/pwm_th1520.rs
+++ b/drivers/pwm/pwm_th1520.rs
@@ -67,16 +67,10 @@ fn ns_to_cycles(ns: u64, rate_hz: u64) -> u64 {
     ns.saturating_mul(rate_hz) / NSEC_PER_SEC_U64
 }
 
-fn cycles_to_ns(cycles: u64, rate_hz: u64) -> u64 {
+fn cycles_to_ns(cycles: u32, rate_hz: u64) -> u64 {
     const NSEC_PER_SEC_U64: u64 = time::NSEC_PER_SEC as u64;
 
-    // TODO: Replace with a kernel helper like `mul_u64_u64_div_u64_roundup`
-    // once available in Rust.
-    let numerator = cycles
-        .saturating_mul(NSEC_PER_SEC_U64)
-        .saturating_add(rate_hz - 1);
-
-    numerator / rate_hz
+    (u64::from(cycles) * NSEC_PER_SEC_U64).div_ceil(rate_hz)
 }
 
 /// Hardware-specific waveform representation for TH1520.
@@ -192,15 +186,15 @@ fn round_waveform_fromhw(
             return Ok(());
         }
 
-        wf.period_length_ns = cycles_to_ns(u64::from(wfhw.period_cycles), rate_hz);
+        wf.period_length_ns = cycles_to_ns(wfhw.period_cycles, rate_hz);
 
-        let duty_cycles = u64::from(wfhw.duty_cycles);
+        let duty_cycles = wfhw.duty_cycles;
 
         if (wfhw.ctrl_val & TH1520_PWM_FPOUT) != 0 {
             wf.duty_length_ns = cycles_to_ns(duty_cycles, rate_hz);
             wf.duty_offset_ns = 0;
         } else {
-            let period_cycles = u64::from(wfhw.period_cycles);
+            let period_cycles = wfhw.period_cycles;
             let original_duty_cycles = period_cycles.saturating_sub(duty_cycles);
 
             // For an inverted signal, `duty_length_ns` is the high time (period - low_time).

---
base-commit: 5b5e33c44a491d5b5e019f527e028bd567a226fa
change-id: 20260521-pwm-th1520-fix-8e45558bbd31

Best regards,
-- 
Maurice Hieronymus <mhi at mailbox.org>



From inochiama at gmail.com  Fri Jun  5 00:58:15 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Fri, 5 Jun 2026 15:58:15 +0800
Subject: [PATCH] RISC-V: KVM: Enhance the logging check for mmu mapping
In-Reply-To: <CAAhSdy096z4SdwQKBxM0ZtE5=i3UZrhMD-BcES9UdP5OgajqEA@mail.gmail.com>
References: <20260528113840.2629186-1-inochiama@gmail.com>
 <CAAhSdy096z4SdwQKBxM0ZtE5=i3UZrhMD-BcES9UdP5OgajqEA@mail.gmail.com>
Message-ID: <aiJyHGne7VAkRD3g@inochi.infowork>

On Fri, Jun 05, 2026 at 12:19:03PM +0530, Anup Patel wrote:
> On Thu, May 28, 2026 at 5:08?PM Inochi Amaoto <inochiama at gmail.com> wrote:
> >
> > When enabling dirty ring, the dirty bitmap is disable, and the logging
> > check is always false as the RISC-V architecture does not select
> > "NEED_KVM_DIRTY_RING_WITH_BITMAP". Although the dirty log is recorded
> > since the write path already trying to add the dirty log, the logic for
> > logging check is broken and some side effect will occurs.
> >
> > Enhance the logging check for mmu mapping so it can check both the dirty
> > ring and the dirty bitmap.
> >
> > Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> > ---
> >  arch/riscv/kvm/mmu.c | 9 ++++-----
> >  1 file changed, 4 insertions(+), 5 deletions(-)
> >
> > diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> > index 2d3def024270..b5873bca9dce 100644
> > --- a/arch/riscv/kvm/mmu.c
> > +++ b/arch/riscv/kvm/mmu.c
> > @@ -142,9 +142,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
> >                                 enum kvm_mr_change change)
> >  {
> >         /*
> > -        * At this point memslot has been committed and there is an
> > -        * allocated dirty_bitmap[], dirty pages will be tracked while
> > -        * the memory slot is write protected.
> > +        * At this point memslot has been committed and dirty pages will be
> > +        * tracked while the memory slot is write protected.
> >          */
> >         if (change != KVM_MR_DELETE && new->flags & KVM_MEM_LOG_DIRTY_PAGES) {
> >                 if (kvm_dirty_log_manual_protect_and_init_set(kvm))
> > @@ -433,8 +432,8 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
> >         struct vm_area_struct *vma;
> >         struct kvm *kvm = vcpu->kvm;
> >         struct kvm_mmu_memory_cache *pcache = &vcpu->arch.mmu_page_cache;
> > -       bool logging = (memslot->dirty_bitmap &&
> > -                       !(memslot->flags & KVM_MEM_READONLY)) ? true : false;
> 
> Why is this not correct approach to determine whether logging is enabled ?
> 
> KVM ARM64 does a very similar thing (Refer, memslot_is_logging() in
> arch/arm64/kvm/mmu.c).
> 

ARM64 is correct as it select NEED_KVM_DIRTY_RING_WITH_BITMAP, which
will add a backup bitmap when enabling dirty ring. However, the RISCV
does not select this, which means the bitmap is not present when the
dirty ring is used. 

Although we still have dirty log with dirty ring now, it comes from
the check in the mark_page_dirty_in_slot(). And the check for variable
"logging" is always false when enabling dirty ring.

Regards,
Inochi

> > +       bool logging = kvm_slot_dirty_track_enabled(memslot) &&
> > +                      !(memslot->flags & KVM_MEM_READONLY);
> >         unsigned long vma_pagesize, mmu_seq;
> >         struct kvm_gstage gstage;
> >         struct page *page;
> > --
> > 2.54.0
> >
> 
> Regards,
> Anup
> 
> -- 
> kvm-riscv mailing list
> kvm-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/kvm-riscv


From wang.yechao255 at zte.com.cn  Fri Jun  5 01:00:19 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Fri, 5 Jun 2026 16:00:19 +0800 (CST)
Subject: =?UTF-8?B?wqBbUEFUQ0ggdjMgMC8zXSBSSVNDLVY6IEtWTTogSHVnZSBwYWdlIHJlY292ZXJ5IGR1cmluZyBkaXNhYmxlLWRpcnR5LWxvZw==?=
Message-ID: <20260605160019772GJy5SDmWQQF7sSqvJ0JtC@zte.com.cn>

From: Wang Yechao <wang.yechao255 at zte.com.cn>

When dirty logging is enabled, the gstage mappings are split into
4K pages to track dirty pages. If the migration fails or is canceled,
in order to keep the VM's performance consistent with that before
dirty logging was enabled, we need to recover the gstage huge page mappings
when dirty logging is disabled.

With this series, dirty_log_perf_test shows a decrease in the number of
vCPU faults:

$ perf stat -e kvm:kvm_page_fault \
/dirty_log_perf_test -s anonymous_hugetlb_1gb -v 1 -e -b 1G

Before: 524,819      kvm:kvm_page_fault
After : 263,211      kvm:kvm_page_fault

Changes in v3:
 - Rebased on https://github.com/kvm-riscv/linux/tree/riscv_kvm_queue
 - Add support to recover 1GB mappings for gstage.
 - Refactor kvm_arch_commit_memory_region to be identical to arm64.
 (sashiko AI Reviews)
 - Scan the child page table for the first valid leaf PTE to recover.
 - Add the memslot boundaries check when recover hugepages.
 - Move the cond_resched_lock to the start loop iteration.
 - The kvm_page_fault tracepoint be placed before the conditional block.
 - Remove the fault_supports_gstage_huge_mapping check.

Changes in v2:
 - Rebased on Linux v7.1-rc1.
 - Skip recovering huge pte if the first child pte is not leaf.
 - Link to v2:
 https://lore.kernel.org/linux-riscv/20260429173002565bdp1o7P0bvOs6yTz64yNx at zte.com.cn/

 - Link to v1:
 https://lore.kernel.org/linux-riscv/20260407171052241tmZDFGusMP_wlEsBVVtJo at zte.com.cn/

Wang Yechao (3):
  RISC-V: KVM: Refactor kvm_arch_commit_memory_region()
  RISC-V: KVM: add tracepoint for guest page faults
  RISC-V: KVM: Recover gstage huge page mappings during
    disable-dirty-log

 arch/riscv/include/asm/kvm_gstage.h |   4 +
 arch/riscv/kvm/gstage.c             |  61 +++++++++++++++
 arch/riscv/kvm/mmu.c                | 112 +++++++++++++++++++++++++++-
 arch/riscv/kvm/trace.h              |  25 +++++++
 arch/riscv/kvm/vcpu_exit.c          |   3 +
 5 files changed, 204 insertions(+), 1 deletion(-)

-- 
2.43.5


From qirui.001 at bytedance.com  Fri Jun  5 01:12:42 2026
From: qirui.001 at bytedance.com (Rui Qi)
Date: Fri, 5 Jun 2026 16:12:42 +0800
Subject: [PATCH v1 2/2] riscv: stacktrace: Use %pB for backtrace display
In-Reply-To: <4197ee54-6c69-cb72-5966-c60ba321a6fa@kernel.org>
References: <20260603115329.791603-1-qirui.001@bytedance.com> <20260603115329.791603-3-qirui.001@bytedance.com> <4197ee54-6c69-cb72-5966-c60ba321a6fa@kernel.org>
Message-ID: <226fe0d0-3d05-4c6b-95fb-a058da2d4169@bytedance.com>

On 6/5/26 8:33 AM, Paul Walmsley wrote:
> On Wed, 3 Jun 2026, Rui Qi wrote:
> 
>> The print_trace_address callback uses print_ip_sym which formats
>> addresses with %pS. This does not adjust the address before symbol
>> lookup, so when a noreturn function (e.g. panic, do_exit) is the last
>> call in a function, the saved return address can point to the start of
>> the next function, and kallsyms resolves it to the wrong symbol.
>>
>> The kernel provides %pB (sprint_backtrace) specifically for this
>> purpose: it subtracts 1 from the address before symbol lookup, which
>> is sufficient to fall back into the calling function range. x86 uses
>> %pB in its printk_stack_address for the same reason.
>>
>> Replace print_ip_sym with a direct printk using %pB, matching the
>> pattern used by x86.
>>
>> Signed-off-by: Rui Qi <qirui.001 at bytedance.com>
> 
> The Sashiko review mentions that the x86 backtrace code uses %pS for exact 
> instruction pointers coming from registers (show_regs_if_on_stack()), vs. 
> %pB for return addresses on the stack (printk_stack_address()):
> 
>     https://sashiko.dev/#/patchset/20260603115329.791603-1-qirui.001%40bytedance.com
> 
> Do we need to incorporate similar logic?
> 
> 
> - Paul

Hi Paul,

Yes, you are right. The Sashiko review raises a valid point that I
should have addressed in the original patch.

%pB subtracts 1 from the address before symbol lookup, which is correct
for return addresses but wrong for exact instruction pointers: if the
exact IP happens to be at offset 0 of a function, subtracting 1 causes
kallsyms to resolve it to the preceding function.

In walk_stackframe(), two kinds of addresses are passed to the callback:

Exact instruction pointers: instruction_pointer(regs) and the epc
from exception frames found during unwinding (when the return
address points into handle_exception..ret_from_exception_end).
These should use %pS.

Return addresses: frame->ra, regs->ra, task->thread.ra. These
should use %pB.

I have updated the patch to add an 'is_ra' parameter to the
walk_stackframe callback, indicating whether the address is a return
address.  print_trace_address() then uses %pB when is_ra is true and
%pS when is_ra is false, matching the x86 approach.

For the generic arch_stack_walk() path, since stack_trace_consume_fn
has a fixed 2-parameter signature, a thin wrapper (stack_walk_wrapper)
adapts between the two callback types, discarding the is_ra flag since
the generic stack trace infrastructure only records raw addresses.

One known limitation: the non-FP version of walk_stackframe() scans
the stack blindly and cannot distinguish pt_regs->epc values from
return addresses, so all stack-scanned values are treated as return
addresses (is_ra = true).  This means epc values from pt_regs
encountered during the scan may still use %pB incorrectly.  This is
an inherent limitation of the non-FP unwinder and not introduced by
this change; the FP version handles the epc case correctly.

The updated patch will be in v2.


From qirui.001 at bytedance.com  Fri Jun  5 01:20:32 2026
From: qirui.001 at bytedance.com (Rui Qi)
Date: Fri,  5 Jun 2026 16:20:32 +0800
Subject: [PATCH v2 0/2] riscv: stacktrace: Fix return address handling in non-FP unwinder
In-Reply-To: <20260603115329.791603-1-qirui.001@bytedance.com>
References: <20260603115329.791603-1-qirui.001@bytedance.com>
Message-ID: <20260605082034.1426923-1-qirui.001@bytedance.com>

This 2-patch series fixes how the non-frame-pointer version of
walk_stackframe handles return addresses, addressing both the
unwinder layer and the display layer.

Background
==========

In the original RISC-V stacktrace code (commit 5d8544e2d007), both
the FP and non-FP versions of walk_stackframe subtracted 0x4 from
return addresses read from the stack:

  FP version:      pc = frame->ra - 0x4;
  Non-FP version:  pc = (*ksp++) - 0x4;

The intent was to convert the return address (the instruction after
a call) back to the call site for better symbol resolution. However,
this is incorrect on RISC-V because the RVC (compressed instruction)
extension allows 2-byte instructions (e.g. c.jal). Subtracting a
fixed 0x4 assumes all call instructions are 4 bytes, which produces
a wrong address for compressed calls.

Commit b785ec129bd9 ("riscv/ftrace: Add HAVE_FUNCTION_GRAPH_RET_ADDR_PTR
support") fixed the FP version by replacing "pc = frame->ra - 0x4"
with ftrace_graph_ret_addr(). The commit message explicitly noted:

  "the original calculation, pc = frame->ra - 4, is buggy when the
   instruction at the return address happened to be a compressed inst."

Later, commit 877425424d6c removed the fallback "#else" branch
entirely since HAVE_FUNCTION_GRAPH_RET_ADDR_PTR is always defined
for RISC-V. However, the non-FP version was simply overlooked and
still carries the bogus -0x4 offset.

Patch 1: Remove -0x4 from the unwinder
=======================================

Remove the -0x4 offset from the non-FP walk_stackframe so it reports
raw return addresses, consistent with the FP version and with other
architectures (ARM64, x86, ARM all report return addresses as-is).

Patch 2: Use %pB for return addresses and %pS for exact IPs
=============================================================

With the -0x4 removed, a pre-existing issue becomes more visible:
when a noreturn function (e.g. panic, do_exit) is the last call in
a function, the saved return address points to the start of the next
function, and kallsyms resolves it to the wrong symbol.

The kernel provides sprint_backtrace() (invoked via %pB) specifically
for this purpose: it subtracts 1 from the address before symbol
lookup, which is sufficient to fall back into the calling function's
range. x86 uses %pB in its printk_stack_address() for this reason.

However, %pB must only be used for return addresses. walk_stackframe
passes two kinds of addresses to its callback: exact instruction
pointers (instruction_pointer(regs) and epc from exception frames)
and return addresses (frame->ra, regs->ra, task->thread.ra). For
exact IPs, subtracting 1 can cause kallsyms to resolve to the
preceding function if the IP is at offset 0 of a function.

Add an 'is_ra' parameter to the walk_stackframe callback to indicate
whether the address is a return address.  Then use %pB for return
addresses and %pS for exact instruction pointers, matching the x86
approach which uses %pS for regs->ip via show_ip() and %pB for
stack return addresses via printk_stack_address().

Known limitation: the non-FP version of walk_stackframe() scans the
stack blindly and cannot distinguish pt_regs->epc values from return
addresses, so all stack-scanned values are treated as return addresses
(is_ra = true).  This means epc values from pt_regs encountered during
the scan may still use %pB incorrectly.  The FP version handles this
case correctly by detecting exception frames explicitly.

Changes since v1
================

- Patch 2: Split %pB usage to only apply to return addresses (is_ra =
  true), using %pS for exact instruction pointers (is_ra = false).
  This addresses the review feedback from Paul Walmsley and the
  Sashiko review noting that x86 uses %pS for exact IPs and %pB only
  for return addresses.

- Patch 2: Add 'is_ra' parameter to walk_stackframe callback, update
  the declaration in asm/stacktrace.h, and adapt all callers
  (print_trace_address, save_wchan, fill_callchain_walk wrapper for
  perf, stack_walk_wrapper for arch_stack_walk).

Design principle
================

The two patches follow a clear separation of concerns:

  - The unwinder reports raw return addresses (no offset adjustment)
  - The display layer handles symbol resolution adjustments (%pB for
    return addresses, %pS for exact IPs)

This matches the convention used by other architectures and ensures
consistent behavior between the FP and non-FP unwinders.

Jiakai Xu [1] and Wang Han [2] have separate patch series in flight
for other stacktrace issues; these patches are orthogonal to their
work.

  [1] https://lore.kernel.org/all/20260517143704.659416-1-xujiakai2025 at iscas.ac.cn/
  [2] https://lore.kernel.org/all/20260528082310.1994388-1-wanghan at linux.alibaba.com/

Rui Qi (2):
  riscv: stacktrace: Remove bogus -0x4 offset in non-FP walk_stackframe
  riscv: stacktrace: Use %pB for return addresses and %pS for exact IPs

 arch/riscv/include/asm/stacktrace.h |  2 +-
 arch/riscv/kernel/perf_callchain.c  |  7 +++-
 arch/riscv/kernel/stacktrace.c      | 56 +++++++++++++++++++++++------
 3 files changed, 53 insertions(+), 12 deletions(-)

--
2.20.1


From qirui.001 at bytedance.com  Fri Jun  5 01:20:33 2026
From: qirui.001 at bytedance.com (Rui Qi)
Date: Fri,  5 Jun 2026 16:20:33 +0800
Subject: [PATCH v2 1/2] riscv: stacktrace: Remove bogus -0x4 offset in non-FP walk_stackframe
In-Reply-To: <20260605082034.1426923-1-qirui.001@bytedance.com>
References: <20260603115329.791603-1-qirui.001@bytedance.com> <20260605082034.1426923-1-qirui.001@bytedance.com>
Message-ID: <20260605082034.1426923-2-qirui.001@bytedance.com>

In the non-frame-pointer version of walk_stackframe, each value read
from the stack is treated as a potential return address and has 0x4
subtracted before being used as the program counter. This was intended
to convert the return address (the instruction after a call) back to
the call site, but it is incorrect:

1. RISC-V has variable-length instructions due to the RVC (compressed
   instruction) extension. A call instruction can be either 4 bytes
   (regular) or 2 bytes (compressed, e.g. c.jal). Subtracting a fixed
   0x4 assumes all call instructions are 4 bytes, which is wrong for
   compressed instructions.

2. Stack traces conventionally report return addresses, not call sites.
   Other architectures (ARM64, x86, ARM) do not subtract instruction
   size from return addresses in their stack unwinding code.

3. The frame-pointer version of walk_stackframe already dropped the
   -0x4 offset. Commit b785ec129bd9 ("riscv/ftrace: Add
   HAVE_FUNCTION_GRAPH_RET_ADDR_PTR support") replaced "pc =
   frame->ra - 0x4" with ftrace_graph_ret_addr(), and the commit
   message explicitly noted that "the original calculation, pc =
   frame->ra - 4, is buggy when the instruction at the return address
   happened to be a compressed inst." The non-FP version was simply
   overlooked.

Remove the bogus -0x4 offset to match the FP version and the
conventions used by other architectures.

Fixes: 5d8544e2d007 ("RISC-V: Generic library routines and assembly")
Signed-off-by: Rui Qi <qirui.001 at bytedance.com>
---
 arch/riscv/kernel/stacktrace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index 2692d3a06afa..c7555447149b 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -129,7 +129,7 @@ void notrace walk_stackframe(struct task_struct *task,
 	while (!kstack_end(ksp)) {
 		if (__kernel_text_address(pc) && unlikely(!fn(arg, pc)))
 			break;
-		pc = READ_ONCE_NOCHECK(*ksp++) - 0x4;
+		pc = READ_ONCE_NOCHECK(*ksp++);
 	}
 }
 
-- 
2.20.1


From qirui.001 at bytedance.com  Fri Jun  5 01:20:34 2026
From: qirui.001 at bytedance.com (Rui Qi)
Date: Fri,  5 Jun 2026 16:20:34 +0800
Subject: [PATCH v2 2/2] riscv: stacktrace: Use %pB for return addresses and %pS for exact IPs
In-Reply-To: <20260605082034.1426923-1-qirui.001@bytedance.com>
References: <20260603115329.791603-1-qirui.001@bytedance.com> <20260605082034.1426923-1-qirui.001@bytedance.com>
Message-ID: <20260605082034.1426923-3-qirui.001@bytedance.com>

The print_trace_address callback uses print_ip_sym which formats
addresses with %pS. This does not adjust the address before symbol
lookup, so when a noreturn function (e.g. panic, do_exit) is the last
call in a function, the saved return address can point to the start of
the next function, and kallsyms resolves it to the wrong symbol.

The kernel provides %pB (sprint_backtrace) specifically for this
purpose: it subtracts 1 from the address before symbol lookup, which
is sufficient to fall back into the calling function range.

However, %pB must only be used for return addresses. walk_stackframe
passes two kinds of addresses to its callback:
- Exact instruction pointers: instruction_pointer(regs) and the epc
  from exception frames on the stack. These should use %pS since they
  are not return addresses and subtracting 1 could cause kallsyms to
  resolve them to the preceding function.
- Return addresses: frame->ra, regs->ra, and task->thread.ra. These
  should use %pB for correct symbol resolution, especially after
  noreturn calls.

Add an 'is_ra' parameter to the walk_stackframe callback to indicate
whether the address is a return address, then use %pB for return
addresses and %pS for exact instruction pointers. This matches the x86
approach which uses %pS for regs->ip via show_ip() and %pB for stack
return addresses via printk_stack_address().

Also update the walk_stackframe() declaration in asm/stacktrace.h and
the fill_callchain() callback in perf_callchain.c to match the new
signature.

Signed-off-by: Rui Qi <qirui.001 at bytedance.com>
---
 arch/riscv/include/asm/stacktrace.h |  2 +-
 arch/riscv/kernel/perf_callchain.c  |  7 +++-
 arch/riscv/kernel/stacktrace.c      | 54 ++++++++++++++++++++++++-----
 3 files changed, 52 insertions(+), 11 deletions(-)

diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h
index b1495a7e06ce..6771d0e0f656 100644
--- a/arch/riscv/include/asm/stacktrace.h
+++ b/arch/riscv/include/asm/stacktrace.h
@@ -12,7 +12,7 @@ struct stackframe {
 };
 
 extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
-				    bool (*fn)(void *, unsigned long), void *arg);
+				    bool (*fn)(void *, unsigned long, bool), void *arg);
 extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
 			   const char *loglvl);
 
diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c
index b465bc9eb870..0a5678f0d400 100644
--- a/arch/riscv/kernel/perf_callchain.c
+++ b/arch/riscv/kernel/perf_callchain.c
@@ -11,6 +11,11 @@ static bool fill_callchain(void *entry, unsigned long pc)
 	return perf_callchain_store(entry, pc) == 0;
 }
 
+static bool fill_callchain_walk(void *entry, unsigned long pc, bool is_ra)
+{
+	return fill_callchain(entry, pc);
+}
+
 /*
  * This will be called when the target is in user mode
  * This function will only be called when we use
@@ -44,5 +49,5 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
 		return;
 	}
 
-	walk_stackframe(NULL, regs, fill_callchain, entry);
+	walk_stackframe(NULL, regs, fill_callchain_walk, entry);
 }
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index c7555447149b..502729ab257b 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -46,32 +46,36 @@ static inline int fp_is_valid(unsigned long fp, unsigned long sp)
 }
 
 void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
-			     bool (*fn)(void *, unsigned long), void *arg)
+			     bool (*fn)(void *, unsigned long, bool), void *arg)
 {
 	unsigned long fp, sp, pc;
 	int graph_idx = 0;
 	int level = 0;
+	bool is_ra;
 
 	if (regs) {
 		fp = frame_pointer(regs);
 		sp = user_stack_pointer(regs);
 		pc = instruction_pointer(regs);
+		is_ra = false;	/* exact instruction pointer */
 	} else if (task == NULL || task == current) {
 		fp = (unsigned long)__builtin_frame_address(0);
 		sp = current_stack_pointer;
 		pc = (unsigned long)walk_stackframe;
+		is_ra = false;	/* function entry address */
 		level = -1;
 	} else {
 		/* task blocked in __switch_to */
 		fp = task->thread.s[0];
 		sp = task->thread.sp;
 		pc = task->thread.ra;
+		is_ra = true;	/* return address */
 	}
 
 	for (;;) {
 		struct stackframe *frame;
 
-		if (unlikely(!__kernel_text_address(pc) || (level++ >= 0 && !fn(arg, pc))))
+		if (unlikely(!__kernel_text_address(pc) || (level++ >= 0 && !fn(arg, pc, is_ra))))
 			break;
 
 		if (unlikely(!fp_is_valid(fp, sp)))
@@ -84,18 +88,21 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
 			/* We hit function where ra is not saved on the stack */
 			fp = frame->ra;
 			pc = regs->ra;
+			is_ra = true;	/* return address */
 		} else {
 			fp = READ_ONCE_TASK_STACK(task, frame->fp);
 			pc = READ_ONCE_TASK_STACK(task, frame->ra);
 			pc = ftrace_graph_ret_addr(task, &graph_idx, pc,
 						   &frame->ra);
+			is_ra = true;	/* return address */
 			if (pc >= (unsigned long)handle_exception &&
 			    pc < (unsigned long)&ret_from_exception_end) {
-				if (unlikely(!fn(arg, pc)))
+				if (unlikely(!fn(arg, pc, is_ra)))
 					break;
 
 				pc = ((struct pt_regs *)sp)->epc;
 				fp = ((struct pt_regs *)sp)->s0;
+				is_ra = false;	/* exact instruction pointer */
 			}
 		}
 
@@ -105,41 +112,58 @@ void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
 #else /* !CONFIG_FRAME_POINTER */
 
 void notrace walk_stackframe(struct task_struct *task,
-	struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *arg)
+	struct pt_regs *regs, bool (*fn)(void *, unsigned long, bool), void *arg)
 {
 	unsigned long sp, pc;
 	unsigned long *ksp;
+	bool is_ra;
 
 	if (regs) {
 		sp = user_stack_pointer(regs);
 		pc = instruction_pointer(regs);
+		is_ra = false;	/* exact instruction pointer */
 	} else if (task == NULL || task == current) {
 		sp = current_stack_pointer;
 		pc = (unsigned long)walk_stackframe;
+		is_ra = false;	/* function entry address */
 	} else {
 		/* task blocked in __switch_to */
 		sp = task->thread.sp;
 		pc = task->thread.ra;
+		is_ra = true;	/* return address */
 	}
 
 	if (unlikely(sp & 0x7))
 		return;
 
+	/*
+	 * Scan the stack for kernel text addresses.  Without frame pointers
+	 * we cannot distinguish return addresses from other saved text
+	 * addresses (e.g. pt_regs->epc), so all stack values are treated
+	 * as return addresses (is_ra = true).  This means pt_regs->epc
+	 * values found during the scan may be displayed with %pB instead
+	 * of the correct %pS, which can cause misattribution when the
+	 * exact IP is at offset 0 of a function.
+	 */
 	ksp = (unsigned long *)sp;
 	while (!kstack_end(ksp)) {
-		if (__kernel_text_address(pc) && unlikely(!fn(arg, pc)))
+		if (__kernel_text_address(pc) && unlikely(!fn(arg, pc, is_ra)))
 			break;
 		pc = READ_ONCE_NOCHECK(*ksp++);
+		is_ra = true;
 	}
 }
 
 #endif /* CONFIG_FRAME_POINTER */
 
-static bool print_trace_address(void *arg, unsigned long pc)
+static bool print_trace_address(void *arg, unsigned long pc, bool is_ra)
 {
 	const char *loglvl = arg;
 
-	print_ip_sym(loglvl, pc);
+	if (is_ra)
+		printk("%s[<%px>] %pB\n", loglvl, (void *)pc, (void *)pc);
+	else
+		printk("%s[<%px>] %pS\n", loglvl, (void *)pc, (void *)pc);
 	return true;
 }
 
@@ -155,7 +179,7 @@ void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
 	dump_backtrace(NULL, task, loglvl);
 }
 
-static bool save_wchan(void *arg, unsigned long pc)
+static bool save_wchan(void *arg, unsigned long pc, bool is_ra)
 {
 	if (!in_sched_functions(pc)) {
 		unsigned long *p = arg;
@@ -176,10 +200,22 @@ unsigned long __get_wchan(struct task_struct *task)
 	return pc;
 }
 
+struct stack_walk_cookie {
+	stack_trace_consume_fn consume;
+	void *cookie;
+};
+
+static bool stack_walk_wrapper(void *arg, unsigned long pc, bool is_ra)
+{
+	struct stack_walk_cookie *ctx = arg;
+	return ctx->consume(ctx->cookie, pc);
+}
+
 noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
 		     struct task_struct *task, struct pt_regs *regs)
 {
-	walk_stackframe(task, regs, consume_entry, cookie);
+	struct stack_walk_cookie ctx = { .consume = consume_entry, .cookie = cookie };
+	walk_stackframe(task, regs, stack_walk_wrapper, &ctx);
 }
 
 /*
-- 
2.20.1


From dlan at kernel.org  Fri Jun  5 01:58:02 2026
From: dlan at kernel.org (Yixun Lan)
Date: Fri, 5 Jun 2026 08:58:02 +0000
Subject: [PATCH] dts: riscv: spacemit: k3: Fix I/O power settings
In-Reply-To: <9585b7c7-100c-4d77-bed1-d2b6b25b3940@freeshell.de>
References: <20260518-07-dts-pinctrl-io-power-v1-1-abe19c14a726@kernel.org>
 <9585b7c7-100c-4d77-bed1-d2b6b25b3940@freeshell.de>
Message-ID: <20260605085802-GKD3727415@kernel.org>

Hi E Shattow,

On 13:17 Wed 03 Jun     , E Shattow wrote:
> 
> Hi Yixun,
> 
> This property on its own does not seem to be enough to get the ethernet
> network port functional on Sipeed K3 Pico-ITX 32GB model that I have,
> when it is loading Debian 13 Trixie debian-installer netinst initramfs
> (with cross-compiled Linux kernel and modules from -next 20260602).
> 
I don't think your problem directly connect to this pacth..

> Reproducer instructions for cross-compiling and debian-installer netinst
> initramfs modification at:
> https://wiki.debian.org/InstallingDebianOn/SpacemiT/K3PicoITX?action=recall&rev=2
> 
> In addition to those instructions above I am using within the factory
> pre-installed vendor U-Boot the following commands to try what your
> patch does:
> 
> fdt addr $fdt_addr_r
> fdt resize
> fdt header get filesize totalsize
> fdt rm /soc/pinctrl at d401e000 spacemit,apbc
> fdt get value spacemit_apbc_phandle /soc/system-controller at d4015000 phandle
> fdt set /soc/pinctrl at d401e000 spacemit,apbc <$spacemit_apbc_phandle>
> 
> I then verify within Linux environment the presence of
> /sys/firmware/devicetree/base/soc/pinctrl at d401e000/spacemit,apbc
> 
> The same Linux kernel and modules as modified into the installer then do
> have functional ethernet networking on that board if running from the
> installed system and with the spacemit,apbc devicetree property. Is this
> a dependency or ordering issue of the modules, or the Kconfig options?
> 
I've checked with the failure kernel dmesg log (you provided offline),
the dwmac driver has been probed twice, with first time failed, it
might be the PHY driver not been initialized, adjust following 
configuration works for me..

CONFIG_STMMAC_ETH=y
CONFIG_REALTEK_PHY=y
CONFIG_I2C_K1=y

the PMIC/Power Regulator rely on I2C driver..

> Also, the more general problem is that cycling rmmod and modprobe on the
> ethernet networking related modules fails:
> 
> rmmod dwmac_spacemit
> rmmod stmmac_platform
> rmmod stmmac
> rmmod mdio
> modprobe dwmac_spacemit
> 
> [ 1487.618517] mdio_bus stmmac-0: MDIO device at address 1 is missing.
> 
> [ 1487.623815] spacemit-dwmac cac80000.ethernet end0: renamed from eth0
> 
> rmmod dwmac_spacemit
> rmmod stmmac_platform
> rmmod stmmac
> rmmod mdio
> modprobe dwmac_spacemit
> 
Need to investigate, could be problem of resource deinitialization issue..

> [ 1539.374486] spacemit-dwmac cac80000.ethernet end0: cannot attach to
> PHY (erro
> r: -ENODEV)
> [ 1615.299451] spacemit-dwmac cac80000.ethernet end0: stmmac_dvr_remove:
> removin
> g driver
> 
> Please advise how to troubleshoot?  Thanks,
> 
> - E Shattow
> 

-- 
Yixun Lan (dlan)


From sunilvl at oss.qualcomm.com  Fri Jun  5 02:03:25 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Fri, 5 Jun 2026 14:33:25 +0530
Subject: [PATCH] iommu/riscv: Add dependency between iommu and devices
In-Reply-To: <20260604145510898G2kTwM2Pr25QE5H8T4Wh6@zte.com.cn>
References: <20260604145510898G2kTwM2Pr25QE5H8T4Wh6@zte.com.cn>
Message-ID: <CAB19ukEzQZktJcBAXi8X2Pwz+hO_FcR+iiaK9nsCAumP9BrHnw@mail.gmail.com>

On Thu, Jun 4, 2026 at 12:28?PM <wang.yechao255 at zte.com.cn> wrote:
>
> From: Wang Yechao <wang.yechao255 at zte.com.cn>
>
> Commit 9156585280f1 ("ACPI: RIMT: Add dependency between iommu and
> devices") adds the dependency between iommu and devices on ACPI
> systems. On devicetree systems, the incorrect removal order also
> occurs.
>
Interesting. Why is it not handled by the fw_devlink infrastructure in DT?

Thanks,
Sunil


From shuwei.wu at mailbox.org  Fri Jun  5 02:09:56 2026
From: shuwei.wu at mailbox.org (Shuwei Wu)
Date: Fri, 05 Jun 2026 17:09:56 +0800
Subject: [PATCH v5 RESEND 5/5] riscv64: dts: sophgo: add initial Milk-V
 Duo S board support
In-Reply-To: <20260530173347.33533-6-josh.milas@gmail.com>
References: <20260530173347.33533-1-josh.milas@gmail.com>
 <20260530173347.33533-6-josh.milas@gmail.com>
Message-ID: <DJ0ZYF5C8MMH.2GBBY188VVPSH@mailbox.org>

Hi Joshua,

On Sun May 31, 2026 at 1:33 AM CST, Joshua Milas wrote:
> This adds initial riscv support for the Milk-V Duo S board
> [1] making it possible to boot Linux to the command line.
>
> Link: https://milkv.io/duo-s [1]
>
> Signed-off-by: Joshua Milas <josh.milas at gmail.com>
> ---
>  arch/riscv/boot/dts/sophgo/Makefile           |  1 +
>  .../boot/dts/sophgo/sg2000-milkv-duo-s.dts    | 85 +++++++++++++++++++
>  2 files changed, 86 insertions(+)
>  create mode 100644 arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts
>
> diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile
> index 6f65526d4193b..58cc6b70d8de4 100644
> --- a/arch/riscv/boot/dts/sophgo/Makefile
> +++ b/arch/riscv/boot/dts/sophgo/Makefile
> @@ -1,6 +1,7 @@
>  # SPDX-License-Identifier: GPL-2.0
>  dtb-$(CONFIG_ARCH_SOPHGO) += cv1800b-milkv-duo.dtb
>  dtb-$(CONFIG_ARCH_SOPHGO) += cv1812h-huashan-pi.dtb
> +dtb-$(CONFIG_ARCH_SOPHGO) += sg2000-milkv-duo-s.dtb
>  dtb-$(CONFIG_ARCH_SOPHGO) += sg2002-licheerv-nano-b.dtb
>  dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb
>  dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-evb-v1.dtb
> diff --git a/arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts b/arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts
> new file mode 100644
> index 0000000000000..8632470f43ab0
> --- /dev/null
> +++ b/arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts
> @@ -0,0 +1,85 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +
> +/dts-v1/;
> +
> +#include "sg2000.dtsi"
> +
> +/ {
> +	model = "Milk-V Duo S";
> +	compatible = "milkv,duo-s", "sophgo,sg2000";
> +
> +	aliases {
> +		i2c4 = &i2c4;
> +		mmc0 = &sdhci0;
> +		serial0 = &uart0;
> +		spi3 = &spi3;
> +	};
> +
> +	chosen {
> +		stdout-path = "serial0:115200n8";
> +	};
> +};
> +
> +&osc {
> +	clock-frequency = <25000000>;
> +};
> +
> +&dmac {
> +	status = "okay";
> +};
> +
> +&emmc {
> +	bus-width = <4>;
> +	no-1-8-v;
> +	cap-mmc-hw-reset;
> +	no-sd;
> +	no-sdio;
> +	non-removable;
> +	status = "okay";
> +};
> +
> +&gmac0 {
> +	status = "okay";
> +};
> +
> +&i2c4 {
> +	status = "okay";
> +};
> +
> +&mdio {
> +	status = "okay";
> +};
> +
> +&saradc {
> +	status = "okay";
> +};
> +
> +&sdhci0 {
> +	bus-width = <4>;
> +	no-1-8-v;
> +	disable-wp;
> +	status = "okay";
> +};
> +
> +&sdhci1 {
> +	bus-width = <4>;
> +	cap-sdio-irq;
> +	no-mmc;
> +	no-sd;
> +	non-removable;
> +	status = "okay";
> +};
> +
> +&spi3 {
> +	status = "okay";
> +};
> +
> +&uart0 {
> +	status = "okay";
> +};
> +
> +&usb {
> +	dr_mode = "host";
> +	status = "okay";
> +};
> +

I tested this series on a Milk-V Duo S board with a RISC-V mainline kernel.

The board boots successfully with sg2000-milkv-duo-s.dtb. UART works, the SD
card is detected and readable, Ethernet works after enabling the MDIO mux
options, and the DMA, USB host, I2C4, SPI3 and SARADC nodes all probe
successfully.

One thing I noticed is that the Wi-Fi SDIO device is not enumerated with the
mainline DT. The sdhci1 host itself probes:

  mmc1: SDHCI controller on 4320000.mmc [4320000.mmc] using ADMA 64-bit
  mmc1: Failed to initialize a non-removable card

and /sys/bus/sdio/devices remains empty.

With the vendor image on the same board, the Wi-Fi SDIO device is detected on
the corresponding controller:

  mmc1: SDHCI controller on 4320000.wifi-sd [4320000.wifi-sd] using ADMA 64-bit
  sdio vendor ID: 0xc8a1
  sdio device ID: 0x0082
  aicwf_sdio_chipmatch USE AIC8800D80
  sdio ready

So it looks like the SDHCI host comes up, but the SDIO device behind it is not
discovered. I may still be missing some config option.

Have you seen this issue on your side? If not, could you please share the
relevant kernel config used for your testing?

-- 
Best regards,
Shuwei Wu


From david at kernel.org  Fri Jun  5 02:16:41 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Fri, 5 Jun 2026 11:16:41 +0200
Subject: [PATCH v3] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
In-Reply-To: <20260605-mark-after-vmemmap-populate-v3-1-a06001ac9264@iscas.ac.cn>
References: <20260605-mark-after-vmemmap-populate-v3-1-a06001ac9264@iscas.ac.cn>
Message-ID: <da19ffcf-8042-4f96-9c2d-649468dc6a0a@kernel.org>

On 6/5/26 07:23, Vivian Wang wrote:
> section_activate() does not flush TLB after populating new vmemmap
> pages. On most architectures, this is okay. However it is a problem on
> RISC-V since there the TLB caching non-present entries is permitted,
> which causes spurious faults on some hardwares.
> 
> This seems to be most easily reproduced with DEBUG_VM=y and
> PAGE_POISONING=y, which causes these newly mapped struct pages to be
> poisoned i.e. written to immediately after mapping.
> 
> Add a hook vmemmap_populate_finalize() in __populate_section_memmap()
> after population, to allow architectures to handle such situations as
> needed. Then implement it on RISC-V to arrange for the existing
> exception handler code to deal with these faults if they happen.
> 
> Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
> ---
> Depends on my earlier kfence fixes for mark_new_valid_map() [1].
> 
> Found while testing AMD_HSA/ZONE_DEVICE on SpacemiT K3. Using
> ZONE_DEVICE requires another fix [2].
> 
> [1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn
> [2]: https://lore.kernel.org/linux-riscv/20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd at iscas.ac.cn
> ---
> Changes in v3:
> - Merged back into one patch (Mike)
> - (No code changes otherwise.)
> - Link to v2: https://patch.msgid.link/20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434 at iscas.ac.cn
> 
> Changes in v2:
> - Split patch in two, hook point and riscv hook 
> - Explain hook necessity in patch 1 message (Mike)
> - Make hook #define based (Mike)
> - Call finalize hook only on populate success
> - Link to v1: https://patch.msgid.link/20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16 at iscas.ac.cn
> ---
>  arch/riscv/include/asm/pgtable.h | 4 ++++
>  arch/riscv/mm/init.c             | 6 ++++++
>  mm/sparse-vmemmap.c              | 8 ++++++++
>  3 files changed, 18 insertions(+)
> 
> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
> index a1a7c6520a09..aa0f50e3d534 100644
> --- a/arch/riscv/include/asm/pgtable.h
> +++ b/arch/riscv/include/asm/pgtable.h
> @@ -1243,6 +1243,10 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
>  #define TASK_SIZE	FIXADDR_START
>  #endif
>  
> +/* Needed on SPARSEMEM_VMEMMAP */
> +#define vmemmap_populate_finalize vmemmap_populate_finalize
> +void __meminit vmemmap_populate_finalize(void);
> +
>  #else /* CONFIG_MMU */
>  
>  #define PAGE_SHARED		__pgprot(0)
> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
> index 706f43523935..cf9ae4099f82 100644
> --- a/arch/riscv/mm/init.c
> +++ b/arch/riscv/mm/init.c
> @@ -1360,6 +1360,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
>  	 */
>  	return vmemmap_populate_hugepages(start, end, node, altmap);
>  }
> +
> +void __meminit vmemmap_populate_finalize(void)
> +{
> +	/* Avoid faults on cached non-present TLB entries. */
> +	mark_new_valid_map();
> +}
>  #endif

How does mark_new_valid_map() handle concurrent access?

There is some comment in there, but I am not sure if that actually implies that
mark_new_valid_map() can be called concurrently from arbitrary context?


-- 
Cheers,

David


From shuwei.wu at mailbox.org  Fri Jun  5 02:33:23 2026
From: shuwei.wu at mailbox.org (Shuwei Wu)
Date: Fri, 05 Jun 2026 17:33:23 +0800
Subject: [PATCH v5 RESEND 4/5] riscv64: dts: sophgo: add SG2000 dtsi
In-Reply-To: <20260530173347.33533-5-josh.milas@gmail.com>
References: <20260530173347.33533-1-josh.milas@gmail.com>
 <20260530173347.33533-5-josh.milas@gmail.com>
Message-ID: <DJ10GDDAE672.1N365YARL5KV1@mailbox.org>

Hi Joshua,

On Sun May 31, 2026 at 1:33 AM CST, Joshua Milas wrote:
> Adds sg2000.dtsi on the RISCV side.
>
> Signed-off-by: Joshua Milas <josh.milas at gmail.com>
> ---
>  arch/riscv/boot/dts/sophgo/sg2000.dtsi | 53 ++++++++++++++++++++++++++
>  1 file changed, 53 insertions(+)
>  create mode 100644 arch/riscv/boot/dts/sophgo/sg2000.dtsi
>
> diff --git a/arch/riscv/boot/dts/sophgo/sg2000.dtsi b/arch/riscv/boot/dts/sophgo/sg2000.dtsi
> new file mode 100644
> index 0000000000000..412adacc00576
> --- /dev/null
> +++ b/arch/riscv/boot/dts/sophgo/sg2000.dtsi
> @@ -0,0 +1,53 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +
> +#define SOC_PERIPHERAL_IRQ(nr)	((nr) + 16)
> +
> +#include <dt-bindings/interrupt-controller/irq.h>
> +#include <dt-bindings/pinctrl/pinctrl-sg2000.h>
> +#include "cv180x-cpus.dtsi"
> +#include "cv180x.dtsi"
> +#include "cv181x.dtsi"
> +
> +/ {
> +	compatible = "sophgo,sg2000";
> +
> +	memory at 80000000 {
> +		device_type = "memory";
> +		reg = <0x80000000 0x10000000>;
> +	};

I noticed that this describes 256 MiB of RAM. The Milk-V Duo documentation lists
the SG2000-based Duo boards as having 512 MB of DRAM [1].
Is the 256 MiB size intentional here, or should the Duo S board DTS override it
with the documented 512 MB DRAM size?
[1] https://milkv.io/docs/duo/overview

> +
> +	soc {
> +		interrupt-parent = <&plic>;
> +		dma-noncoherent;
> +
> +		pinctrl: pinctrl at 3001000 {
> +			compatible = "sophgo,sg2000-pinctrl";
> +			reg = <0x03001000 0x1000>,
> +			      <0x05027000 0x1000>;
> +			reg-names = "sys", "rtc";
> +		};
> +
> +		clk: clock-controller at 3002000 {
> +			compatible = "sophgo,sg2000-clk";
> +			reg = <0x03002000 0x1000>;
> +			clocks = <&osc>;
> +			#clock-cells = <1>;
> +		};
> +
> +		plic: interrupt-controller at 70000000 {
> +			compatible = "sophgo,sg2000-plic", "thead,c900-plic";
> +			reg = <0x70000000 0x4000000>;
> +			interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>;
> +			interrupt-controller;
> +			#address-cells = <0>;
> +			#interrupt-cells = <2>;
> +			riscv,ndev = <101>;
> +		};
> +
> +		clint: timer at 74000000 {
> +			compatible = "sophgo,sg2000-clint", "thead,c900-clint";
> +			reg = <0x74000000 0x10000>;
> +			interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>;
> +		};
> +	};
> +};

-- 
Best regards,
Shuwei Wu



From e at freeshell.de  Fri Jun  5 03:12:07 2026
From: e at freeshell.de (E Shattow)
Date: Fri, 5 Jun 2026 03:12:07 -0700
Subject: [PATCH] dts: riscv: spacemit: k3: Fix I/O power settings
In-Reply-To: <20260605085802-GKD3727415@kernel.org>
References: <20260518-07-dts-pinctrl-io-power-v1-1-abe19c14a726@kernel.org>
 <9585b7c7-100c-4d77-bed1-d2b6b25b3940@freeshell.de>
 <20260605085802-GKD3727415@kernel.org>
Message-ID: <7ff3ec2b-fbc3-46b3-9dd8-71c193db4059@freeshell.de>



On 6/5/26 01:58, Yixun Lan wrote:
> Hi E Shattow,
> 
> On 13:17 Wed 03 Jun     , E Shattow wrote:
>>
>> Hi Yixun,
>>
>> This property on its own does not seem to be enough to get the ethernet
>> network port functional on Sipeed K3 Pico-ITX 32GB model that I have,
>> when it is loading Debian 13 Trixie debian-installer netinst initramfs
>> (with cross-compiled Linux kernel and modules from -next 20260602).
>>
> I don't think your problem directly connect to this pacth..
> 
>> Reproducer instructions for cross-compiling and debian-installer netinst
>> initramfs modification at:
>> https://wiki.debian.org/InstallingDebianOn/SpacemiT/K3PicoITX?action=recall&rev=2
>>
>> In addition to those instructions above I am using within the factory
>> pre-installed vendor U-Boot the following commands to try what your
>> patch does:
>>
>> fdt addr $fdt_addr_r
>> fdt resize
>> fdt header get filesize totalsize
>> fdt rm /soc/pinctrl at d401e000 spacemit,apbc
>> fdt get value spacemit_apbc_phandle /soc/system-controller at d4015000 phandle
>> fdt set /soc/pinctrl at d401e000 spacemit,apbc <$spacemit_apbc_phandle>
>>
>> I then verify within Linux environment the presence of
>> /sys/firmware/devicetree/base/soc/pinctrl at d401e000/spacemit,apbc
>>
>> The same Linux kernel and modules as modified into the installer then do
>> have functional ethernet networking on that board if running from the
>> installed system and with the spacemit,apbc devicetree property. Is this
>> a dependency or ordering issue of the modules, or the Kconfig options?
>>
> I've checked with the failure kernel dmesg log (you provided offline),
> the dwmac driver has been probed twice, with first time failed, it
> might be the PHY driver not been initialized, adjust following 
> configuration works for me..
> 
> CONFIG_STMMAC_ETH=y
> CONFIG_REALTEK_PHY=y
> CONFIG_I2C_K1=y
> 
> the PMIC/Power Regulator rely on I2C driver..
> 
>> Also, the more general problem is that cycling rmmod and modprobe on the
>> ethernet networking related modules fails:
>>
>> rmmod dwmac_spacemit
>> rmmod stmmac_platform
>> rmmod stmmac
>> rmmod mdio
>> modprobe dwmac_spacemit
>>
>> [ 1487.618517] mdio_bus stmmac-0: MDIO device at address 1 is missing.
>>
>> [ 1487.623815] spacemit-dwmac cac80000.ethernet end0: renamed from eth0
>>
>> rmmod dwmac_spacemit
>> rmmod stmmac_platform
>> rmmod stmmac
>> rmmod mdio
>> modprobe dwmac_spacemit
>>
> Need to investigate, could be problem of resource deinitialization issue..
> 
>> [ 1539.374486] spacemit-dwmac cac80000.ethernet end0: cannot attach to
>> PHY (erro
>> r: -ENODEV)
>> [ 1615.299451] spacemit-dwmac cac80000.ethernet end0: stmmac_dvr_remove:
>> removin
>> g driver
>>
>> Please advise how to troubleshoot?  Thanks,
>>
>> - E Shattow
>>
> 

Yes, confirming now that the network is functional (with -next 20260603
from 4th Jun 2026, inclusive of this patch as-is) in debian-installer
netinst by manually configure and ping the network interface before the
application begins the network probe action. After the network probe
action the network device is not reachable.

I'm not experienced with internals of debian-installer to know if the
module is rmmod/modprobe cycled or how else this may be triggered by the
debian-installer application and its network probe action. I do note the
following, that 'lsmod' output has changed:

 Module                  Size  Used by
 sd_mod                167936  0
 uas                    36864  0
 usb_storage           110592  1 uas
 scsi_mod              405504  3 sd_mod,usb_storage,uas
 scsi_common            20480  4 scsi_mod,sd_mod,usb_storage,uas
 onboard_usb_dev        24576  0
 xhci_plat_hcd          24576  0
 xhci_hcd              569344  1 xhci_plat_hcd
 dwc3_generic_plat      12288  0
 dwc3                  471040  1 dwc3_generic_plat
-realtek                61440  0
+realtek                61440  1
 phy_package            16384  1 realtek
 udc_core              114688  1 dwc3
 roles                  20480  1 dwc3
 dwmac_spacemit         12288  0
 stmmac_platform        40960  1 dwmac_spacemit
 stmmac                495616  2 stmmac_platform,dwmac_spacemit
 usbcore               536576  6
xhci_hcd,onboard_usb_dev,usb_storage,uas,xhci_pl
 at_hcd,dwc3
 pcs_xpcs               36864  1 stmmac
 phylink               118784  2 stmmac,pcs_xpcs
 i2c_k1                 28672  0
 usb_common             24576  6
xhci_hcd,usbcore,dwc3_generic_plat,xhci_plat_hcd
 ,dwc3,udc_core
 phy_k1_usb2            12288  2

before and after probe respectively. There is no other change in the
'lsmod' output. The corresponding change in dmesg as follows:

 [    4.911996]  sda: sda1

 [    4.912160] sd 0:0:0:0: [sda] Attached SCSI removable disk

 [   14.820291] workqueue: work func deferred_probe_timeout_work_func
enqueued on deprecated workqueue. Use system_{percpu|dfl}_wq instead.

+[   33.767106] dldo4: disabling

+[   47.890240] spacemit-dwmac cac80000.ethernet end0: Register
MEM_TYPE_PAGE_POOL RxQ-0
+[   47.920334] spacemit-dwmac cac80000.ethernet end0: PHY [stmmac-0:01]
driver [RTL8211F Gigabit Ethernet] (irq=POLL)

+[   47.921411] dwmac4: Master AXI performs any burst length

+[   47.921426] spacemit-dwmac cac80000.ethernet end0: No Safety
Features support found
+[   47.921791] spacemit-dwmac cac80000.ethernet end0: IEEE 1588-2008
Advanced Timestamp supported

+[   47.921958] spacemit-dwmac cac80000.ethernet end0: registered PTP
clock
+[   47.921966] spacemit-dwmac cac80000.ethernet end0: configuring for
phy/rgmii-id link mode

+[   49.087144] spacemit-dwmac cac80000.ethernet end0: Register
MEM_TYPE_PAGE_POOL RxQ-0
+[   49.128304] spacemit-dwmac cac80000.ethernet end0: PHY [stmmac-0:01]
driver [RTL8211F Gigabit Ethernet] (irq=POLL)

+[   49.238342] dwmac4: Master AXI performs any burst length

+[   49.238357] spacemit-dwmac cac80000.ethernet end0: No Safety
Features support found
+[   49.238400] spacemit-dwmac cac80000.ethernet end0: IEEE 1588-2008
Advanced Timestamp supported

+[   49.238580] spacemit-dwmac cac80000.ethernet end0: registered PTP
clock
+[   49.238588] spacemit-dwmac cac80000.ethernet end0: configuring for
phy/rgmii-id link mode

+[   52.325163] spacemit-dwmac cac80000.ethernet end0: Link is Up -
1Gbps/Full - flow control rx/tx

Thanks for looking into this,

-E


From inochiama at gmail.com  Fri Jun  5 04:44:03 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Fri, 5 Jun 2026 19:44:03 +0800
Subject: [PATCH v2 1/2] riscv: track effective hardware PTE A/D updates
In-Reply-To: <20260522142358.87589-1-cuiyunhui@bytedance.com>
References: <20260522142358.87589-1-cuiyunhui@bytedance.com>
Message-ID: <aiK2WPERUEvVMZqY@inochi.infowork>

On Fri, May 22, 2026 at 10:23:57PM +0800, Yunhui Cui wrote:
> Track the effective hardware PTE A/D update mode separately from
> Svadu capability discovery. When both Svade and Svadu are present,
> enable SBI FWFT PTE A/D hardware updating on each online CPU via
> CPUHP and use the resulting runtime state for arch_has_hw_pte_young().
> Fall back to software-managed A/D updates if enabling hardware updates
> fails.
> 
> When Svadu is present without Svade, assume hardware PTE A/D updating
> is enabled from boot, and document that boot-time behavior in the DT
> binding.
> 
> Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
> ---
>  .../devicetree/bindings/riscv/extensions.yaml |  6 +-
>  arch/riscv/include/asm/cpufeature.h           |  6 ++
>  arch/riscv/include/asm/pgtable.h              |  8 +--
>  arch/riscv/kernel/cpufeature.c                | 58 +++++++++++++++++--
>  4 files changed, 65 insertions(+), 13 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
> index 2b0a8a93bb214..b09888e9988de 100644
> --- a/Documentation/devicetree/bindings/riscv/extensions.yaml
> +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
> @@ -294,10 +294,10 @@ properties:
>                 of the PTE A/D bits or page faults when they need updated.
>              2) Only Svade present in DT => Supervisor must assume Svade to be
>                 always enabled.
> -            3) Only Svadu present in DT => Supervisor must assume Svadu to be
> -               always enabled.
> +            3) Only Svadu present in DT => Supervisor must assume Svadu is
> +               enabled at boot.
>              4) Both Svade and Svadu present in DT => Supervisor must assume
> -               Svadu turned-off at boot time. To use Svadu, supervisor must
> +               Svadu is disabled at boot time. To use Svadu, supervisor must
>                 explicitly enable it using the SBI FWFT extension.
>  
>          - const: svadu
> diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> index 739fcc84bf7b2..ad9fad6eee55d 100644
> --- a/arch/riscv/include/asm/cpufeature.h
> +++ b/arch/riscv/include/asm/cpufeature.h
> @@ -128,6 +128,12 @@ struct riscv_isa_ext_data {
>  extern const struct riscv_isa_ext_data riscv_isa_ext[];
>  extern const size_t riscv_isa_ext_count;
>  extern bool riscv_isa_fallback;
> +DECLARE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
> +

I think a EXPORT_SYMBOL is required, otherwise the kvm is failed to be
built as module.

Regards,
Inochi


> +static __always_inline bool riscv_has_hw_pte_ad_updating(void)
> +{
> +	return static_branch_unlikely(&riscv_hw_pte_ad_updating);
> +}
>  
>  unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
>  static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
> index a1a7c6520a095..20663a466cf6c 100644
> --- a/arch/riscv/include/asm/pgtable.h
> +++ b/arch/riscv/include/asm/pgtable.h
> @@ -732,14 +732,14 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
>  #define pgprot_dmacoherent pgprot_writecombine
>  
>  /*
> - * Both Svade and Svadu control the hardware behavior when the PTE A/D bits need to be set. By
> - * default the M-mode firmware enables the hardware updating scheme when only Svadu is present in
> - * DT.
> + * Both Svade and Svadu control the hardware behavior when the PTE A/D bits
> + * need to be set. The core MM code only cares whether hardware updating of
> + * the accessed/dirty state is currently active.
>   */
>  #define arch_has_hw_pte_young arch_has_hw_pte_young
>  static inline bool arch_has_hw_pte_young(void)
>  {
> -	return riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
> +	return riscv_has_hw_pte_ad_updating();
>  }
>  
>  /*
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index f46aa5602d74d..831dd6a7c1a06 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -35,6 +35,7 @@
>  static bool any_cpu_has_zicboz;
>  static bool any_cpu_has_zicbop;
>  static bool any_cpu_has_zicbom;
> +DEFINE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
>  
>  unsigned long elf_hwcap __read_mostly;
>  
> @@ -287,15 +288,60 @@ static int riscv_ext_zvfbfwma_validate(const struct riscv_isa_ext_data *data,
>  	return -EPROBE_DEFER;
>  }
>  
> -static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data,
> -				    const unsigned long *isa_bitmap)
> +static void riscv_set_hw_pte_ad_updating(void)
> +{
> +	static_branch_enable(&riscv_hw_pte_ad_updating);
> +}
> +
> +static int riscv_hw_pte_ad_updating_starting(unsigned int cpu)
> +{
> +	int ret;
> +
> +	ret = sbi_fwft_set(SBI_FWFT_PTE_AD_HW_UPDATING, 1, 0);
> +	if (ret) {
> +		if (ret != -EOPNOTSUPP)
> +			pr_err("CPU%u failed to enable hardware PTE A/D updating: %d\n",
> +			       cpu, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int __init riscv_hw_pte_ad_updating_init(void)
>  {
> -	/* SVADE has already been detected, use SVADE only */
> -	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SVADE))
> -		return -EOPNOTSUPP;
> +	bool has_svade, has_svadu;
> +	int state;
>  
> +	has_svade = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADE);
> +	has_svadu = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
> +
> +	if (!has_svadu)
> +		return 0;
> +
> +	if (!has_svade)
> +		goto enable;
> +
> +	state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
> +				  "riscv/pte-ad:starting",
> +				  riscv_hw_pte_ad_updating_starting,
> +				  NULL);
> +	if (state < 0) {
> +		pr_info("riscv: leave PTE A/D updates software-managed (%d)\n",
> +			state);
> +		return 0;
> +	}
> +
> +	/*
> +	 * A successful CPUHP_AP_ONLINE_DYN registration means the startup
> +	 * callback has already succeeded on all online CPUs.
> +	 */
> +enable:
> +	riscv_set_hw_pte_ad_updating();
> +	pr_debug("riscv: hardware PTE A/D updating enabled\n");
>  	return 0;
>  }
> +arch_initcall(riscv_hw_pte_ad_updating_init);
>  
>  static int riscv_cfilp_validate(const struct riscv_isa_ext_data *data,
>  				const unsigned long *isa_bitmap)
> @@ -584,7 +630,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
>  	__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
>  	__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
>  	__RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),
> -	__RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate),
> +	__RISCV_ISA_EXT_DATA(svadu, RISCV_ISA_EXT_SVADU),
>  	__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
>  	__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
>  	__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
> -- 
> 2.39.5
> 


From ukleinek at kernel.org  Fri Jun  5 05:07:58 2026
From: ukleinek at kernel.org (Uwe =?utf-8?Q?Kleine-K=C3=B6nig?=)
Date: Fri, 5 Jun 2026 14:07:58 +0200
Subject: [PATCH v2] pwm: th1520: Remove requirement for
 mul_u64_u64_div_u64_roundup
In-Reply-To: <20260605-pwm-th1520-fix-v2-1-5921e3a595f7@mailbox.org>
References: <20260605-pwm-th1520-fix-v2-1-5921e3a595f7@mailbox.org>
Message-ID: <aiK7i_bblFzHDiH2@monoceros>

Hello,

On Fri, Jun 05, 2026 at 09:03:59AM +0200, Maurice Hieronymus wrote:
> The cycle register is always u32, so cycles_to_ns() can take a u32
> instead of a u64. With that narrowing, cycles * NSEC_PER_SEC is at most
> u32::MAX * 1e9 (~4.3e18), which fits in u64 without overflow. The
> saturating arithmetic is therefore no longer needed, and the ceiling
> division can use Rust's u64::div_ceil() directly instead of the
> open-coded numerator/denominator form.
> 
> This also drops the TODO referring to a future
> mul_u64_u64_div_u64_roundup kernel helper, which is no longer required.
> 
> Reviewed-by: Michal Wilczynski <m.wilczynski at samsung.com>
> Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>

Applied to

https://git.kernel.org/pub/scm/linux/kernel/git/ukleinek/linux.git pwm/for-next

Thanks
Uwe
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260605/4413be9f/attachment.sig>

From ustc.gu at gmail.com  Fri Jun  5 05:17:11 2026
From: ustc.gu at gmail.com (Felix Gu)
Date: Fri, 5 Jun 2026 20:17:11 +0800
Subject: [PATCH 0/2] drm/bridge: th1520-dw-hdmi: Two fixes
In-Reply-To: <4180689d3426882dcac2eb74209d398477f88b90.camel@iscas.ac.cn>
References: <20260321-th1520-v1-0-ec877197770d@gmail.com> <4180689d3426882dcac2eb74209d398477f88b90.camel@iscas.ac.cn>
Message-ID: <CAN4SLj09F+bSQFk4x3POGrh6hh2s8ssk1CmTDvrDzBCswZJBuQ@mail.gmail.com>

On Sat, Mar 21, 2026 at 1:05?PM Icenowy Zheng <zhengxingda at iscas.ac.cn> wrote:
>
> ? 2026-03-21?? 03:12 +0800?Felix Gu???
> > Signed-off-by: Felix Gu <ustc.gu at gmail.com>
> > ---
> > Felix Gu (2):
> >       drm/bridge: th1520-dw-hdmi: Fix error check on dw_hdmi_probe()
> > return value
> >       drm/bridge: th1520-dw-hdmi: Fix remove() callback
>
> Both fixes look trivial and let me start to doubt how could I make such
> mistakes.
>
> Reviewed-by: Icenowy Zheng <zhengxingda at iscas.ac.cn>
>
Hi,
Gentle ping on this.

Best regards,
Felix


From elder at riscstar.com  Fri Jun  5 06:15:46 2026
From: elder at riscstar.com (Alex Elder)
Date: Fri, 5 Jun 2026 08:15:46 -0500
Subject: [PATCH v7 1/2] i2c: spacemit: configure ILCR/IWCR for accurate
 SCL frequency
In-Reply-To: <20260508-k1-i2c-ilcr-v7-1-8c2dde5c3ed5@linux.spacemit.com>
References: <20260508-k1-i2c-ilcr-v7-0-8c2dde5c3ed5@linux.spacemit.com>
 <20260508-k1-i2c-ilcr-v7-1-8c2dde5c3ed5@linux.spacemit.com>
Message-ID: <db056a30-7b09-41f1-bae3-42dafb73cbfc@riscstar.com>

On 5/8/26 2:25 AM, Troy Mitchell wrote:
> The SpacemiT I2C controller's SCL (Serial Clock Line) frequency for
> master mode operations is determined by the ILCR (I2C Load Count Register).
> Previously, the driver relied on the hardware's reset default
> values for this register.
> 
> The hardware's default ILCR values (SLV=0x156, FLV=0x5d) yield SCL
> frequencies lower than intended. For example, with the default
> 31.5 MHz input clock, these default settings result in an SCL
> frequency of approximately 93 kHz (standard mode) when targeting 100 kHz,
> and approximately 338 kHz (fast mode) when targeting 400 kHz.
> These frequencies are below the 100 kHz/400 kHz nominal speeds.
> 
> This patch integrates the SCL frequency management into
> the Common Clock Framework (CCF). Specifically, the ILCR register,
> which acts as a frequency divider for the SCL clock, is now registered
> as a managed clock (scl_clk) within the CCF.
> 
> The actual hardware timing formulas are:
> - standard mode: SCL = FCLK / (2 * SLV + 8)
> - fast mode:     SCL = FCLK / (2 * FLV + 10)
> 
> These formulas are only valid when the IWCR (Wait Count Register) is
> programmed to 0x142A, a value specified by the I2C IP designer. The
> driver now initializes IWCR to this value during controller init.
> 
> Reviewed-by: Yixun Lan <dlan at gentoo.org>
> Signed-off-by: Troy Mitchell <troy.mitchell at linux.spacemit.com>

I have several comments below, but none of them are really
critical, they're just suggestions.  Consider incorporating
each of them, but that's up to you.  Either way:

Reviewed-by: Alex Elder <elder at riscstar.com>

> ---
> Changelog in v7:
> - break SPACEMIT_IWCR_INIT_VALUE into FIELD_PREP fields with GENMASK definitions
> - extract spacemit_i2c_calc_lv() as shared helper for set_rate and determine_rate
> - switch from devm_clk_register() to devm_clk_hw_register() (deprecated API)
> - use devm_clk_hw_get_clk() to obtain struct clk* from clk_hw
> - Link to v6: https://lore.kernel.org/all/20260429-k1-i2c-ilcr-v6-1-1c7a5a5a8b24 at linux.spacemit.com/
> 
> Changelog in v6:
> - fix SCL frequency calculation to match hardware timing formulas
>    (SCL = FCLK / (2*SLV+8) for standard, FCLK / (2*FLV+10) for fast)
> - initialize IWCR to 0x142A during init(required by I2C IP for
>    correct SCL timing)
> - use DIV_ROUND_CLOSEST() instead of DIV_ROUND_UP() for more accurate frequency
> - use field_prep() instead of manual bit shift for ILCR register programming
> - replace .round_rate with .determine_rate (round_rate was removed from clk_ops)
> - remove _MAX_VALUE macros (no longer needed after removing max_lv validation)
> - remove redundant max_lv validation in set_rate (determine_rate guarantees valid values)
> - simplify scl_clk_disable_unprepare callback to take clk pointer directly
> - remove unused parent parameter from spacemit_i2c_register_scl_clk()
> - remove stale description about whitespace cleanup from commit message
> - Link to v5: https://lore.kernel.org/r/20251226-k1-i2c-ilcr-v5-0-b5807b7dd0e6 at linux.spacemit.com
> 
> Changelog in v5:
> - use __ffs() instead of *_SHIFT
> - remove useless *_SHIFT
> - check return value when scl clk name array is truncated
> - rebase to v6.19-rc1
> - Link to v3: https://lore.kernel.org/all/20251017-k1-i2c-ilcr-v4-1-eed4903ecdb9 at linux.spacemit.com/
> 
> Changelog in v4:
> - initialize clk_init_data with {} so that init.flags is implicitly set to 0
> - minor cleanup and style fixes for better readability
> - remove unused spacemit_i2c_scl_clk_exclusive_put() cleanup callback
> - replace clk_set_rate_exclusive()/clk_rate_exclusive_put() pair with clk_set_rate()
> - simplify LCR LV field macros by using FIELD_GET/FIELD_MAX helpers
> - Link to v3: https://lore.kernel.org/all/20250814-k1-i2c-ilcr-v3-1-317723e74bcd at linux.spacemit.com/
> 
> Changelog in v3:
> - use MASK macro in `recalc_rate` function
> - rename clock name
> - Link to v2: https://lore.kernel.org/r/20250718-k1-i2c-ilcr-v2-1-b4c68f13dcb1 at linux.spacemit.com
> 
> Changelog in v2:
> - Align line breaks.
> - Check `lv` in `clk_set_rate` function.
> - Force fast mode when SCL frequency is illegal or unavailable.
> - Change "linux/bits.h" to <linux/bits.h>
> - Kconfig: Add dependency on CCF.
> - Link to v1: https://lore.kernel.org/all/20250710-k1-i2c-ilcr-v1-1-188d1f460c7d at linux.spacemit.com/
> ---
>   drivers/i2c/busses/Kconfig  |   2 +-
>   drivers/i2c/busses/i2c-k1.c | 174 ++++++++++++++++++++++++++++++++++++++++++--
>   2 files changed, 167 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
> index 8c935f867a37..89898fff1967 100644
> --- a/drivers/i2c/busses/Kconfig
> +++ b/drivers/i2c/busses/Kconfig
> @@ -793,7 +793,7 @@ config I2C_JZ4780
>   config I2C_K1
>   	tristate "SpacemiT K1 I2C adapter"
>   	depends on ARCH_SPACEMIT || COMPILE_TEST
> -	depends on OF
> +	depends on OF && COMMON_CLK
>   	help
>   	  This option enables support for the I2C interface on the SpacemiT K1
>   	  platform.
> diff --git a/drivers/i2c/busses/i2c-k1.c b/drivers/i2c/busses/i2c-k1.c
> index 9152cf436bea..c6fe2052e479 100644
> --- a/drivers/i2c/busses/i2c-k1.c
> +++ b/drivers/i2c/busses/i2c-k1.c
> @@ -4,7 +4,9 @@
>    */
>   
>   #include <linux/bitfield.h>
> +#include <linux/bits.h>
>   #include <linux/clk.h>
> +#include <linux/clk-provider.h>
>   #include <linux/i2c.h>
>   #include <linux/iopoll.h>
>   #include <linux/module.h>
> @@ -17,6 +19,8 @@
>   #define SPACEMIT_ISR		 0x4		/* Status register */
>   #define SPACEMIT_IDBR		 0xc		/* Data buffer register */
>   #define SPACEMIT_IRCR		 0x18		/* Reset cycle counter */
> +#define SPACEMIT_ILCR		 0x10		/* Load Count Register */
> +#define SPACEMIT_IWCR		 0x14		/* Wait Count Register */
>   #define SPACEMIT_IBMR		 0x1c		/* Bus monitor register */
>   
>   /* SPACEMIT_ICR register fields */
> @@ -88,6 +92,19 @@
>   #define SPACEMIT_BMR_SDA         BIT(0)		/* SDA line level */
>   #define SPACEMIT_BMR_SCL         BIT(1)		/* SCL line level */
>   

/* SPACEMIT_ILCR register fields */

> +#define SPACEMIT_LCR_LV_STANDARD_MASK		GENMASK(8, 0)
> +#define SPACEMIT_LCR_LV_FAST_MASK		GENMASK(17, 9)
> +
> +/* SPACEMIT_IWCR register fields */
> +#define SPACEMIT_WCR_COUNT			GENMASK(4, 0)
> +#define SPACEMIT_WCR_HS_COUNT1			GENMASK(9, 5)
> +#define SPACEMIT_WCR_HS_COUNT2			GENMASK(14, 10)
> +
> +/* Required by I2C IP for correct SCL timing */
> +#define SPACEMIT_IWCR_INIT_VALUE		(FIELD_PREP(SPACEMIT_WCR_COUNT, 10) | \
> +						 FIELD_PREP(SPACEMIT_WCR_HS_COUNT1, 1) | \
> +						 FIELD_PREP(SPACEMIT_WCR_HS_COUNT2, 5))
> +
>   /* i2c bus recover timeout: us */
>   #define SPACEMIT_I2C_BUS_BUSY_TIMEOUT		100000
>   
> @@ -109,11 +126,20 @@ enum spacemit_i2c_state {
>   	SPACEMIT_STATE_WRITE,
>   };
>   
> +enum spacemit_i2c_mode {
> +	SPACEMIT_MODE_STANDARD,
> +	SPACEMIT_MODE_FAST
> +};
> +
>   /* i2c-spacemit driver's main struct */
>   struct spacemit_i2c_dev {
>   	struct device *dev;
>   	struct i2c_adapter adapt;
>   
> +	struct clk_hw scl_clk_hw;
> +	struct clk *scl_clk;
> +	enum spacemit_i2c_mode mode;
> +
>   	/* hardware resources */
>   	void __iomem *base;
>   	int irq;
> @@ -135,6 +161,85 @@ struct spacemit_i2c_dev {
>   	u32 status;
>   };
>   
> +static void spacemit_i2c_scl_clk_disable_unprepare(void *data)
> +{

I know a cast from void pointer is not needed, but I normally
would expect to see this here:

	struct clk *clk = data;

> +	clk_disable_unprepare(data);
> +}
> +
> +/*
> + * Calculate the ILCR divider value (lv) from the target SCL rate.
> + *
> + * Hardware timing formulas:
> + * - standard mode: SCL = FCLK / (2 * SLV + 8)
> + * - fast mode:     SCL = FCLK / (2 * FLV + 10)

This is a very clear description of what you're doing here.

> + */
> +static u32 spacemit_i2c_calc_lv(struct spacemit_i2c_dev *i2c,
> +				unsigned long parent_rate,
> +				unsigned long target_rate)
> +{
> +	u32 offset, denom;
> +
> +	offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10;

No need for the parentheses above.

> +	denom = DIV_ROUND_CLOSEST(parent_rate, target_rate);
> +
> +	return (denom <= offset) ? 0 : DIV_ROUND_CLOSEST(denom - offset, 2);

Parentheses are not needed here around the condition here either
(and in general for simple ternary conditional operators).

> +}
> +
> +static int spacemit_i2c_clk_set_rate(struct clk_hw *hw, unsigned long rate,
> +				     unsigned long parent_rate)
> +{
> +	struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
> +	u32 lv, lcr, mask;
> +
> +	lv = spacemit_i2c_calc_lv(i2c, parent_rate, rate);
> +
> +	mask = (i2c->mode == SPACEMIT_MODE_STANDARD) ?
> +		SPACEMIT_LCR_LV_STANDARD_MASK : SPACEMIT_LCR_LV_FAST_MASK;
> +
> +	lcr = readl(i2c->base + SPACEMIT_ILCR);
> +	lcr &= ~mask;
> +	lcr |= field_prep(mask, lv);
> +	writel(lcr, i2c->base + SPACEMIT_ILCR);
> +
> +	return 0;
> +}
> +
> +static int spacemit_i2c_clk_determine_rate(struct clk_hw *hw,
> +					   struct clk_rate_request *req)
> +{
> +	struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
> +	u32 lv, offset;
> +
> +	lv = spacemit_i2c_calc_lv(i2c, req->best_parent_rate, req->rate);
> +	offset = (i2c->mode == SPACEMIT_MODE_STANDARD) ? 8 : 10;
> +	req->rate = DIV_ROUND_CLOSEST(req->best_parent_rate, lv * 2 + offset);
> +
> +	return 0;
> +}
> +
> +static unsigned long spacemit_i2c_clk_recalc_rate(struct clk_hw *hw,
> +						  unsigned long parent_rate)
> +{
> +	struct spacemit_i2c_dev *i2c = container_of(hw, struct spacemit_i2c_dev, scl_clk_hw);
> +	u32 lcr, lv = 0;
> +
> +	lcr = readl(i2c->base + SPACEMIT_ILCR);
> +

You could structure this function a little more like
spacemit_i2c_clk_determine_rate().

Or you could create a tiny helper that computes the rate,
given the parent rate, lv, and mode.  The main reason for
doing that is that the "complex" math is isolated rather
than duplicated.

> +	if (i2c->mode == SPACEMIT_MODE_STANDARD) {
> +		lv = FIELD_GET(SPACEMIT_LCR_LV_STANDARD_MASK, lcr);
> +		return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 8);
> +	}
> +
> +	lv = FIELD_GET(SPACEMIT_LCR_LV_FAST_MASK, lcr);
> +	return DIV_ROUND_CLOSEST(parent_rate, lv * 2 + 10);
> +}
> +
> +static const struct clk_ops spacemit_i2c_clk_ops = {
> +	.set_rate = spacemit_i2c_clk_set_rate,
> +	.determine_rate = spacemit_i2c_clk_determine_rate,
> +	.recalc_rate = spacemit_i2c_clk_recalc_rate,
> +};
> +
>   static void spacemit_i2c_enable(struct spacemit_i2c_dev *i2c)
>   {
>   	u32 val;
> @@ -153,6 +258,28 @@ static void spacemit_i2c_disable(struct spacemit_i2c_dev *i2c)
>   	writel(val, i2c->base + SPACEMIT_ICR);
>   }
>   
> +static int spacemit_i2c_register_scl_clk(struct spacemit_i2c_dev *i2c)
> +{
> +	struct clk_init_data init = {};
> +	char name[64];
> +	int ret;
> +
> +	ret = snprintf(name, sizeof(name), "%s_scl_clk", dev_name(i2c->dev));
> +	if (ret >= ARRAY_SIZE(name))
> +		dev_warn(i2c->dev, "scl clock name truncated");
> +
> +	init.name = name;
> +	init.ops = &spacemit_i2c_clk_ops;
> +	init.parent_data = (struct clk_parent_data[]) {
> +		{ .fw_name = "func" },
> +	};
> +	init.num_parents = 1;
> +
> +	i2c->scl_clk_hw.init = &init;
> +
> +	return devm_clk_hw_register(i2c->dev, &i2c->scl_clk_hw);
> +}
> +
>   static void spacemit_i2c_reset(struct spacemit_i2c_dev *i2c)
>   {
>   	writel(SPACEMIT_CR_UR, i2c->base + SPACEMIT_ICR);
> @@ -286,7 +413,7 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
>   		val |= SPACEMIT_CR_MSDIE;
>   	}
>   
> -	if (i2c->clock_freq == SPACEMIT_I2C_MAX_FAST_MODE_FREQ)
> +	if (i2c->mode == SPACEMIT_MODE_FAST)
>   		val |= SPACEMIT_CR_MODE_FAST;
>   
>   	/* disable response to general call */
> @@ -309,6 +436,14 @@ static void spacemit_i2c_init(struct spacemit_i2c_dev *i2c)
>   	writel(val, i2c->base + SPACEMIT_IRCR);
>   
>   	spacemit_i2c_clear_int_status(i2c, SPACEMIT_I2C_INT_STATUS_MASK);
> +
> +	/*
> +	 * Initialize IWCR to the value specified by the I2C IP designer.
> +	 * The SCL frequency formulas (SCL = FCLK / (2*SLV+8) for standard
> +	 * mode, SCL = FCLK / (2*FLV+10) for fast mode) are only valid when
> +	 * IWCR contains this specific value.
> +	 */

Nice explanation for writing the magic number.

					-Alex

> +	writel(SPACEMIT_IWCR_INIT_VALUE, i2c->base + SPACEMIT_IWCR);
>   }
>   
>   static void spacemit_i2c_start(struct spacemit_i2c_dev *i2c)
> @@ -703,14 +838,15 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
>   		dev_warn(dev, "failed to read clock-frequency property: %d\n", ret);
>   
>   	/* For now, this driver doesn't support high-speed. */
> -	if (!i2c->clock_freq || i2c->clock_freq > SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
> -		dev_warn(dev, "unsupported clock frequency %u; using %u\n",
> -			 i2c->clock_freq, SPACEMIT_I2C_MAX_FAST_MODE_FREQ);
> +	if (i2c->clock_freq > SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ &&
> +	    i2c->clock_freq <= SPACEMIT_I2C_MAX_FAST_MODE_FREQ) {
> +		i2c->mode = SPACEMIT_MODE_FAST;
> +	} else if (i2c->clock_freq && i2c->clock_freq <= SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
> +		i2c->mode = SPACEMIT_MODE_STANDARD;
> +	} else {
> +		dev_warn(i2c->dev, "invalid clock-frequency, fallback to fast mode");
> +		i2c->mode = SPACEMIT_MODE_FAST;
>   		i2c->clock_freq = SPACEMIT_I2C_MAX_FAST_MODE_FREQ;
> -	} else if (i2c->clock_freq < SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ) {
> -		dev_warn(dev, "unsupported clock frequency %u; using %u\n",
> -			 i2c->clock_freq,  SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ);
> -		i2c->clock_freq = SPACEMIT_I2C_MAX_STANDARD_MODE_FREQ;
>   	}
>   
>   	i2c->dev = &pdev->dev;
> @@ -732,6 +868,15 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
>   	if (IS_ERR(clk))
>   		return dev_err_probe(dev, PTR_ERR(clk), "failed to enable func clock");
>   
> +	ret = spacemit_i2c_register_scl_clk(i2c);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to register scl clock\n");
> +
> +	i2c->scl_clk = devm_clk_hw_get_clk(dev, &i2c->scl_clk_hw, "scl");
> +	if (IS_ERR(i2c->scl_clk))
> +		return dev_err_probe(dev, PTR_ERR(i2c->scl_clk),
> +				     "failed to get scl clock\n");
> +
>   	clk = devm_clk_get_enabled(dev, "bus");
>   	if (IS_ERR(clk))
>   		return dev_err_probe(dev, PTR_ERR(clk), "failed to enable bus clock");
> @@ -741,6 +886,19 @@ static int spacemit_i2c_probe(struct platform_device *pdev)
>   		return dev_err_probe(dev, PTR_ERR(rst),
>   				     "failed to acquire deasserted reset\n");
>   
> +	ret = clk_set_rate(i2c->scl_clk, i2c->clock_freq);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to set rate for SCL clock");
> +
> +	ret = clk_prepare_enable(i2c->scl_clk);
> +	if (ret)
> +		return dev_err_probe(dev, ret, "failed to prepare and enable clock");
> +
> +	ret = devm_add_action_or_reset(dev, spacemit_i2c_scl_clk_disable_unprepare,
> +				       i2c->scl_clk);
> +	if (ret)
> +		return ret;
> +
>   	spacemit_i2c_reset(i2c);
>   
>   	i2c_set_adapdata(&i2c->adapt, i2c);
> 



From mpe at kernel.org  Fri Jun  5 07:02:41 2026
From: mpe at kernel.org (Michael Ellerman)
Date: Sat, 6 Jun 2026 00:02:41 +1000
Subject: [PATCH v2 7/7] riscv: dts: tenstorrent: Add Atlantis platform
In-Reply-To: <20260604-pacifier-sludge-196f47ab3c11@spud>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-8-joel@jms.id.au>
 <20260604-pacifier-sludge-196f47ab3c11@spud>
Message-ID: <f3fd53dc-7010-4b3d-a33c-4d1d32d3a1a6@kernel.org>

On 5/6/26 2:47 am, Conor Dooley wrote:
> On Fri, Jun 05, 2026 at 12:09:53AM +0930, Joel Stanley wrote:
>> Add initial support for the Tenstorrent Atlantis platform, based on the
>> Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.
>>
>> The evb machine represents an internal bringup vehicle with just the
>> interrupt controllers and a UART. This will be replaced in time with a
>> full featured machine once details are available.
...
>> diff --git a/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
>> new file mode 100644
>> index 000000000000..06259cca8357
>> --- /dev/null
>> +++ b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
>> @@ -0,0 +1,33 @@
>> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
>> +/dts-v1/;
>> +
>> +#include "atlantis-soc.dtsi"
>> +
>> +/ {
>> +	model = "Tenstorrent Atlantis development platform";
>> +	compatible = "tenstorrent,atlantis-evb", "tenstorrent,atlantis";
>> +
>> +	#address-cells = <2>;
>> +	#size-cells = <2>;
>> +
>> +	memory at 0 {
>> +		device_type = "memory";
>> +		reg = <0x0 0x00000000 0x0 0x80000000>,
>> +		      <0x1 0x80000000 0x0 0x80000000>;
>> +	};
>> +
>> +	aliases {
>> +		serial0 = &uart1;
>> +	};
>> +
>> +	chosen {
>> +		bootargs = "earlycon console=ttyS0";
> 
> FYI, this should not be in here.

It should be there if you want a working console :)

I know it's a "rule" to not include bootargs, but this system has no 
boot loader, so not setting bootargs just means the DTS is no use to anyone.

>> +		stdout-path = "serial0";
>> +	};
>> +};
>> +
>> +&uart1 {
>> +	/delete-property/ clocks;
> 
> Why are you doing this? Looks kinda suspect!

On the bringup system the uart has a fixed clock, I don't know exactly why.

>> +	clock-frequency = <5000000>;
>> +	status = "okay";
>> +};
Having said that, I think we talked about making this DTS match the qemu 
model rather than the internal bringup system. So if we do that then 
this will change.

Thanks for the reviews.

cheers


From mssola at mssola.com  Fri Jun  5 07:12:47 2026
From: mssola at mssola.com (=?UTF-8?q?Miquel=20Sabat=C3=A9=20Sol=C3=A0?=)
Date: Fri,  5 Jun 2026 16:12:47 +0200
Subject: [PATCH RESEND] riscv: enable HAVE_CMPXCHG_{DOUBLE,LOCAL}
Message-ID: <20260605141247.253315-1-mssola@mssola.com>

Support for atomic Compare-And-Swap instructions has been in the RISC-V
port of the Linux kernel for a long time. That being said, we apparently
never bothered to set HAVE_CMPXCHG_DOUBLE and HAVE_CMPXCHG_LOCAL in the
Kconfig, despite having all the framework to support them.

Signed-off-by: Miquel Sabat? Sol? <mssola at mssola.com>
---
This is a resend of [1], rebased on top of the latest commit from the
for-next branch.

I have built this patch with multiple configurations and ran it with KVM
(the VisionFive2 board that I have lacks the needed extensions). All seems
to work, but I do wonder if we did not enable these for a reason or this
just slipped through. So far in the code I believe everything is in place,
and I haven't seen any commit in the git log stating otherwise.

[1] https://lore.kernel.org/all/20260220074449.8526-1-mssola at mssola.com/

 Documentation/features/locking/cmpxchg-local/arch-support.txt | 2 +-
 arch/riscv/Kconfig                                            | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/features/locking/cmpxchg-local/arch-support.txt b/Documentation/features/locking/cmpxchg-local/arch-support.txt
index 2c3a4b91f16d..28d5fa8c3b4f 100644
--- a/Documentation/features/locking/cmpxchg-local/arch-support.txt
+++ b/Documentation/features/locking/cmpxchg-local/arch-support.txt
@@ -20,7 +20,7 @@
     |    openrisc: | TODO |
     |      parisc: | TODO |
     |     powerpc: | TODO |
-    |       riscv: | TODO |
+    |       riscv: |  ok  |
     |        s390: |  ok  |
     |          sh: | TODO |
     |       sparc: | TODO |
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 1955fcc5effd..b8ca5792a392 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -152,6 +152,8 @@ config RISCV
 	select HAVE_ARCH_USERFAULTFD_WP if 64BIT && MMU && USERFAULTFD && RISCV_ISA_SVRSW60T59B
 	select HAVE_ARCH_VMAP_STACK if MMU && 64BIT
 	select HAVE_ASM_MODVERSIONS
+	select HAVE_CMPXCHG_DOUBLE if RISCV_ISA_ZACAS && RISCV_ISA_ZABHA
+	select HAVE_CMPXCHG_LOCAL if RISCV_ISA_ZACAS && RISCV_ISA_ZABHA
 	select HAVE_BUILDTIME_MCOUNT_SORT
 	select HAVE_CONTEXT_TRACKING_USER
 	select HAVE_DEBUG_KMEMLEAK
--
2.54.0


From anup at brainfault.org  Fri Jun  5 07:54:21 2026
From: anup at brainfault.org (Anup Patel)
Date: Fri, 5 Jun 2026 20:24:21 +0530
Subject: [PATCH] RISC-V: KVM: Enhance the logging check for mmu mapping
In-Reply-To: <20260528113840.2629186-1-inochiama@gmail.com>
References: <20260528113840.2629186-1-inochiama@gmail.com>
Message-ID: <CAAhSdy1svqDsgNSMhawR4xJN0=LLpRv2dkTu54oc9S7BmqfVzg@mail.gmail.com>

On Thu, May 28, 2026 at 5:08?PM Inochi Amaoto <inochiama at gmail.com> wrote:
>
> When enabling dirty ring, the dirty bitmap is disable, and the logging
> check is always false as the RISC-V architecture does not select
> "NEED_KVM_DIRTY_RING_WITH_BITMAP". Although the dirty log is recorded
> since the write path already trying to add the dirty log, the logic for
> logging check is broken and some side effect will occurs.
>
> Enhance the logging check for mmu mapping so it can check both the dirty
> ring and the dirty bitmap.
>
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this patch for Linux-7.2

Thanks,
Anup

> ---
>  arch/riscv/kvm/mmu.c | 9 ++++-----
>  1 file changed, 4 insertions(+), 5 deletions(-)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 2d3def024270..b5873bca9dce 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -142,9 +142,8 @@ void kvm_arch_commit_memory_region(struct kvm *kvm,
>                                 enum kvm_mr_change change)
>  {
>         /*
> -        * At this point memslot has been committed and there is an
> -        * allocated dirty_bitmap[], dirty pages will be tracked while
> -        * the memory slot is write protected.
> +        * At this point memslot has been committed and dirty pages will be
> +        * tracked while the memory slot is write protected.
>          */
>         if (change != KVM_MR_DELETE && new->flags & KVM_MEM_LOG_DIRTY_PAGES) {
>                 if (kvm_dirty_log_manual_protect_and_init_set(kvm))
> @@ -433,8 +432,8 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
>         struct vm_area_struct *vma;
>         struct kvm *kvm = vcpu->kvm;
>         struct kvm_mmu_memory_cache *pcache = &vcpu->arch.mmu_page_cache;
> -       bool logging = (memslot->dirty_bitmap &&
> -                       !(memslot->flags & KVM_MEM_READONLY)) ? true : false;
> +       bool logging = kvm_slot_dirty_track_enabled(memslot) &&
> +                      !(memslot->flags & KVM_MEM_READONLY);
>         unsigned long vma_pagesize, mmu_seq;
>         struct kvm_gstage gstage;
>         struct page *page;
> --
> 2.54.0
>


From ripatel at wii.dev  Fri Jun  5 08:10:31 2026
From: ripatel at wii.dev (Richard Patel)
Date: Fri, 5 Jun 2026 15:10:31 +0000
Subject: [PATCH] riscv: cfi: reject unknown flags in PR_SET_CFI
In-Reply-To: <3f2d4628-a95d-89c3-2fd7-3e1a407d698a@kernel.org>
References: <20260518183918.322545-1-ripatel@wii.dev>
 <3f2d4628-a95d-89c3-2fd7-3e1a407d698a@kernel.org>
Message-ID: <aiLm58Sjuj8XAaSF@wii.dev>

On Thu, Jun 04, 2026 at 04:40:31PM -0600, Paul Walmsley wrote:
> Hi,
> 
> On Mon, 18 May 2026, Richard Patel wrote:
> 
> > prctl(PR_SET_CFI,PR_CFI_BRANCH_LANDING_PADS) silently ignored
> > unknown control values. Only PR_CFI_{ENABLE,DISABLE,LOCK} should
> > be permitted.
> <
> > This is a uABI breaking change (fails previously accepted bits
> > with EINVAL).
> 
> Thanks for the patch.  However, I'm not convinced that this actually 
> breaks anything.  The behavior of the interface changes when unknown flags 
> are specified, but I'm not aware of anything that relies on this specific 
> behavior.
> 
> Does that match your understanding?

I agree, yes, happy to rephrase the commit message.


From anup at brainfault.org  Fri Jun  5 08:30:52 2026
From: anup at brainfault.org (Anup Patel)
Date: Fri, 5 Jun 2026 21:00:52 +0530
Subject: [PATCH v5 1/5] KVM: RISC-V: SBI FWFT: Mark vCPU CSRs dirty after
 setting feature value
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-1-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com> <20260601-kvm-get_reg_list-v2-v5-1-415d08a2813b@sifive.com>
Message-ID: <CAAhSdy0m+ZpxBznL-gx5ozpbyLzU7rO6zZnnB=5eZt=eLvV+sA@mail.gmail.com>

On Mon, Jun 1, 2026 at 3:56?PM Yong-Xuan Wang <yongxuan.wang at sifive.com> wrote:
>
> Mark the vCPU CSRs as dirty after successfully setting an FWFT feature
> value. FWFT features may modify CSRs (e.g., pointer masking modifies
> henvcfg.PMM), and failing to mark them dirty can lead to the guest
> observing stale CSR state after vCPU scheduling or migration.
>
> Fixes: 1323a5cfe52c ("KVM: riscv: Skip CSR restore if VCPU is reloaded on the same core")
>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup

> ---
>  arch/riscv/kvm/vcpu_sbi_fwft.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
> index 2eab15339694..5e4aafb0cbf1 100644
> --- a/arch/riscv/kvm/vcpu_sbi_fwft.c
> +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
> @@ -521,6 +521,7 @@ static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
>                 break;
>         case 2:
>                 ret = conf->feature->set(vcpu, conf, true, value);
> +               vcpu->arch.csr_dirty = true;
>                 break;
>         default:
>                 return -ENOENT;
>
> --
> 2.43.7
>


From conor at kernel.org  Fri Jun  5 08:41:20 2026
From: conor at kernel.org (Conor Dooley)
Date: Fri, 5 Jun 2026 16:41:20 +0100
Subject: [PATCH v2 7/7] riscv: dts: tenstorrent: Add Atlantis platform
In-Reply-To: <f3fd53dc-7010-4b3d-a33c-4d1d32d3a1a6@kernel.org>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-8-joel@jms.id.au>
 <20260604-pacifier-sludge-196f47ab3c11@spud>
 <f3fd53dc-7010-4b3d-a33c-4d1d32d3a1a6@kernel.org>
Message-ID: <20260605-unlivable-stardom-00ac93dfce5c@spud>

On Sat, Jun 06, 2026 at 12:02:41AM +1000, Michael Ellerman wrote:
> On 5/6/26 2:47 am, Conor Dooley wrote:
> > On Fri, Jun 05, 2026 at 12:09:53AM +0930, Joel Stanley wrote:
> > > Add initial support for the Tenstorrent Atlantis platform, based on the
> > > Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.
> > > 
> > > The evb machine represents an internal bringup vehicle with just the
> > > interrupt controllers and a UART. This will be replaced in time with a
> > > full featured machine once details are available.
> ...
> > > diff --git a/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
> > > new file mode 100644
> > > index 000000000000..06259cca8357
> > > --- /dev/null
> > > +++ b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
> > > @@ -0,0 +1,33 @@
> > > +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> > > +/dts-v1/;
> > > +
> > > +#include "atlantis-soc.dtsi"
> > > +
> > > +/ {
> > > +	model = "Tenstorrent Atlantis development platform";
> > > +	compatible = "tenstorrent,atlantis-evb", "tenstorrent,atlantis";
> > > +
> > > +	#address-cells = <2>;
> > > +	#size-cells = <2>;
> > > +
> > > +	memory at 0 {
> > > +		device_type = "memory";
> > > +		reg = <0x0 0x00000000 0x0 0x80000000>,
> > > +		      <0x1 0x80000000 0x0 0x80000000>;
> > > +	};
> > > +
> > > +	aliases {
> > > +		serial0 = &uart1;
> > > +	};
> > > +
> > > +	chosen {
> > > +		bootargs = "earlycon console=ttyS0";
> > 
> > FYI, this should not be in here.
> 
> It should be there if you want a working console :)
> 
> I know it's a "rule" to not include bootargs, but this system has no boot
> loader, so not setting bootargs just means the DTS is no use to anyone.

I see! Could you note this please in the commit message?

> 
> > > +		stdout-path = "serial0";
> > > +	};
> > > +};
> > > +
> > > +&uart1 {
> > > +	/delete-property/ clocks;
> > 
> > Why are you doing this? Looks kinda suspect!
> 
> On the bringup system the uart has a fixed clock, I don't know exactly why.

The reason I ask is less about the rate being fixed, and more why you
need to set it like this. You've got
clocks = <&prcm_rcpu CLK_UART1_PCLK>;
and I would expect (or maybe more accurately hope) that the prcm_rcpu
driver would be able to report the fixed rate?

> 
> > > +	clock-frequency = <5000000>;
> > > +	status = "okay";
> > > +};
> Having said that, I think we talked about making this DTS match the qemu
> model rather than the internal bringup system. So if we do that then this
> will change.
> 
> Thanks for the reviews.
> 
> cheers
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260605/1d8e70fa/attachment.sig>

From anup at brainfault.org  Fri Jun  5 09:11:43 2026
From: anup at brainfault.org (Anup Patel)
Date: Fri, 5 Jun 2026 21:41:43 +0530
Subject: [PATCH v5 2/5] KVM: RISC-V: SBI FWFT: Add optional init()
 callback for hardware probing
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-2-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com> <20260601-kvm-get_reg_list-v2-v5-2-415d08a2813b@sifive.com>
Message-ID: <CAAhSdy1QsWMYvn9ma5gSLHyezY32t=2YGpddOgrCzqCR9qa_ug@mail.gmail.com>

On Mon, Jun 1, 2026 at 3:56?PM Yong-Xuan Wang <yongxuan.wang at sifive.com> wrote:
>
> Add an optional init() callback to separate one-time hardware probing
> from runtime availability checks. For pointer masking, this allows
> probing supported PMM lengths during initialization while checking ISA
> extension availability at runtime.
>
> Fix try_to_set_pmm() to restore the previous HENVCFG.PMM value after
> probing, preventing side effects from hardware detection. Add preemption
> protection to ensure CSR probe sequences complete atomically on the same
> CPU.
>
> Fixes: 6f576fc0aeb9 ("RISC-V: KVM: Add support for SBI_FWFT_POINTER_MASKING_PMLEN")
>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup

> ---
>  arch/riscv/kvm/vcpu_sbi_fwft.c | 33 +++++++++++++++++++++++++++++----
>  1 file changed, 29 insertions(+), 4 deletions(-)
>
> diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
> index 5e4aafb0cbf1..aee951f2b8e6 100644
> --- a/arch/riscv/kvm/vcpu_sbi_fwft.c
> +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
> @@ -35,6 +35,16 @@ struct kvm_sbi_fwft_feature {
>          */
>         bool (*supported)(struct kvm_vcpu *vcpu);
>
> +       /**
> +        * @init: Probe and initialize the feature on the vcpu
> +        *
> +        * This callback is optional. If provided, it will be called during
> +        * vcpu initialization to probe the feature availability and perform
> +        * any necessary initialization. Returns true if the feature is supported
> +        * and initialized successfully, false otherwise.
> +        */
> +       bool (*init)(struct kvm_vcpu *vcpu);
> +
>         /**
>          * @reset: Reset the feature value irrespective whether feature is supported or not
>          *
> @@ -131,19 +141,30 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
>
>  static bool try_to_set_pmm(unsigned long value)
>  {
> +       unsigned long prev;
> +       bool ret;
> +
> +       prev = csr_read_clear(CSR_HENVCFG, ENVCFG_PMM);
>         csr_set(CSR_HENVCFG, value);
> -       return (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
> +       ret = (csr_read_clear(CSR_HENVCFG, ENVCFG_PMM) & ENVCFG_PMM) == value;
> +       csr_write(CSR_HENVCFG, prev);
> +
> +       return ret;
>  }
>
>  static bool kvm_sbi_fwft_pointer_masking_pmlen_supported(struct kvm_vcpu *vcpu)
>  {
> -       struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
> +       return riscv_isa_extension_available(vcpu->arch.isa, SMNPM);
> +}
>
> -       if (!riscv_isa_extension_available(vcpu->arch.isa, SMNPM))
> -               return false;
> +static bool kvm_sbi_fwft_pointer_masking_pmlen_init(struct kvm_vcpu *vcpu)
> +{
> +       struct kvm_sbi_fwft *fwft = vcpu_to_fwft(vcpu);
>
> +       preempt_disable();
>         fwft->have_vs_pmlen_7 = try_to_set_pmm(ENVCFG_PMM_PMLEN_7);
>         fwft->have_vs_pmlen_16 = try_to_set_pmm(ENVCFG_PMM_PMLEN_16);
> +       preempt_enable();
>
>         return fwft->have_vs_pmlen_7 || fwft->have_vs_pmlen_16;
>  }
> @@ -231,6 +252,7 @@ static const struct kvm_sbi_fwft_feature features[] = {
>                 .first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pointer_masking.enable) /
>                                  sizeof(unsigned long),
>                 .supported = kvm_sbi_fwft_pointer_masking_pmlen_supported,
> +               .init = kvm_sbi_fwft_pointer_masking_pmlen_init,
>                 .reset = kvm_sbi_fwft_reset_pointer_masking_pmlen,
>                 .set = kvm_sbi_fwft_set_pointer_masking_pmlen,
>                 .get = kvm_sbi_fwft_get_pointer_masking_pmlen,
> @@ -365,6 +387,9 @@ static int kvm_sbi_ext_fwft_init(struct kvm_vcpu *vcpu)
>                 else
>                         conf->supported = true;
>
> +               if (conf->supported && feature->init)
> +                       conf->supported = feature->init(vcpu);
> +
>                 conf->enabled = conf->supported;
>                 conf->feature = feature;
>         }
>
> --
> 2.43.7
>


From anup at brainfault.org  Fri Jun  5 09:12:07 2026
From: anup at brainfault.org (Anup Patel)
Date: Fri, 5 Jun 2026 21:42:07 +0530
Subject: [PATCH v5 3/5] KVM: RISC-V: SBI FWFT: Fix stale feature exposure
 after runtime extension changes
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-3-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com> <20260601-kvm-get_reg_list-v2-v5-3-415d08a2813b@sifive.com>
Message-ID: <CAAhSdy25VTfezS2zUsuTCTZ+Bwie7c-oHQYOWod1ix1y5rWOWQ@mail.gmail.com>

On Mon, Jun 1, 2026 at 3:56?PM Yong-Xuan Wang <yongxuan.wang at sifive.com> wrote:
>
> Fix a bug where FWFT features could be incorrectly exposed to guests
> after userspace disables their dependent ISA extensions at runtime.
>
> The 'supported' field in kvm_sbi_fwft_config was set once during vCPU
> initialization based on the initial hardware/extension availability.
> However, when userspace subsequently disables ISA extensions via the KVM
> ONE_REG interface, the 'supported' field was not updated. This caused
> the following issues:
> 1. FWFT features would remain visible and accessible to guests even
>    after their prerequisite ISA extensions were disabled
> 2. Guests could configure FWFT features that depend on disabled
>    extensions, leading to undefined behavior
> 3. The static 'supported' flag and the dynamic supported() callback
>    could disagree about feature availability
>
> The fix introduces a two-layer checking mechanism:
> 1. Add an optional init() callback to the kvm_sbi_fwft_feature structure
>    for features that require hardware probing during initialization. This
>    separates the one-time hardware detection logic from the runtime
>    availability check.
> 2. Add runtime checks in all FWFT-related functions that call
>    feature->supported(vcpu) if the callback exists. This ensures feature
>    availability is re-evaluated based on the current ISA extension state.
>
> This approach maintains the cached 'supported' field for initialization-
> time decisions while ensuring runtime availability is always determined
> by the current vCPU configuration, not initialization-time snapshots.
>
> Fixes: 6b72fd170592 ("RISC-V: KVM: add support for FWFT SBI extension")
>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup

> ---
>  arch/riscv/kvm/vcpu_sbi_fwft.c | 10 ++++++++++
>  1 file changed, 10 insertions(+)
>
> diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
> index aee951f2b8e6..ab39ac464ffd 100644
> --- a/arch/riscv/kvm/vcpu_sbi_fwft.c
> +++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
> @@ -303,6 +303,8 @@ static int kvm_fwft_get_feature(struct kvm_vcpu *vcpu, u32 feature,
>
>         if (!tconf->supported || !tconf->enabled)
>                 return SBI_ERR_NOT_SUPPORTED;
> +       else if (tconf->feature->supported && !tconf->feature->supported(vcpu))
> +               return SBI_ERR_NOT_SUPPORTED;
>
>         *conf = tconf;
>
> @@ -433,6 +435,8 @@ static unsigned long kvm_sbi_ext_fwft_get_reg_count(struct kvm_vcpu *vcpu)
>                 conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
>                 if (!conf || !conf->supported)
>                         continue;
> +               else if (conf->feature->supported && !conf->feature->supported(vcpu))
> +                       continue;
>
>                 ret++;
>         }
> @@ -455,6 +459,8 @@ static int kvm_sbi_ext_fwft_get_reg_id(struct kvm_vcpu *vcpu, int index, u64 *re
>                 conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
>                 if (!conf || !conf->supported)
>                         continue;
> +               else if (conf->feature->supported && !conf->feature->supported(vcpu))
> +                       continue;
>
>                 if (index == idx) {
>                         *reg_id = KVM_REG_RISCV |
> @@ -490,6 +496,8 @@ static int kvm_sbi_ext_fwft_get_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
>         conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
>         if (!conf || !conf->supported)
>                 return -ENOENT;
> +       else if (conf->feature->supported && !conf->feature->supported(vcpu))
> +               return -ENOENT;
>
>         switch (reg_num - feature->first_reg_num) {
>         case 0:
> @@ -527,6 +535,8 @@ static int kvm_sbi_ext_fwft_set_reg(struct kvm_vcpu *vcpu, unsigned long reg_num
>         conf = kvm_sbi_fwft_get_config(vcpu, feature->id);
>         if (!conf || !conf->supported)
>                 return -ENOENT;
> +       else if (conf->feature->supported && !conf->feature->supported(vcpu))
> +               return -ENOENT;
>
>         switch (reg_num - feature->first_reg_num) {
>         case 0:
>
> --
> 2.43.7
>


From anup at brainfault.org  Fri Jun  5 09:13:28 2026
From: anup at brainfault.org (Anup Patel)
Date: Fri, 5 Jun 2026 21:43:28 +0530
Subject: [PATCH v5 4/5] KVM: riscv: selftests: Refactor ISA and SBI
 extension sublist macros
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-4-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com> <20260601-kvm-get_reg_list-v2-v5-4-415d08a2813b@sifive.com>
Message-ID: <CAAhSdy3ffD+ndNQFWeGZTQAwnQBhEB=fGKOJO4e0H2r66U7eEQ@mail.gmail.com>

On Mon, Jun 1, 2026 at 3:56?PM Yong-Xuan Wang <yongxuan.wang at sifive.com> wrote:
>
> Refactor the get-reg-list test to use unified sublist macros for ISA
> and SBI extensions, eliminating code duplication and improving
> maintainability.
>
> Previously, each extension had its own hand-coded sublist definition
> (e.g., SUBLIST_ZICBOM, SUBLIST_AIA, etc.) and the config structures
> repeated the same pattern. This made the code verbose and error-prone.
>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup

> ---
>  tools/testing/selftests/kvm/riscv/get-reg-list.c | 78 +++++++++---------------
>  1 file changed, 28 insertions(+), 50 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
> index 8d6fdb5d38b8..5033c09201ef 100644
> --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
> +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
> @@ -1013,7 +1013,7 @@ static __u64 fp_d_regs[] = {
>  };
>
>  /* Define a default vector registers with length. This will be overwritten at runtime */
> -static __u64 vector_regs[] = {
> +static __u64 v_regs[] = {
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vstart),
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vl),
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_VECTOR | KVM_REG_RISCV_VECTOR_CSR_REG(vtype),
> @@ -1057,37 +1057,17 @@ static __u64 vector_regs[] = {
>  #define SUBLIST_BASE \
>         {"base", .regs = base_regs, .regs_n = ARRAY_SIZE(base_regs), \
>          .skips_set = base_skips_set, .skips_set_n = ARRAY_SIZE(base_skips_set),}
> -#define SUBLIST_SBI_BASE \
> -       {"sbi-base", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_V01, \
> -        .regs = sbi_base_regs, .regs_n = ARRAY_SIZE(sbi_base_regs),}
> -#define SUBLIST_SBI_STA \
> -       {"sbi-sta", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_STA, \
> -        .regs = sbi_sta_regs, .regs_n = ARRAY_SIZE(sbi_sta_regs),}
> -#define SUBLIST_SBI_FWFT \
> -       {"sbi-fwft", .feature_type = VCPU_FEATURE_SBI_EXT, .feature = KVM_RISCV_SBI_EXT_FWFT, \
> -        .regs = sbi_fwft_regs, .regs_n = ARRAY_SIZE(sbi_fwft_regs),}
> -#define SUBLIST_ZICBOM \
> -       {"zicbom", .feature = KVM_RISCV_ISA_EXT_ZICBOM, .regs = zicbom_regs, .regs_n = ARRAY_SIZE(zicbom_regs),}
> -#define SUBLIST_ZICBOP \
> -       {"zicbop", .feature = KVM_RISCV_ISA_EXT_ZICBOP, .regs = zicbop_regs, .regs_n = ARRAY_SIZE(zicbop_regs),}
> -#define SUBLIST_ZICBOZ \
> -       {"zicboz", .feature = KVM_RISCV_ISA_EXT_ZICBOZ, .regs = zicboz_regs, .regs_n = ARRAY_SIZE(zicboz_regs),}
> -#define SUBLIST_AIA \
> -       {"aia", .feature = KVM_RISCV_ISA_EXT_SSAIA, .regs = aia_regs, .regs_n = ARRAY_SIZE(aia_regs),}
> -#define SUBLIST_SMSTATEEN \
> -       {"smstateen", .feature = KVM_RISCV_ISA_EXT_SMSTATEEN, .regs = smstateen_regs, .regs_n = ARRAY_SIZE(smstateen_regs),}
> -#define SUBLIST_FP_F \
> -       {"fp_f", .feature = KVM_RISCV_ISA_EXT_F, .regs = fp_f_regs, \
> -               .regs_n = ARRAY_SIZE(fp_f_regs),}
> -#define SUBLIST_FP_D \
> -       {"fp_d", .feature = KVM_RISCV_ISA_EXT_D, .regs = fp_d_regs, \
> -               .regs_n = ARRAY_SIZE(fp_d_regs),}
> -
> -#define SUBLIST_V \
> -       {"v", .feature = KVM_RISCV_ISA_EXT_V, .regs = vector_regs, .regs_n = ARRAY_SIZE(vector_regs),}
> +
> +#define SUBLIST_ISA(ext, extu)                         \
> +       {                                               \
> +               .name = #ext,                           \
> +               .feature = KVM_RISCV_ISA_EXT_##extu,    \
> +               .regs = ext##_regs,                     \
> +               .regs_n = ARRAY_SIZE(ext##_regs),       \
> +       }
>
>  #define KVM_ISA_EXT_SIMPLE_CONFIG(ext, extu)                   \
> -static __u64 regs_##ext[] = {                                  \
> +static __u64 ext##_regs[] = {                                  \
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG |                    \
>         KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE |      \
>         KVM_RISCV_ISA_EXT_##extu,                               \
> @@ -1095,18 +1075,22 @@ static __u64 regs_##ext[] = {                                   \
>  static struct vcpu_reg_list config_##ext = {                   \
>         .sublists = {                                           \
>                 SUBLIST_BASE,                                   \
> -               {                                               \
> -                       .name = #ext,                           \
> -                       .feature = KVM_RISCV_ISA_EXT_##extu,    \
> -                       .regs = regs_##ext,                     \
> -                       .regs_n = ARRAY_SIZE(regs_##ext),       \
> -               },                                              \
> +               SUBLIST_ISA(ext, extu),                         \
>                 {0},                                            \
>         },                                                      \
>  }                                                              \
>
> +#define SUBLIST_SBI(ext, extu)                                 \
> +       {                                                       \
> +               .name = "sbi-"#ext,                             \
> +               .feature_type = VCPU_FEATURE_SBI_EXT,           \
> +               .feature = KVM_RISCV_SBI_EXT_##extu,            \
> +               .regs = sbi_##ext##_regs,                       \
> +               .regs_n = ARRAY_SIZE(sbi_##ext##_regs),         \
> +       }
> +
>  #define KVM_SBI_EXT_SIMPLE_CONFIG(ext, extu)                   \
> -static __u64 regs_sbi_##ext[] = {                              \
> +static __u64 sbi_##ext##_regs[] = {                            \
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG |                    \
>         KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE |      \
>         KVM_RISCV_SBI_EXT_##extu,                               \
> @@ -1114,13 +1098,7 @@ static __u64 regs_sbi_##ext[] = {                                \
>  static struct vcpu_reg_list config_sbi_##ext = {               \
>         .sublists = {                                           \
>                 SUBLIST_BASE,                                   \
> -               {                                               \
> -                       .name = "sbi-"#ext,                     \
> -                       .feature_type = VCPU_FEATURE_SBI_EXT,   \
> -                       .feature = KVM_RISCV_SBI_EXT_##extu,    \
> -                       .regs = regs_sbi_##ext,                 \
> -                       .regs_n = ARRAY_SIZE(regs_sbi_##ext),   \
> -               },                                              \
> +               SUBLIST_SBI(ext, extu),                         \
>                 {0},                                            \
>         },                                                      \
>  }                                                              \
> @@ -1129,7 +1107,7 @@ static struct vcpu_reg_list config_sbi_##ext = {          \
>  static struct vcpu_reg_list config_##ext = {                   \
>         .sublists = {                                           \
>                 SUBLIST_BASE,                                   \
> -               SUBLIST_##extu,                                 \
> +               SUBLIST_ISA(ext, extu),                         \
>                 {0},                                            \
>         },                                                      \
>  }                                                              \
> @@ -1138,14 +1116,14 @@ static struct vcpu_reg_list config_##ext = {                    \
>  static struct vcpu_reg_list config_sbi_##ext = {               \
>         .sublists = {                                           \
>                 SUBLIST_BASE,                                   \
> -               SUBLIST_SBI_##extu,                             \
> +               SUBLIST_SBI(ext, extu),                         \
>                 {0},                                            \
>         },                                                      \
>  }                                                              \
>
>  /* Note: The below list is alphabetically sorted. */
>
> -KVM_SBI_EXT_SUBLIST_CONFIG(base, BASE);
> +KVM_SBI_EXT_SUBLIST_CONFIG(base, V01);
>  KVM_SBI_EXT_SUBLIST_CONFIG(sta, STA);
>  KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
>  KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
> @@ -1153,9 +1131,9 @@ KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP);
>  KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY);
>  KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT);
>
> -KVM_ISA_EXT_SUBLIST_CONFIG(aia, AIA);
> -KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, FP_F);
> -KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, FP_D);
> +KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA);
> +KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F);
> +KVM_ISA_EXT_SUBLIST_CONFIG(fp_d, D);
>  KVM_ISA_EXT_SUBLIST_CONFIG(v, V);
>  KVM_ISA_EXT_SIMPLE_CONFIG(h, H);
>  KVM_ISA_EXT_SIMPLE_CONFIG(smnpm, SMNPM);
>
> --
> 2.43.7
>


From anup at brainfault.org  Fri Jun  5 09:14:08 2026
From: anup at brainfault.org (Anup Patel)
Date: Fri, 5 Jun 2026 21:44:08 +0530
Subject: [PATCH v5 5/5] KVM: riscv: selftests: Split SBI FWFT into
 separate feature-specific sublists
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-5-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com> <20260601-kvm-get_reg_list-v2-v5-5-415d08a2813b@sifive.com>
Message-ID: <CAAhSdy2oeV=XjQp8YQ9iMwHVQ8B3HDmmUbhmbbYjRLvbp6daow@mail.gmail.com>

On Mon, Jun 1, 2026 at 3:56?PM Yong-Xuan Wang <yongxuan.wang at sifive.com> wrote:
>
> Divide the monolithic SBI FWFT (Firmware Features) register list into
> separate sublists, each testing a specific FWFT feature independently
> with proper dependency checking.
>
> Previously, all FWFT features were tested together in a single sublist.
> This caused issues because:
> 1. Not all FWFT features are available on all platforms
> 2. Some features depend on specific ISA extensions (e.g., pointer_masking
> requires Smnpm)
> 3. Tests would fail if any single feature was unavailable
>
> Add the feature-specific SBI FWFT sublists with the following
> improvements:
> - Add check_fwft_feature() helper to verify FWFT feature availability
>   at runtime
> - Update filter_reg() to handle per-feature FWFT register filtering
>
> Signed-off-by: Yong-Xuan Wang <yongxuan.wang at sifive.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Thanks,
Anup

> ---
>  tools/testing/selftests/kvm/riscv/get-reg-list.c | 60 ++++++++++++++++++++++--
>  1 file changed, 57 insertions(+), 3 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
> index 5033c09201ef..cb86cb6b3635 100644
> --- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
> +++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
> @@ -27,6 +27,7 @@ enum {
>  };
>
>  static bool isa_ext_cant_disable[KVM_RISCV_ISA_EXT_MAX];
> +static bool sbi_ext_enabled[KVM_RISCV_SBI_EXT_MAX];
>
>  bool filter_reg(__u64 reg)
>  {
> @@ -149,6 +150,14 @@ bool filter_reg(__u64 reg)
>         case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1h):
>         case KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio2h):
>                 return isa_ext_cant_disable[KVM_RISCV_ISA_EXT_SSAIA];
> +       /*
> +        * FWFT misaligned delegation registers are always visible when the SBI FWFT
> +        * extension is enable and the host supports the misaligned delegation.
> +        */
> +       case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable):
> +       case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags):
> +       case KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value):
> +               return sbi_ext_enabled[KVM_RISCV_SBI_EXT_FWFT];
>         default:
>                 break;
>         }
> @@ -193,6 +202,27 @@ static int override_vector_reg_size(struct kvm_vcpu *vcpu, struct vcpu_reg_subli
>         return 0;
>  }
>
> +void check_fwft_feature(struct kvm_vcpu *vcpu, struct vcpu_reg_sublist *s, u64 feature)
> +{
> +       unsigned long value;
> +       int rc;
> +
> +       /* Enable SBI FWFT extension so that we can check the supported register */
> +       rc = __vcpu_set_reg(vcpu, feature, 1);
> +       if (rc)
> +               return;
> +
> +       for (int i = 0; i < s->regs_n; i++) {
> +               if ((s->regs[i] & KVM_REG_RISCV_TYPE_MASK) == KVM_REG_RISCV_SBI_STATE) {
> +                       rc = __vcpu_get_reg(vcpu, s->regs[i], &value);
> +                       __TEST_REQUIRE(!rc, "%s not available, skipping tests", s->name);
> +               }
> +       }
> +
> +       /* We should assert if disabling failed here while enabling succeeded before */
> +       vcpu_set_reg(vcpu, feature, 0);
> +}
> +
>  void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
>  {
>         unsigned long isa_ext_state[KVM_RISCV_ISA_EXT_MAX] = { 0 };
> @@ -235,6 +265,9 @@ void finalize_vcpu(struct kvm_vcpu *vcpu, struct vcpu_reg_list *c)
>                         break;
>                 case VCPU_FEATURE_SBI_EXT:
>                         feature = RISCV_SBI_EXT_REG(s->feature);
> +                       if (s->feature == KVM_RISCV_SBI_EXT_FWFT)
> +                               check_fwft_feature(vcpu, s, feature);
> +                       sbi_ext_enabled[s->feature] = true;
>                         break;
>                 default:
>                         TEST_FAIL("Unknown feature type");
> @@ -897,11 +930,15 @@ static __u64 sbi_sta_regs[] = {
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_STA | KVM_REG_RISCV_SBI_STA_REG(shmem_hi),
>  };
>
> -static __u64 sbi_fwft_regs[] = {
> +static __u64 sbi_fwft_misaligned_deleg_regs[] = {
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.enable),
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.flags),
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(misaligned_deleg.value),
> +};
> +
> +static __u64 sbi_fwft_pointer_masking_regs[] = {
> +       KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable),
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags),
>         KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value),
> @@ -1129,7 +1166,6 @@ KVM_SBI_EXT_SIMPLE_CONFIG(pmu, PMU);
>  KVM_SBI_EXT_SIMPLE_CONFIG(dbcn, DBCN);
>  KVM_SBI_EXT_SIMPLE_CONFIG(susp, SUSP);
>  KVM_SBI_EXT_SIMPLE_CONFIG(mpxy, MPXY);
> -KVM_SBI_EXT_SUBLIST_CONFIG(fwft, FWFT);
>
>  KVM_ISA_EXT_SUBLIST_CONFIG(aia, SSAIA);
>  KVM_ISA_EXT_SUBLIST_CONFIG(fp_f, F);
> @@ -1206,6 +1242,23 @@ KVM_ISA_EXT_SIMPLE_CONFIG(zvksed, ZVKSED);
>  KVM_ISA_EXT_SIMPLE_CONFIG(zvksh, ZVKSH);
>  KVM_ISA_EXT_SIMPLE_CONFIG(zvkt, ZVKT);
>
> +static struct vcpu_reg_list config_sbi_fwft_misaligned_deleg = {
> +       .sublists = {
> +               SUBLIST_BASE,
> +               SUBLIST_SBI(fwft_misaligned_deleg, FWFT),
> +               {0},
> +       },
> +};
> +
> +static struct vcpu_reg_list config_sbi_fwft_pointer_masking = {
> +       .sublists = {
> +               SUBLIST_BASE,
> +               SUBLIST_ISA(smnpm, SMNPM),
> +               SUBLIST_SBI(fwft_pointer_masking, FWFT),
> +               {0},
> +       },
> +};
> +
>  struct vcpu_reg_list *vcpu_configs[] = {
>         &config_sbi_base,
>         &config_sbi_sta,
> @@ -1213,7 +1266,8 @@ struct vcpu_reg_list *vcpu_configs[] = {
>         &config_sbi_dbcn,
>         &config_sbi_susp,
>         &config_sbi_mpxy,
> -       &config_sbi_fwft,
> +       &config_sbi_fwft_misaligned_deleg,
> +       &config_sbi_fwft_pointer_masking,
>         &config_aia,
>         &config_fp_f,
>         &config_fp_d,
>
> --
> 2.43.7
>


From anup at brainfault.org  Fri Jun  5 09:16:45 2026
From: anup at brainfault.org (Anup Patel)
Date: Fri, 5 Jun 2026 21:46:45 +0530
Subject: [PATCH v5 0/5] KVM: riscv: Fix stale FWFT feature exposure and
 enhance selftests
In-Reply-To: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
References: <20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b@sifive.com>
Message-ID: <CAAhSdy1bMSadxaoKvSy6fdfb9pLufg=39-sHOHnr7Vj0Y-4Z2w@mail.gmail.com>

On Mon, Jun 1, 2026 at 3:56?PM Yong-Xuan Wang <yongxuan.wang at sifive.com> wrote:
>
> This series fixes three bugs in the SBI FWFT (Firmware Features) extension
> and improves the related selftest infrastructure.
> The bugs are:
> 1. Missing CSR dirty marking: When userspace sets FWFT feature values via
>    KVM_SET_ONE_REG, modified CSRs (e.g., henvcfg.PMM for pointer masking)
>    are not marked dirty, leading to stale state after vCPU scheduling or
>    migration.
> 2. Hardware probing side effects: The try_to_set_pmm() function modifies
>    HENVCFG.PMM during hardware capability detection but fails to restore
>    the original value, leaving the CSR in an altered state that affects
>    subsequent operations.
> 3. Stale feature exposure: FWFT feature support is cached at vCPU
>    initialization time. When userspace subsequently disables ISA extensions
>    via KVM_SET_ONE_REG, the cached support status is not updated, allowing
>    guests to access features that depend on disabled extensions.
> Patches 1-3 fix these bugs separately.
>
> The selftest improvements (patches 4-5) enhance the get-reg-list test by
> refactoring the extension sublist infrastructure and splitting FWFT
> feature testing into separate, properly-gated sublists.
>
> ---
> Changes in v5:
> - Add CSR dirty marking fix (new patch 1/5) (sashiko-bot)
> - Split original FWFT bug fix into two focused patches
>   - Add init() callback with try_to_set_pmm() restoration fix (new patch
>     2/5) (sashiko-bot)
>   - Keep runtime supported() checks as separate patch (patch 3/5)
> - Link to v4: https://patch.msgid.link/20260601-kvm-get_reg_list-v2-v4-0-c88abc81ebda at sifive.com
>
> Changes in v4:
> - Rename the title of cover letter
> - Disable preemption when running try_to_set_pmm() (sashiko-bot)
> - Remove check_supported_reg() (sashiko-bot)
> - Link to v3: https://patch.msgid.link/20260528-kvm-get_reg_list-v2-v3-0-170969a8599f at sifive.com
>
> Changes in v3:
> - Restore 'supported' field with init() callback for initialization probing
>   (sashiko-bot)
> - Add NULL checks before calling feature->supported() in all functions
> - Fix isa_ext_enabled tracking logic and restore isa_ext_cant_disable array
> - Add sbi_ext_enabled tracking and enhance dependency checking (sashiko-bot)
> - Refine code organization and variable naming consistency (sashiko-bot)
> - Link to v2: https://patch.msgid.link/20260526-kvm-get_reg_list-v2-v2-0-7940a401454a at sifive.com
>
> Changes in v2:
> - Fix FWFT stale feature exposure by removing static 'supported' field
> - Refactor get-reg-list test to use unified extension sublist macros
> - Split FWFT testing into per-feature sublists with runtime checks
>   (Andrew)
>
> To: Anup Patel <anup at brainfault.org>
> To: Atish Patra <atish.patra at linux.dev>
> To: Paul Walmsley <pjw at kernel.org>
> To: Palmer Dabbelt <palmer at dabbelt.com>
> To: Albert Ou <aou at eecs.berkeley.edu>
> To: Alexandre Ghiti <alex at ghiti.fr>
> To: Cl?ment L?ger <cleger at rivosinc.com>
> To: Andrew Jones <ajones at ventanamicro.com>
> To: Paolo Bonzini <pbonzini at redhat.com>
> To: Shuah Khan <shuah at kernel.org>
> Cc: greentime.hu at sifive.com
> Cc: vincent.chen at sifive.com
> Cc: zong.li at sifive.com
> Cc: kvm at vger.kernel.org
> Cc: kvm-riscv at lists.infradead.org
> Cc: linux-riscv at lists.infradead.org
> Cc: linux-kernel at vger.kernel.org
> Cc: linux-kselftest at vger.kernel.org
>
> ---
> Yong-Xuan Wang (5):
>       KVM: RISC-V: SBI FWFT: Mark vCPU CSRs dirty after setting feature value
>       KVM: RISC-V: SBI FWFT: Add optional init() callback for hardware probing
>       KVM: RISC-V: SBI FWFT: Fix stale feature exposure after runtime extension changes
>       KVM: riscv: selftests: Refactor ISA and SBI extension sublist macros
>       KVM: riscv: selftests: Split SBI FWFT into separate feature-specific sublists

Queued this series for Linux-7.2

Regards,
Anup


From fustini at kernel.org  Fri Jun  5 09:57:43 2026
From: fustini at kernel.org (Drew Fustini)
Date: Fri, 5 Jun 2026 09:57:43 -0700
Subject: [PATCH] riscv: defconfig: thead: enable PCA953X GPIO driver
In-Reply-To: <7ffb4a7c-ea74-431a-8be9-1a1d7418b467@kernel.org>
References: <CGME20260603082156eucas1p1f44a198f7957d9d82ec0b8bc296fb03c@eucas1p1.samsung.com>
 <20260603082132.3200787-1-m.szyprowski@samsung.com>
 <7ffb4a7c-ea74-431a-8be9-1a1d7418b467@kernel.org>
Message-ID: <aiMAB0RjnjEzDQKu@x1>

On Fri, Jun 05, 2026 at 02:50:54PM +1000, Michael Ellerman wrote:
> On 3/6/26 6:21 pm, Marek Szyprowski wrote:
> > Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
> > LicheePi4a board.
> > 
> > Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> > ---
> >   arch/riscv/configs/defconfig | 2 ++
> >   1 file changed, 2 insertions(+)
> > 
> > diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
> > index 08445df56006..a51a423d53f4 100644
> > --- a/arch/riscv/configs/defconfig
> > +++ b/arch/riscv/configs/defconfig
> > @@ -174,6 +174,8 @@ CONFIG_PINCTRL_SOPHGO_SG2002=y
> >   CONFIG_GPIO_DWAPB=y
> >   CONFIG_GPIO_SIFIVE=y
> >   CONFIG_GPIO_SPACEMIT_K1=y
> > +CONFIG_GPIO_PCA953X=y
> > +CONFIG_GPIO_PCA953X_IRQ=y
> Does it need to be built-in, or would a module work?
> 
> It's not a huge driver (~20KB), but it all adds up.

Good point.

Marek - could you respin as module?

thanks,
drew


From lukas.schmid at netcube.li  Fri Jun  5 12:13:12 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Fri,  5 Jun 2026 21:13:12 +0200
Subject: [PATCH v2 0/3] Add support for NetCube Systems OpenNMC (dobermann)
Message-ID: <20260605191322.1920944-1-lukas.schmid@netcube.li>

This series adds support for the NetCube Systems OpenNMC

Changes in v2:
 - fixed ordering of compatible enum
 - fixed gpio line names

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
Lukas Schmid (3):
  dt-bindings: arm: sunxi: Add NetCube Systems OpenNMC (dobermann)
  riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube
    Systems OpenNMC
  ARM: dts: sunxi: add support for NetCube Systems OpenNMC (dobermann)

 .../devicetree/bindings/arm/sunxi.yaml        |   1 +
 .../sun8i-t113s-netcube-dobermann.dts         | 149 ++++++++++++++++++
 .../boot/dts/allwinner/sunxi-d1s-t113.dtsi    |   6 +
 3 files changed, 156 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts

-- 
2.47.3




From lukas.schmid at netcube.li  Fri Jun  5 12:13:14 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Fri,  5 Jun 2026 21:13:14 +0200
Subject: [PATCH v2 2/3] riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube Systems OpenNMC
In-Reply-To: <20260605191322.1920944-1-lukas.schmid@netcube.li>
References: <20260605191322.1920944-1-lukas.schmid@netcube.li>
Message-ID: <20260605191322.1920944-3-lukas.schmid@netcube.li>

Added the "uart4_pb_pins" pinctrl used by the OpenNMC

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
index 82cc85acccb1..00fddedfa36f 100644
--- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
+++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
@@ -191,6 +191,12 @@ uart3_pb_pins: uart3-pb-pins {
 				pins = "PB6", "PB7";
 				function = "uart3";
 			};
+
+			/omit-if-no-ref/
+			uart4_pb_pins: uart4-pb-pins {
+				pins = "PB2", "PB3";
+				function = "uart4";
+			};
 		};
 
 		ccu: clock-controller at 2001000 {
-- 
2.47.3




From lukas.schmid at netcube.li  Fri Jun  5 12:13:15 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Fri,  5 Jun 2026 21:13:15 +0200
Subject: [PATCH v2 3/3] ARM: dts: sunxi: add support for NetCube Systems OpenNMC (dobermann)
In-Reply-To: <20260605191322.1920944-1-lukas.schmid@netcube.li>
References: <20260605191322.1920944-1-lukas.schmid@netcube.li>
Message-ID: <20260605191322.1920944-4-lukas.schmid@netcube.li>

NetCube Systems OpenNMC is an open replacement for APC SmartSlot Management
Cards. It is based on the Nagami System-on-Module. It breaks out the
following interfaces:

- 10/100 Mbps Ethernet
- USB Type-C OTG using a TUSB320 (usb0)
- USB Type-C Console Port using a CH340 (uart3)
- USB Type-A Host with internal CH334 USB-Hub (usb1)
- MicroSD Slot with Card-Detect (mmc0)
- WiFi/Bluetooth using the modules built-in ESP32
- SmartSlot serial interface (uart4)
- DS3232 RTC with CR1220 Battery Backup
- Extension connector providing SPI,I2C,USB,CAN,UART for future use.

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 .../sun8i-t113s-netcube-dobermann.dts         | 149 ++++++++++++++++++
 1 file changed, 149 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts

diff --git a/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts b/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
new file mode 100644
index 000000000000..d7765caffe2a
--- /dev/null
+++ b/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2026 Lukas Schmid <lukas.schmid at netcube.li>
+ */
+
+/dts-v1/;
+#include "sun8i-t113s-netcube-nagami.dtsi"
+
+#include <dt-bindings/leds/common.h>
+
+/ {
+	model = "NetCube Systems OpenNMC (dobermann)";
+	compatible = "netcube,dobermann", "netcube,nagami",
+		     "allwinner,sun8i-t113s";
+
+	aliases {
+		serial2 = &uart4; // UART on SmartSlot
+		rtc0 = &ds3232;
+		rtc1 = &rtc; // not battery backed
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led_heartbeat_green: led-heartbeat-green {
+			gpios = <&pio 6 14 GPIO_ACTIVE_HIGH>; /* PG14 */
+			linux,default-trigger = "heartbeat";
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_HEARTBEAT;
+		};
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+
+	tusb320: typec at 60 {
+		compatible = "ti,tusb320";
+		reg = <0x60>;
+		interrupts-extended = <&pio 3 22 IRQ_TYPE_LEVEL_LOW>;  /* PD22 */
+	};
+
+	ds3232: rtc at 68 {
+		compatible = "dallas,ds3232";
+		reg = <0x68>;
+	};
+};
+
+/* microSD Card Slot on the board */
+&mmc0 {
+	vmmc-supply = <&reg_vcc3v3>;
+	disable-wp;
+	bus-width = <4>;
+	cd-gpios = <&pio 6 15 GPIO_ACTIVE_LOW>; /* PG15 */
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&pio {
+	gpio-line-names = "", "", "", "", // PA
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "SMART_TX", "SMART_RX", // PB
+			  "EXT_IO3", "EXT_IO2", "CONSOLE_TX", "CONSOLE_RX",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "eMMC_CLK", "eMMC_CMD", // PC
+			  "eMMC_D2", "eMMC_D1", "eMMC_D0", "eMMC_D3",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "", // PD
+			  "", "", "", "",
+			  "", "USB_SEC_EN", "EXT_SPI_nCS", "EXT_SPI_SCK",
+			  "EXT_SPI_MOSI", "EXT_SPI_MISO", "EXT_IO5", "EXT_IO4",
+			  "SMART_SEL", "", "", "",
+			  "I2C2_SCL", "I2C2_SDA", "TUSB320_nINT", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "ETH_CRSDV", "ETH_RXD0", "ETH_RXD1", "ETH_TXCK", // PE
+			  "ETH_TXD0", "ETH_TXD1", "ETH_TXEN", "",
+			  "ETH_MDC", "ETH_MDIO", "I2C3_nINT", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "uSD_D1", "uSD_D0", "uSD_CLK", "uSD_CMD", // PF
+			  "uSD_D3", "uSD_D2", "TUSB320_ID", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "ESP_CLK", "ESP_CMD", "ESP_D0", "ESP_D1", // PG
+			  "ESP_D2", "ESP_D3", "ESP_TXD", "ESP_RXD",
+			  "ESP_nBOOT", "ESP_nRST", "I2C3_SCL", "I2C3_SDA",
+			  "EXT_IO1", "EXT_IO0", "LED_HEARTBEAT", "SD_DETECT",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "";
+};
+
+/* SmartSlot serial */
+&uart4 {
+	pinctrl-0 = <&uart4_pb_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usb_otg {
+	extcon = <&tusb320 0>;
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usbphy {
+	usb0_id_det-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	status = "okay";
+};
-- 
2.47.3




From lukas.schmid at netcube.li  Fri Jun  5 12:13:13 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Fri,  5 Jun 2026 21:13:13 +0200
Subject: [PATCH v2 1/3] dt-bindings: arm: sunxi: Add NetCube Systems OpenNMC (dobermann)
In-Reply-To: <20260605191322.1920944-1-lukas.schmid@netcube.li>
References: <20260605191322.1920944-1-lukas.schmid@netcube.li>
Message-ID: <20260605191322.1920944-2-lukas.schmid@netcube.li>

The OpenNMC is an open replacement for APC SmartSlot management cards
based on the Nagami System-on-Module.

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 Documentation/devicetree/bindings/arm/sunxi.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
index e6443c266fa1..077b65507645 100644
--- a/Documentation/devicetree/bindings/arm/sunxi.yaml
+++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
@@ -598,6 +598,7 @@ properties:
       - description: NetCube Systems Nagami SoM based boards
         items:
           - enum:
+              - netcube,dobermann
               - netcube,nagami-basic-carrier
               - netcube,nagami-keypad-carrier
           - const: netcube,nagami
-- 
2.47.3




From fustini at kernel.org  Fri Jun  5 12:54:11 2026
From: fustini at kernel.org (Drew Fustini)
Date: Fri, 5 Jun 2026 12:54:11 -0700
Subject: [PATCH v2 1/7] dt-bindings: aplic: Add Tenstorrent Atlantis
 compatible
In-Reply-To: <20260604143957.668047-2-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-2-joel@jms.id.au>
Message-ID: <aiMpY6tjGhv/cRWI@x1>

On Fri, Jun 05, 2026 at 12:09:47AM +0930, Joel Stanley wrote:
> Add compatible for APLIC in Tenstorrent Atlantis SoC.
> 
> Reviewed-by: Anup Patel <anup at brainfault.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>

Reviewed-by: Drew Fustini <fustini at kernel.org>


From fustini at kernel.org  Fri Jun  5 12:54:25 2026
From: fustini at kernel.org (Drew Fustini)
Date: Fri, 5 Jun 2026 12:54:25 -0700
Subject: [PATCH v2 2/7] dt-bindings: imsics: Add Tenstorrent Atlantis
 compatible
In-Reply-To: <20260604143957.668047-3-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-3-joel@jms.id.au>
Message-ID: <aiMpcbgFRHHY/Cy+@x1>

On Fri, Jun 05, 2026 at 12:09:48AM +0930, Joel Stanley wrote:
> Add compatible for IMSICS in Tenstorrent Atlantis SoC.
> 
> Reviewed-by: Anup Patel <anup at brainfault.org>
> Signed-off-by: Joel Stanley <joel at jms.id.au>

Reviewed-by: Drew Fustini <fustini at kernel.org>


From fustini at kernel.org  Fri Jun  5 12:55:29 2026
From: fustini at kernel.org (Drew Fustini)
Date: Fri, 5 Jun 2026 12:55:29 -0700
Subject: [PATCH v2 6/7] dt-bindings: riscv: Add Tenstorrent Atlantis
 platform
In-Reply-To: <20260604143957.668047-7-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-7-joel@jms.id.au>
Message-ID: <aiMpsQDN0IGjjwgj@x1>

On Fri, Jun 05, 2026 at 12:09:52AM +0930, Joel Stanley wrote:
> Add compatible for the Tenstorrent Atlantis platform.
> 
> Signed-off-by: Joel Stanley <joel at jms.id.au>

Reviewed-by: Drew Fustini <fustini at kernel.org>


From fustini at kernel.org  Fri Jun  5 12:56:20 2026
From: fustini at kernel.org (Drew Fustini)
Date: Fri, 5 Jun 2026 12:56:20 -0700
Subject: [PATCH v2 3/7] dt-bindings: riscv: cpus: Add Tenstorrent Ascalon
In-Reply-To: <20260604143957.668047-4-joel@jms.id.au>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-4-joel@jms.id.au>
Message-ID: <aiMp5Lcy4Y2m6sJA@x1>

On Fri, Jun 05, 2026 at 12:09:49AM +0930, Joel Stanley wrote:
> Add Tenstorrent Ascalon microarchitecture and the Tenstorrent Ascalon-XG
> core.
> 
> Signed-off-by: Joel Stanley <joel at jms.id.au>

Reviewed-by: Drew Fustini <fustini at kernel.org>


From robh at kernel.org  Fri Jun  5 13:31:06 2026
From: robh at kernel.org (Rob Herring)
Date: Fri, 5 Jun 2026 15:31:06 -0500
Subject: [PATCH v2 7/7] riscv: dts: tenstorrent: Add Atlantis platform
In-Reply-To: <f3fd53dc-7010-4b3d-a33c-4d1d32d3a1a6@kernel.org>
References: <20260604143957.668047-1-joel@jms.id.au>
 <20260604143957.668047-8-joel@jms.id.au>
 <20260604-pacifier-sludge-196f47ab3c11@spud>
 <f3fd53dc-7010-4b3d-a33c-4d1d32d3a1a6@kernel.org>
Message-ID: <20260605203106.GA98957-robh@kernel.org>

On Sat, Jun 06, 2026 at 12:02:41AM +1000, Michael Ellerman wrote:
> On 5/6/26 2:47 am, Conor Dooley wrote:
> > On Fri, Jun 05, 2026 at 12:09:53AM +0930, Joel Stanley wrote:
> > > Add initial support for the Tenstorrent Atlantis platform, based on the
> > > Atlantis SoC featuring 8x RVA23-compliant Tenstorrent Ascalon-XG cores.
> > > 
> > > The evb machine represents an internal bringup vehicle with just the
> > > interrupt controllers and a UART. This will be replaced in time with a
> > > full featured machine once details are available.
> ...
> > > diff --git a/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
> > > new file mode 100644
> > > index 000000000000..06259cca8357
> > > --- /dev/null
> > > +++ b/arch/riscv/boot/dts/tenstorrent/atlantis-evb.dts
> > > @@ -0,0 +1,33 @@
> > > +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> > > +/dts-v1/;
> > > +
> > > +#include "atlantis-soc.dtsi"
> > > +
> > > +/ {
> > > +	model = "Tenstorrent Atlantis development platform";
> > > +	compatible = "tenstorrent,atlantis-evb", "tenstorrent,atlantis";
> > > +
> > > +	#address-cells = <2>;
> > > +	#size-cells = <2>;
> > > +
> > > +	memory at 0 {
> > > +		device_type = "memory";
> > > +		reg = <0x0 0x00000000 0x0 0x80000000>,
> > > +		      <0x1 0x80000000 0x0 0x80000000>;
> > > +	};
> > > +
> > > +	aliases {
> > > +		serial0 = &uart1;
> > > +	};
> > > +
> > > +	chosen {
> > > +		bootargs = "earlycon console=ttyS0";
> > 
> > FYI, this should not be in here.
> 
> It should be there if you want a working console :)
> 
> I know it's a "rule" to not include bootargs, but this system has no boot
> loader, so not setting bootargs just means the DTS is no use to anyone.

'console' is redundant as 'stdout-path' is set.

'earlycon' is only needed if you don't boot to the regular UART console. 
I would hope by default this system boots all the way.

> 
> > > +		stdout-path = "serial0";


Rob


From patchwork-bot+netdevbpf at kernel.org  Fri Jun  5 15:30:21 2026
From: patchwork-bot+netdevbpf at kernel.org (patchwork-bot+netdevbpf at kernel.org)
Date: Fri, 05 Jun 2026 22:30:21 +0000
Subject: [PATCH bpf-next 0/2] RISC-V JIT support for
 bpf_get_current_task/_btf
In-Reply-To: <20260602205847.102825-1-varunrmallya@gmail.com>
References: <20260602205847.102825-1-varunrmallya@gmail.com>
Message-ID: <178069862138.3943503.16397384527889534334.git-patchwork-notify@kernel.org>

Hello:

This series was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast at kernel.org>:

On Wed,  3 Jun 2026 02:28:45 +0530 you wrote:
> These two patches add support for the bpf_get_current_task and
> bpf_get_current_task_btf kfuncs in RISC-V JIT and add a selftest.
> 
> The first patch adds support for cpu and feature detection on
> the JIT disassembly helper function as RISC-V JITed code was not
> being disassembled using `LLVMCreateDisasm` as it was missing the
> "+c" CPU feature and JITed code contained RISC-V Compressed (C)
> Extension. This patch generalizes that to detect CPU features and
> enables testing on more RISC-V JIT work ahead.
> 
> [...]

Here is the summary with links:
  - [bpf-next,1/2] selftests/bpf: use host CPU features in JIT disassembler
    https://git.kernel.org/bpf/bpf-next/c/557d0cc3f252
  - [bpf-next,2/2] bpf, riscv: inline bpf_get_current_task() and bpf_get_current_task_btf()
    https://git.kernel.org/bpf/bpf-next/c/6d13ddb1d465

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From lukas.schmid at netcube.li  Sat Jun  6 12:16:41 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Sat,  6 Jun 2026 21:16:41 +0200
Subject: [PATCH v3 3/3] ARM: dts: sunxi: add support for NetCube Systems OpenNMC (dobermann)
In-Reply-To: <20260606191649.2347704-1-lukas.schmid@netcube.li>
References: <20260606191649.2347704-1-lukas.schmid@netcube.li>
Message-ID: <20260606191649.2347704-4-lukas.schmid@netcube.li>

NetCube Systems OpenNMC is an open replacement for APC SmartSlot Management
Cards. It is based on the Nagami System-on-Module. It breaks out the
following interfaces:

- 10/100 Mbps Ethernet
- USB Type-C OTG using a TUSB320 (usb0)
- USB Type-C Console Port using a CH340 (uart3)
- USB Type-A Host with internal CH334 USB-Hub (usb1)
- MicroSD Slot with Card-Detect (mmc0)
- WiFi/Bluetooth using the modules built-in ESP32
- SmartSlot serial interface (uart4)
- DS3232 RTC with CR1220 Battery Backup
- Extension connector providing SPI,I2C,USB,CAN,UART for future use.

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 arch/arm/boot/dts/allwinner/Makefile          |   2 +
 .../sun8i-t113s-netcube-dobermann.dts         | 149 ++++++++++++++++++
 2 files changed, 151 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts

diff --git a/arch/arm/boot/dts/allwinner/Makefile b/arch/arm/boot/dts/allwinner/Makefile
index f71392a55df8..220a20734dc2 100644
--- a/arch/arm/boot/dts/allwinner/Makefile
+++ b/arch/arm/boot/dts/allwinner/Makefile
@@ -201,6 +201,7 @@ DTC_FLAGS_sun8i-h3-orangepi-pc := -@
 DTC_FLAGS_sun8i-h3-bananapi-m2-plus-v1.2 := -@
 DTC_FLAGS_sun8i-h3-orangepi-pc-plus := -@
 DTC_FLAGS_sun8i-t113s-netcube-nagami-basic-carrier := -@
+DTC_FLAGS_sun8i-t113s-netcube-dobermann := -@
 DTC_FLAGS_sun8i-v3s-netcube-kumquat := -@
 dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-a23-evb.dtb \
@@ -261,6 +262,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-s3-lichee-zero-plus.dtb \
 	sun8i-s3-pinecube.dtb \
 	sun8i-t113s-mangopi-mq-r-t113.dtb \
+	sun8i-t113s-netcube-dobermann.dts \
 	sun8i-t113s-netcube-nagami-basic-carrier.dtb \
 	sun8i-t113s-netcube-nagami-keypad-carrier.dtb \
 	sun8i-t3-cqa3t-bv3.dtb \
diff --git a/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts b/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
new file mode 100644
index 000000000000..d7765caffe2a
--- /dev/null
+++ b/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2026 Lukas Schmid <lukas.schmid at netcube.li>
+ */
+
+/dts-v1/;
+#include "sun8i-t113s-netcube-nagami.dtsi"
+
+#include <dt-bindings/leds/common.h>
+
+/ {
+	model = "NetCube Systems OpenNMC (dobermann)";
+	compatible = "netcube,dobermann", "netcube,nagami",
+		     "allwinner,sun8i-t113s";
+
+	aliases {
+		serial2 = &uart4; // UART on SmartSlot
+		rtc0 = &ds3232;
+		rtc1 = &rtc; // not battery backed
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led_heartbeat_green: led-heartbeat-green {
+			gpios = <&pio 6 14 GPIO_ACTIVE_HIGH>; /* PG14 */
+			linux,default-trigger = "heartbeat";
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_HEARTBEAT;
+		};
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+
+	tusb320: typec at 60 {
+		compatible = "ti,tusb320";
+		reg = <0x60>;
+		interrupts-extended = <&pio 3 22 IRQ_TYPE_LEVEL_LOW>;  /* PD22 */
+	};
+
+	ds3232: rtc at 68 {
+		compatible = "dallas,ds3232";
+		reg = <0x68>;
+	};
+};
+
+/* microSD Card Slot on the board */
+&mmc0 {
+	vmmc-supply = <&reg_vcc3v3>;
+	disable-wp;
+	bus-width = <4>;
+	cd-gpios = <&pio 6 15 GPIO_ACTIVE_LOW>; /* PG15 */
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&pio {
+	gpio-line-names = "", "", "", "", // PA
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "SMART_TX", "SMART_RX", // PB
+			  "EXT_IO3", "EXT_IO2", "CONSOLE_TX", "CONSOLE_RX",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "eMMC_CLK", "eMMC_CMD", // PC
+			  "eMMC_D2", "eMMC_D1", "eMMC_D0", "eMMC_D3",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "", // PD
+			  "", "", "", "",
+			  "", "USB_SEC_EN", "EXT_SPI_nCS", "EXT_SPI_SCK",
+			  "EXT_SPI_MOSI", "EXT_SPI_MISO", "EXT_IO5", "EXT_IO4",
+			  "SMART_SEL", "", "", "",
+			  "I2C2_SCL", "I2C2_SDA", "TUSB320_nINT", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "ETH_CRSDV", "ETH_RXD0", "ETH_RXD1", "ETH_TXCK", // PE
+			  "ETH_TXD0", "ETH_TXD1", "ETH_TXEN", "",
+			  "ETH_MDC", "ETH_MDIO", "I2C3_nINT", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "uSD_D1", "uSD_D0", "uSD_CLK", "uSD_CMD", // PF
+			  "uSD_D3", "uSD_D2", "TUSB320_ID", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "ESP_CLK", "ESP_CMD", "ESP_D0", "ESP_D1", // PG
+			  "ESP_D2", "ESP_D3", "ESP_TXD", "ESP_RXD",
+			  "ESP_nBOOT", "ESP_nRST", "I2C3_SCL", "I2C3_SDA",
+			  "EXT_IO1", "EXT_IO0", "LED_HEARTBEAT", "SD_DETECT",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "";
+};
+
+/* SmartSlot serial */
+&uart4 {
+	pinctrl-0 = <&uart4_pb_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usb_otg {
+	extcon = <&tusb320 0>;
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usbphy {
+	usb0_id_det-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	status = "okay";
+};
-- 
2.47.3




From lukas.schmid at netcube.li  Sat Jun  6 12:16:40 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Sat,  6 Jun 2026 21:16:40 +0200
Subject: [PATCH v3 2/3] riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube Systems OpenNMC
In-Reply-To: <20260606191649.2347704-1-lukas.schmid@netcube.li>
References: <20260606191649.2347704-1-lukas.schmid@netcube.li>
Message-ID: <20260606191649.2347704-3-lukas.schmid@netcube.li>

Added the "uart4_pb_pins" pinctrl used by the OpenNMC

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
index 82cc85acccb1..00fddedfa36f 100644
--- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
+++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
@@ -191,6 +191,12 @@ uart3_pb_pins: uart3-pb-pins {
 				pins = "PB6", "PB7";
 				function = "uart3";
 			};
+
+			/omit-if-no-ref/
+			uart4_pb_pins: uart4-pb-pins {
+				pins = "PB2", "PB3";
+				function = "uart4";
+			};
 		};
 
 		ccu: clock-controller at 2001000 {
-- 
2.47.3




From lukas.schmid at netcube.li  Sat Jun  6 12:16:38 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Sat,  6 Jun 2026 21:16:38 +0200
Subject: [PATCH v3 0/3] Add support for NetCube Systems OpenNMC (dobermann)
Message-ID: <20260606191649.2347704-1-lukas.schmid@netcube.li>

This series adds support for the NetCube Systems OpenNMC

Changes in v3:
 - actually add the Makefile changes

Changes in v2:
 - fixed ordering of compatible enum
 - fixed gpio line names

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
Lukas Schmid (3):
  dt-bindings: arm: sunxi: Add NetCube Systems OpenNMC (dobermann)
  riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube
    Systems OpenNMC
  ARM: dts: sunxi: add support for NetCube Systems OpenNMC (dobermann)

 .../devicetree/bindings/arm/sunxi.yaml        |   1 +
 arch/arm/boot/dts/allwinner/Makefile          |   2 +
 .../sun8i-t113s-netcube-dobermann.dts         | 149 ++++++++++++++++++
 .../boot/dts/allwinner/sunxi-d1s-t113.dtsi    |   6 +
 4 files changed, 158 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts

-- 
2.47.3




From lukas.schmid at netcube.li  Sat Jun  6 12:16:39 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Sat,  6 Jun 2026 21:16:39 +0200
Subject: [PATCH v3 1/3] dt-bindings: arm: sunxi: Add NetCube Systems OpenNMC (dobermann)
In-Reply-To: <20260606191649.2347704-1-lukas.schmid@netcube.li>
References: <20260606191649.2347704-1-lukas.schmid@netcube.li>
Message-ID: <20260606191649.2347704-2-lukas.schmid@netcube.li>

The OpenNMC is an open replacement for APC SmartSlot management cards
based on the Nagami System-on-Module.

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 Documentation/devicetree/bindings/arm/sunxi.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
index e6443c266fa1..077b65507645 100644
--- a/Documentation/devicetree/bindings/arm/sunxi.yaml
+++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
@@ -598,6 +598,7 @@ properties:
       - description: NetCube Systems Nagami SoM based boards
         items:
           - enum:
+              - netcube,dobermann
               - netcube,nagami-basic-carrier
               - netcube,nagami-keypad-carrier
           - const: netcube,nagami
-- 
2.47.3




From lukas.schmid at netcube.li  Sat Jun  6 13:54:41 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Sat,  6 Jun 2026 22:54:41 +0200
Subject: [PATCH v4 1/3] dt-bindings: arm: sunxi: Add NetCube Systems OpenNMC (dobermann)
In-Reply-To: <20260606205452.2386930-1-lukas.schmid@netcube.li>
References: <20260606205452.2386930-1-lukas.schmid@netcube.li>
Message-ID: <20260606205452.2386930-2-lukas.schmid@netcube.li>

The OpenNMC is an open replacement for APC SmartSlot management cards
based on the Nagami System-on-Module.

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 Documentation/devicetree/bindings/arm/sunxi.yaml | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/arm/sunxi.yaml b/Documentation/devicetree/bindings/arm/sunxi.yaml
index e6443c266fa1..077b65507645 100644
--- a/Documentation/devicetree/bindings/arm/sunxi.yaml
+++ b/Documentation/devicetree/bindings/arm/sunxi.yaml
@@ -598,6 +598,7 @@ properties:
       - description: NetCube Systems Nagami SoM based boards
         items:
           - enum:
+              - netcube,dobermann
               - netcube,nagami-basic-carrier
               - netcube,nagami-keypad-carrier
           - const: netcube,nagami
-- 
2.47.3




From lukas.schmid at netcube.li  Sat Jun  6 13:54:40 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Sat,  6 Jun 2026 22:54:40 +0200
Subject: [PATCH v4 0/3] Add support for NetCube Systems OpenNMC (dobermann)
Message-ID: <20260606205452.2386930-1-lukas.schmid@netcube.li>

This series adds support for the NetCube Systems OpenNMC.

Sorry for the quick resend. This v4 includes the corrected Makefile
target name.

Changes in v4:
 - fix the ARM Makefile target name for the new board

Changes in v3:
 - actually add the Makefile changes

Changes in v2:
 - fixed ordering of compatible enum
 - fixed gpio line names

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
Lukas Schmid (3):
  dt-bindings: arm: sunxi: Add NetCube Systems OpenNMC (dobermann)
  riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube
    Systems OpenNMC
  ARM: dts: sunxi: add support for NetCube Systems OpenNMC (dobermann)

 .../devicetree/bindings/arm/sunxi.yaml        |   1 +
 arch/arm/boot/dts/allwinner/Makefile          |   2 +
 .../sun8i-t113s-netcube-dobermann.dts         | 149 ++++++++++++++++++
 .../boot/dts/allwinner/sunxi-d1s-t113.dtsi    |   6 +
 4 files changed, 158 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts

-- 
2.47.3



From lukas.schmid at netcube.li  Sat Jun  6 13:54:43 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Sat,  6 Jun 2026 22:54:43 +0200
Subject: [PATCH v4 3/3] ARM: dts: sunxi: add support for NetCube Systems OpenNMC (dobermann)
In-Reply-To: <20260606205452.2386930-1-lukas.schmid@netcube.li>
References: <20260606205452.2386930-1-lukas.schmid@netcube.li>
Message-ID: <20260606205452.2386930-4-lukas.schmid@netcube.li>

NetCube Systems OpenNMC is an open replacement for APC SmartSlot Management
Cards. It is based on the Nagami System-on-Module. It breaks out the
following interfaces:

- 10/100 Mbps Ethernet
- USB Type-C OTG using a TUSB320 (usb0)
- USB Type-C Console Port using a CH340 (uart3)
- USB Type-A Host with internal CH334 USB-Hub (usb1)
- MicroSD Slot with Card-Detect (mmc0)
- WiFi/Bluetooth using the modules built-in ESP32
- SmartSlot serial interface (uart4)
- DS3232 RTC with CR1220 Battery Backup
- Extension connector providing SPI,I2C,USB,CAN,UART for future use.

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 arch/arm/boot/dts/allwinner/Makefile          |   2 +
 .../sun8i-t113s-netcube-dobermann.dts         | 149 ++++++++++++++++++
 2 files changed, 151 insertions(+)
 create mode 100644 arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts

diff --git a/arch/arm/boot/dts/allwinner/Makefile b/arch/arm/boot/dts/allwinner/Makefile
index f71392a55df8..0fc954d41595 100644
--- a/arch/arm/boot/dts/allwinner/Makefile
+++ b/arch/arm/boot/dts/allwinner/Makefile
@@ -201,6 +201,7 @@ DTC_FLAGS_sun8i-h3-orangepi-pc := -@
 DTC_FLAGS_sun8i-h3-bananapi-m2-plus-v1.2 := -@
 DTC_FLAGS_sun8i-h3-orangepi-pc-plus := -@
 DTC_FLAGS_sun8i-t113s-netcube-nagami-basic-carrier := -@
+DTC_FLAGS_sun8i-t113s-netcube-dobermann := -@
 DTC_FLAGS_sun8i-v3s-netcube-kumquat := -@
 dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-a23-evb.dtb \
@@ -261,6 +262,7 @@ dtb-$(CONFIG_MACH_SUN8I) += \
 	sun8i-s3-lichee-zero-plus.dtb \
 	sun8i-s3-pinecube.dtb \
 	sun8i-t113s-mangopi-mq-r-t113.dtb \
+	sun8i-t113s-netcube-dobermann.dtb \
 	sun8i-t113s-netcube-nagami-basic-carrier.dtb \
 	sun8i-t113s-netcube-nagami-keypad-carrier.dtb \
 	sun8i-t3-cqa3t-bv3.dtb \
diff --git a/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts b/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
new file mode 100644
index 000000000000..d7765caffe2a
--- /dev/null
+++ b/arch/arm/boot/dts/allwinner/sun8i-t113s-netcube-dobermann.dts
@@ -0,0 +1,149 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+/*
+ * Copyright (C) 2026 Lukas Schmid <lukas.schmid at netcube.li>
+ */
+
+/dts-v1/;
+#include "sun8i-t113s-netcube-nagami.dtsi"
+
+#include <dt-bindings/leds/common.h>
+
+/ {
+	model = "NetCube Systems OpenNMC (dobermann)";
+	compatible = "netcube,dobermann", "netcube,nagami",
+		     "allwinner,sun8i-t113s";
+
+	aliases {
+		serial2 = &uart4; // UART on SmartSlot
+		rtc0 = &ds3232;
+		rtc1 = &rtc; // not battery backed
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led_heartbeat_green: led-heartbeat-green {
+			gpios = <&pio 6 14 GPIO_ACTIVE_HIGH>; /* PG14 */
+			linux,default-trigger = "heartbeat";
+			color = <LED_COLOR_ID_GREEN>;
+			function = LED_FUNCTION_HEARTBEAT;
+		};
+	};
+};
+
+&ehci0 {
+	status = "okay";
+};
+
+&ehci1 {
+	status = "okay";
+};
+
+&i2c2 {
+	status = "okay";
+
+	tusb320: typec at 60 {
+		compatible = "ti,tusb320";
+		reg = <0x60>;
+		interrupts-extended = <&pio 3 22 IRQ_TYPE_LEVEL_LOW>;  /* PD22 */
+	};
+
+	ds3232: rtc at 68 {
+		compatible = "dallas,ds3232";
+		reg = <0x68>;
+	};
+};
+
+/* microSD Card Slot on the board */
+&mmc0 {
+	vmmc-supply = <&reg_vcc3v3>;
+	disable-wp;
+	bus-width = <4>;
+	cd-gpios = <&pio 6 15 GPIO_ACTIVE_LOW>; /* PG15 */
+	status = "okay";
+};
+
+&ohci0 {
+	status = "okay";
+};
+
+&ohci1 {
+	status = "okay";
+};
+
+&pio {
+	gpio-line-names = "", "", "", "", // PA
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "SMART_TX", "SMART_RX", // PB
+			  "EXT_IO3", "EXT_IO2", "CONSOLE_TX", "CONSOLE_RX",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "eMMC_CLK", "eMMC_CMD", // PC
+			  "eMMC_D2", "eMMC_D1", "eMMC_D0", "eMMC_D3",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "", // PD
+			  "", "", "", "",
+			  "", "USB_SEC_EN", "EXT_SPI_nCS", "EXT_SPI_SCK",
+			  "EXT_SPI_MOSI", "EXT_SPI_MISO", "EXT_IO5", "EXT_IO4",
+			  "SMART_SEL", "", "", "",
+			  "I2C2_SCL", "I2C2_SDA", "TUSB320_nINT", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "ETH_CRSDV", "ETH_RXD0", "ETH_RXD1", "ETH_TXCK", // PE
+			  "ETH_TXD0", "ETH_TXD1", "ETH_TXEN", "",
+			  "ETH_MDC", "ETH_MDIO", "I2C3_nINT", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "uSD_D1", "uSD_D0", "uSD_CLK", "uSD_CMD", // PF
+			  "uSD_D3", "uSD_D2", "TUSB320_ID", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "ESP_CLK", "ESP_CMD", "ESP_D0", "ESP_D1", // PG
+			  "ESP_D2", "ESP_D3", "ESP_TXD", "ESP_RXD",
+			  "ESP_nBOOT", "ESP_nRST", "I2C3_SCL", "I2C3_SDA",
+			  "EXT_IO1", "EXT_IO0", "LED_HEARTBEAT", "SD_DETECT",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "",
+			  "", "", "", "";
+};
+
+/* SmartSlot serial */
+&uart4 {
+	pinctrl-0 = <&uart4_pb_pins>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usb_otg {
+	extcon = <&tusb320 0>;
+	dr_mode = "otg";
+	status = "okay";
+};
+
+&usbphy {
+	usb0_id_det-gpios = <&pio 5 6 GPIO_ACTIVE_HIGH>; /* PF6 */
+	status = "okay";
+};
-- 
2.47.3




From lukas.schmid at netcube.li  Sat Jun  6 13:54:42 2026
From: lukas.schmid at netcube.li (Lukas Schmid)
Date: Sat,  6 Jun 2026 22:54:42 +0200
Subject: [PATCH v4 2/3] riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl required by NetCube Systems OpenNMC
In-Reply-To: <20260606205452.2386930-1-lukas.schmid@netcube.li>
References: <20260606205452.2386930-1-lukas.schmid@netcube.li>
Message-ID: <20260606205452.2386930-3-lukas.schmid@netcube.li>

Added the "uart4_pb_pins" pinctrl used by the OpenNMC

Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
---
 arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
index 82cc85acccb1..00fddedfa36f 100644
--- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
+++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
@@ -191,6 +191,12 @@ uart3_pb_pins: uart3-pb-pins {
 				pins = "PB6", "PB7";
 				function = "uart3";
 			};
+
+			/omit-if-no-ref/
+			uart4_pb_pins: uart4-pb-pins {
+				pins = "PB2", "PB3";
+				function = "uart4";
+			};
 		};
 
 		ccu: clock-controller at 2001000 {
-- 
2.47.3




From pjw at kernel.org  Sat Jun  6 17:50:55 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Sat, 6 Jun 2026 18:50:55 -0600 (MDT)
Subject: [PATCH RESEND] riscv: enable HAVE_CMPXCHG_{DOUBLE,LOCAL}
In-Reply-To: <20260605141247.253315-1-mssola@mssola.com>
References: <20260605141247.253315-1-mssola@mssola.com>
Message-ID: <f63eefc9-769d-409c-4099-274254432129@kernel.org>

Hi,

On Fri, 5 Jun 2026, Miquel Sabat? Sol? wrote:

> Support for atomic Compare-And-Swap instructions has been in the RISC-V
> port of the Linux kernel for a long time. That being said, we apparently
> never bothered to set HAVE_CMPXCHG_DOUBLE and HAVE_CMPXCHG_LOCAL in the
> Kconfig, despite having all the framework to support them.
> 
> Signed-off-by: Miquel Sabat? Sol? <mssola at mssola.com>
> ---
> This is a resend of [1], rebased on top of the latest commit from the
> for-next branch.
> 
> I have built this patch with multiple configurations and ran it with KVM
> (the VisionFive2 board that I have lacks the needed extensions). All seems
> to work, but I do wonder if we did not enable these for a reason or this
> just slipped through. So far in the code I believe everything is in place,
> and I haven't seen any commit in the git log stating otherwise.
> 
> [1] https://lore.kernel.org/all/20260220074449.8526-1-mssola at mssola.com/

Thanks for the patch.  Your comments above are why I've been hesitant to 
merge it.  I'm not aware of any publicly available hardware that supports 
Zacas/Zabha.  No one has stepped forward to provide any Tested-by:s on 
hardware that hasn't been released yet.  You mention that you tested on 
your VisionFive2 board, but it would not have exercised those code paths.

Of course, we already have Zacas/Zabha support, merged back in 2024, in 
cmpxchg.h.  I assume (?) that it was tested in QEMU, but I don't see any 
comments about that in the patch series.  No one sent any Tested-by:s 
then, either.

It would be good if you (and ideally others) could put this patch through 
some testing on QEMU with Zacas and Zabha enabled, before we merge it.  
The affected code paths for HAVE_CMPXCHG_LOCAL seem to primarily involve 
per-CPU counters and MM zone counters, so those would be the areas to 
focus.  HAVE_CMPXCHG_DOUBLE seems to do nothing useful other than 
preventing the AMD IOMMU driver from being selected if it's not present, 
so that part of the patch seems fairly useless.  In fact I'd suggest 
dropping that from the patch and just sending a separate patch to remove 
HAVE_CMPXCHG_DOUBLE from the kernel completely.


- Paul

From patchwork-bot+linux-riscv at kernel.org  Sat Jun  6 22:10:12 2026
From: patchwork-bot+linux-riscv at kernel.org (patchwork-bot+linux-riscv at kernel.org)
Date: Sun, 07 Jun 2026 05:10:12 +0000
Subject: [PATCH v2 0/2] riscv: stacktrace: Fix return address handling in
 non-FP unwinder
In-Reply-To: <20260605082034.1426923-1-qirui.001@bytedance.com>
References: <20260605082034.1426923-1-qirui.001@bytedance.com>
Message-ID: <178080901279.114658.9003538182499897339.git-patchwork-notify@kernel.org>

Hello:

This series was applied to riscv/linux.git (for-next)
by Paul Walmsley <pjw at kernel.org>:

On Fri,  5 Jun 2026 16:20:32 +0800 you wrote:
> This 2-patch series fixes how the non-frame-pointer version of
> walk_stackframe handles return addresses, addressing both the
> unwinder layer and the display layer.
> 
> Background
> ==========
> 
> [...]

Here is the summary with links:
  - [v2,1/2] riscv: stacktrace: Remove bogus -0x4 offset in non-FP walk_stackframe
    https://git.kernel.org/riscv/c/73b6d019c851
  - [v2,2/2] riscv: stacktrace: Use %pB for return addresses and %pS for exact IPs
    (no matching commit)

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From apatel at ventanamicro.com  Sat Jun  6 22:48:55 2026
From: apatel at ventanamicro.com (Anup Patel)
Date: Sun, 7 Jun 2026 11:18:55 +0530
Subject: [PATCH v2 1/2] KVM: riscv: Check hugetlb block mappings against
 memslot bounds
In-Reply-To: <20260604142602.3582602-2-tjytimi@163.com>
References: <20260604142602.3582602-1-tjytimi@163.com> <20260604142602.3582602-2-tjytimi@163.com>
Message-ID: <CAK9=C2XGRgz+3c2Rf8bj8tPtAiCpHXrsm2sNC1b7qHt-5p6PZQ@mail.gmail.com>

On Thu, Jun 4, 2026 at 7:58?PM Jinyu Tang <tjytimi at 163.com> wrote:
>
> RISC-V KVM has used the hugetlb VMA size directly as the G-stage
> mapping size since stage-2 page table support was added. That is safe
> only if the block covered by the fault is fully contained in the
> memslot and the userspace address has the same offset as the GPA
> within that block.
>
> The THP path already checks those constraints before installing a PMD
> block mapping. The hugetlb path did not, so an unaligned memslot could
> make KVM install a PMD or PUD sized G-stage block that covers memory
> outside the slot or maps the wrong host pages.
>
> Pass the target mapping size into fault_supports_gstage_huge_mapping().
> The same helper can be used for both THP PMD mappings and hugetlb
> PMD/PUD mappings.
>
> Select hugetlb mapping sizes through the same memslot-boundary check,
> falling back from PUD to PMD to PAGE_SIZE. When a smaller hugetlb
> mapping size is selected, fault the GFN aligned to that selected size
> instead of the original VMA size.
>
> Also keep hugetlb mappings out of transparent_hugepage_adjust(). Once
> the hugetlb path has chosen PAGE_SIZE, promoting it again through the
> THP helper would miss the hugetlb fallback decision.
>
> Fixes: 9d05c1fee837 ("RISC-V: KVM: Implement stage2 page table programming")
> Signed-off-by: Jinyu Tang <tjytimi at 163.com>
> Reviewed-by: Nutty Liu <nutty.liu at hotmail.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

> ---
> v1 -> v2:
>   - Squash the helper parameterization into this hugetlb fix.
>   - Use the ALIGN()/ALIGN_DOWN() form suggested by Nutty Liu and Anup
>     for the memslot boundary check.
>
>  arch/riscv/kvm/mmu.c | 54 ++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 44 insertions(+), 10 deletions(-)
>
> diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
> index 2d3def024..0adf017a2 100644
> --- a/arch/riscv/kvm/mmu.c
> +++ b/arch/riscv/kvm/mmu.c
> @@ -286,7 +286,8 @@ bool kvm_test_age_gfn(struct kvm *kvm, struct kvm_gfn_range *range)
>  }
>
>  static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
> -                                              unsigned long hva)
> +                                              unsigned long hva,
> +                                              unsigned long map_size)
>  {
>         hva_t uaddr_start, uaddr_end;
>         gpa_t gpa_start;
> @@ -300,8 +301,8 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>
>         /*
>          * Pages belonging to memslots that don't have the same alignment
> -        * within a PMD for userspace and GPA cannot be mapped with g-stage
> -        * PMD entries, because we'll end up mapping the wrong pages.
> +        * within a huge page for userspace and GPA cannot be mapped with
> +        * g-stage block entries, because we'll end up mapping the wrong pages.
>          *
>          * Consider a layout like the following:
>          *
> @@ -321,7 +322,7 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>          *   e -> g
>          *   f -> h
>          */
> -       if ((gpa_start & (PMD_SIZE - 1)) != (uaddr_start & (PMD_SIZE - 1)))
> +       if ((gpa_start & (map_size - 1)) != (uaddr_start & (map_size - 1)))
>                 return false;
>
>         /*
> @@ -336,7 +337,8 @@ static bool fault_supports_gstage_huge_mapping(struct kvm_memory_slot *memslot,
>          * userspace_addr or the base_gfn, as both are equally aligned (per
>          * the check above) and equally sized.
>          */
> -       return (hva >= ALIGN(uaddr_start, PMD_SIZE)) && (hva < ALIGN_DOWN(uaddr_end, PMD_SIZE));
> +       return (hva >= ALIGN(uaddr_start, map_size)) &&
> +              (hva < ALIGN_DOWN(uaddr_end, map_size));
>  }
>
>  static int get_hva_mapping_size(struct kvm *kvm,
> @@ -404,7 +406,7 @@ static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
>          * sure that the HVA and GPA are sufficiently aligned and that the
>          * block map is contained within the memslot.
>          */
> -       if (fault_supports_gstage_huge_mapping(memslot, hva)) {
> +       if (fault_supports_gstage_huge_mapping(memslot, hva, PMD_SIZE)) {
>                 int sz;
>
>                 sz = get_hva_mapping_size(kvm, hva);
> @@ -421,12 +423,33 @@ static unsigned long transparent_hugepage_adjust(struct kvm *kvm,
>         return PAGE_SIZE;
>  }
>
> +static unsigned long hugetlb_mapping_size(struct kvm_memory_slot *memslot,
> +                                         unsigned long hva,
> +                                         unsigned long map_size)
> +{
> +       switch (map_size) {
> +       case PUD_SIZE:

As pointed out by sashiko-bot, we need a "#ifndef CONFIG_32BIT" over here.
I have taken care at the time of merging this patch.

> +               if (fault_supports_gstage_huge_mapping(memslot, hva, PUD_SIZE))
> +                       return PUD_SIZE;
> +               fallthrough;
> +       case PMD_SIZE:
> +               if (fault_supports_gstage_huge_mapping(memslot, hva, PMD_SIZE))
> +                       return PMD_SIZE;
> +               fallthrough;
> +       case PAGE_SIZE:
> +               return PAGE_SIZE;
> +       default:
> +               return map_size;
> +       }
> +}
> +
>  int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
>                       gpa_t gpa, unsigned long hva, bool is_write,
>                       struct kvm_gstage_mapping *out_map)
>  {
>         int ret;
>         kvm_pfn_t hfn;
> +       bool is_hugetlb;
>         bool writable;
>         short vma_pageshift;
>         gfn_t gfn = gpa >> PAGE_SHIFT;
> @@ -460,16 +483,23 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
>                 return -EFAULT;
>         }
>
> -       if (is_vm_hugetlb_page(vma))
> +       is_hugetlb = is_vm_hugetlb_page(vma);
> +       if (is_hugetlb)
>                 vma_pageshift = huge_page_shift(hstate_vma(vma));
>         else
>                 vma_pageshift = PAGE_SHIFT;
>         vma_pagesize = 1ULL << vma_pageshift;
>         if (logging || (vma->vm_flags & VM_PFNMAP))
>                 vma_pagesize = PAGE_SIZE;
> +       else if (is_hugetlb)
> +               vma_pagesize = hugetlb_mapping_size(memslot, hva, vma_pagesize);
>
> +       /*
> +        * For hugetlb mappings, vma_pagesize might have been reduced from the
> +        * VMA size to a smaller safe mapping size.
> +        */
>         if (vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE)
> -               gfn = (gpa & huge_page_mask(hstate_vma(vma))) >> PAGE_SHIFT;
> +               gfn = ALIGN_DOWN(gpa, vma_pagesize) >> PAGE_SHIFT;
>
>         /*
>          * Read mmu_invalidate_seq so that KVM can detect if the results of
> @@ -511,8 +541,12 @@ int kvm_riscv_mmu_map(struct kvm_vcpu *vcpu, struct kvm_memory_slot *memslot,
>         if (mmu_invalidate_retry(kvm, mmu_seq))
>                 goto out_unlock;
>
> -       /* Check if we are backed by a THP and thus use block mapping if possible */
> -       if (!logging && (vma_pagesize == PAGE_SIZE))
> +       /*
> +        * Check if we are backed by a THP and thus use block mapping if
> +        * possible. Hugetlb mappings already selected their target size above,
> +        * so do not promote them through the THP helper.
> +        */
> +       if (!logging && !is_hugetlb && vma_pagesize == PAGE_SIZE)
>                 vma_pagesize = transparent_hugepage_adjust(kvm, memslot, hva, &hfn, &gpa);
>
>         if (writable) {
> --
> 2.43.0
>

Queued this patch for Linux-7.2

Thanks,
Anup


From apatel at ventanamicro.com  Sat Jun  6 22:54:40 2026
From: apatel at ventanamicro.com (Anup Patel)
Date: Sun, 7 Jun 2026 11:24:40 +0530
Subject: [PATCH v2 2/2] KVM: selftests: Add a hugetlb memslot alignment
 test mode
In-Reply-To: <20260604142602.3582602-3-tjytimi@163.com>
References: <20260604142602.3582602-1-tjytimi@163.com> <20260604142602.3582602-3-tjytimi@163.com>
Message-ID: <CAK9=C2Xx+wWL=htOvqmPfF4=f68CNF0r3W9nfTNSMjfSyws-tw@mail.gmail.com>

On Thu, Jun 4, 2026 at 7:58?PM Jinyu Tang <tjytimi at 163.com> wrote:
>
> kvm_page_table_test can already exercise hugetlb-backed guest memory,
> but it always creates the test memslot with GPA alignment matching the
> hugetlb backing size. That misses the case where a valid hugetlb
> memslot is later moved so that the memslot GPA and HVA no longer have
> the same offset within the backing huge page.
>
> Add a -u option that moves the test memslot GPA by one guest page after
> creating the hugetlb memslot. The memslot is created through the normal
> helper first, so the backing allocation remains valid and hugetlb aligned.
> Moving the memslot then creates a deliberate HVA/GPA offset mismatch
> before the guest mapping is installed.
>
> This mode is useful for checking that architecture MMUs do not install
> a block mapping when the block would map the wrong host pages or cover
> memory outside the memslot. The option is restricted to hugetlb-backed
> test memory because it's specifically about hugetlb block mapping
> eligibility.
>
> Signed-off-by: Jinyu Tang <tjytimi at 163.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

I did not observe any impact on the default usage without "-u"
option hence queueing it for Linux-7.2

Thanks
Anup

> ---
> v1 -> v2:
>   - Keep the selftest change unchanged from v1
>
>  .../selftests/kvm/kvm_page_table_test.c       | 28 +++++++++++++++----
>  1 file changed, 22 insertions(+), 6 deletions(-)
>
> diff --git a/tools/testing/selftests/kvm/kvm_page_table_test.c b/tools/testing/selftests/kvm/kvm_page_table_test.c
> index fc5242fb9..a910e3abb 100644
> --- a/tools/testing/selftests/kvm/kvm_page_table_test.c
> +++ b/tools/testing/selftests/kvm/kvm_page_table_test.c
> @@ -230,6 +230,7 @@ struct test_params {
>         u64 phys_offset;
>         u64 test_mem_size;
>         enum vm_mem_backing_src_type src_type;
> +       bool misalign_slot_gpa;
>  };
>
>  static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg)
> @@ -244,6 +245,7 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg)
>         u64 guest_num_pages;
>         u64 alignment;
>         void *host_test_mem;
> +       struct userspace_mem_region *region;
>         struct kvm_vm *vm;
>
>         /* Align up the test memory size */
> @@ -276,13 +278,22 @@ static struct kvm_vm *pre_init_before_test(enum vm_guest_mode mode, void *arg)
>         /* Add an extra memory slot with specified backing src type */
>         vm_userspace_mem_region_add(vm, src_type, guest_test_phys_mem,
>                                     TEST_MEM_SLOT_INDEX, guest_num_pages, 0);
> +       region = memslot2region(vm, TEST_MEM_SLOT_INDEX);
> +       host_test_mem = region->host_mem;
> +
> +       if (p->misalign_slot_gpa) {
> +               TEST_ASSERT(is_backing_src_hugetlb(src_type),
> +                           "Memslot GPA misalignment requires hugetlb backing");
> +               TEST_ASSERT(guest_num_pages > 1,
> +                           "Need at least two guest pages to misalign memslot GPA");
> +
> +               guest_test_phys_mem += guest_page_size;
> +               vm_mem_region_move(vm, TEST_MEM_SLOT_INDEX, guest_test_phys_mem);
> +       }
>
>         /* Do mapping(GVA->GPA) for the testing memory slot */
>         virt_map(vm, guest_test_virt_mem, guest_test_phys_mem, guest_num_pages);
>
> -       /* Cache the HVA pointer of the region */
> -       host_test_mem = addr_gpa2hva(vm, (gpa_t)guest_test_phys_mem);
> -
>         /* Export shared structure test_args to guest */
>         sync_global_to_guest(vm, test_args);
>
> @@ -417,8 +428,8 @@ static void run_test(enum vm_guest_mode mode, void *arg)
>  static void help(char *name)
>  {
>         puts("");
> -       printf("usage: %s [-h] [-p offset] [-m mode] "
> -              "[-b mem-size] [-v vcpus] [-s mem-type]\n", name);
> +       printf("usage: %s [-h] [-p offset] [-m mode] [-b mem-size]\n", name);
> +       printf("          [-v vcpus] [-s mem-type] [-u]\n");
>         puts("");
>         printf(" -p: specify guest physical test memory offset\n"
>                "     Warning: a low offset can conflict with the loaded test code.\n");
> @@ -428,6 +439,8 @@ static void help(char *name)
>         printf(" -v: specify the number of vCPUs to run\n"
>                "     (default: 1)\n");
>         backing_src_help("-s");
> +       printf(" -u: move the test memslot GPA by one guest page after creating\n"
> +              "     the memslot, forcing a hugetlb HVA/GPA offset mismatch\n");
>         puts("");
>  }
>
> @@ -442,7 +455,7 @@ int main(int argc, char *argv[])
>
>         guest_modes_append_default();
>
> -       while ((opt = getopt(argc, argv, "hp:m:b:v:s:")) != -1) {
> +       while ((opt = getopt(argc, argv, "hp:m:b:v:s:u")) != -1) {
>                 switch (opt) {
>                 case 'p':
>                         p.phys_offset = strtoull(optarg, NULL, 0);
> @@ -461,6 +474,9 @@ int main(int argc, char *argv[])
>                 case 's':
>                         p.src_type = parse_backing_src_type(optarg);
>                         break;
> +               case 'u':
> +                       p.misalign_slot_gpa = true;
> +                       break;
>                 case 'h':
>                 default:
>                         help(argv[0]);
> --
> 2.43.0
>


From anup at brainfault.org  Sat Jun  6 23:20:31 2026
From: anup at brainfault.org (Anup Patel)
Date: Sun, 7 Jun 2026 11:50:31 +0530
Subject: [PATCH v2 1/2] RISC-V: KVM: Fix skip of valid pages in kvm_riscv_gstage_wp_range
In-Reply-To: <20260604230317.30501-2-atwufei@163.com>
References: <20260604230317.30501-1-atwufei@163.com> <20260604230317.30501-2-atwufei@163.com>
Message-ID: <CAAhSdy3hugWgSPKiuos38-osAFWkvQ3fHph9AMhGQZZAAf+pSw@mail.gmail.com>

On Fri, Jun 5, 2026 at 4:33?AM <atwufei at 163.com> wrote:
>
> From: Wu Fei <wu.fei9 at sanechips.com.cn>
>
> The current gstage range walker unconditionally advances by 'page_size'
> when a leaf PTE is not found, e.g. when the range to wp is
> [0xfffff01fc000, 0xfffff023c000) and page_size is 2MB, if found_leaf of
> 0xfffff01fc000 returns false, it skip the whole range, but it's possible
> to have valid entries in [0xfffff0200000, 0xfffff023c000).
>
> Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this patch for Linux-7.2

Thanks,
Anup


> ---
>  arch/riscv/kvm/gstage.c | 16 ++++++++--------
>  1 file changed, 8 insertions(+), 8 deletions(-)
>
> diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
> index d9fe8be2a151..2b141a78ecac 100644
> --- a/arch/riscv/kvm/gstage.c
> +++ b/arch/riscv/kvm/gstage.c
> @@ -429,14 +429,14 @@ void kvm_riscv_gstage_wp_range(struct kvm_gstage *gstage, gpa_t start, gpa_t end
>                 if (ret)
>                         break;
>
> -               if (!found_leaf)
> -                       goto next;
> -
> -               addr = ALIGN_DOWN(addr, page_size);
> -               kvm_riscv_gstage_op_pte(gstage, addr, ptep,
> -                                       ptep_level, GSTAGE_OP_WP);
> -next:
> -               addr += page_size;
> +               if (!found_leaf) {
> +                       addr = ALIGN(addr + 1, page_size);
> +               } else {
> +                       addr = ALIGN_DOWN(addr, page_size);
> +                       kvm_riscv_gstage_op_pte(gstage, addr, ptep,
> +                                               ptep_level, GSTAGE_OP_WP);
> +                       addr += page_size;
> +               }
>         }
>  }
>
> --
> 2.51.0
>


From anup at brainfault.org  Sat Jun  6 23:20:35 2026
From: anup at brainfault.org (Anup Patel)
Date: Sun, 7 Jun 2026 11:50:35 +0530
Subject: [PATCH v2 2/2] RISC-V: KVM: Fix skip of valid pages in kvm_riscv_gstage_unmap_range
In-Reply-To: <20260604230317.30501-3-atwufei@163.com>
References: <20260604230317.30501-1-atwufei@163.com> <20260604230317.30501-3-atwufei@163.com>
Message-ID: <CAAhSdy0KLEaCevhDTR-vK4EFZuFV5Nc32eZHhqndOuXkqW4bEA@mail.gmail.com>

On Fri, Jun 5, 2026 at 4:33?AM <atwufei at 163.com> wrote:
>
> From: Wu Fei <wu.fei9 at sanechips.com.cn>
>
> Same as kvm_riscv_gstage_wp_range, the possible valid pages should not
> be skipped if !found_leaf. Different from wp case, which can
> write-protect more than asked, unmap can't do that, no splitting is
> added right now but a warning is logged instead.
>
> Signed-off-by: Wu Fei <wu.fei9 at sanechips.com.cn>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this patch for Linux-7.2

Thanks,
Anup


> ---
>  arch/riscv/kvm/gstage.c | 20 ++++++++++++--------
>  1 file changed, 12 insertions(+), 8 deletions(-)
>
> diff --git a/arch/riscv/kvm/gstage.c b/arch/riscv/kvm/gstage.c
> index 2b141a78ecac..d78f5aeb8b40 100644
> --- a/arch/riscv/kvm/gstage.c
> +++ b/arch/riscv/kvm/gstage.c
> @@ -395,15 +395,19 @@ void kvm_riscv_gstage_unmap_range(struct kvm_gstage *gstage,
>                 if (ret)
>                         break;
>
> -               if (!found_leaf)
> -                       goto next;
> -
> -               if (!(addr & (page_size - 1)) && ((end - addr) >= page_size))
> -                       kvm_riscv_gstage_op_pte(gstage, addr, ptep,
> -                                               ptep_level, GSTAGE_OP_CLEAR);
> +               if (!found_leaf) {
> +                       addr = ALIGN(addr + 1, page_size);
> +               } else {
> +                       if (!(addr & (page_size - 1)) && ((end - addr) >= page_size))
> +                               kvm_riscv_gstage_op_pte(gstage, addr, ptep,
> +                                                       ptep_level, GSTAGE_OP_CLEAR);
> +                       else {
> +                               WARN_ONCE(1, "Skip unmap range addr: %#llx, end: %#llx, page_size: %#lx\n",
> +                                               addr, end, page_size);
> +                       }
>
> -next:
> -               addr += page_size;
> +                       addr += page_size;
> +               }
>
>                 /*
>                  * If the range is too large, release the kvm->mmu_lock
> --
> 2.51.0
>


From pjw at kernel.org  Sat Jun  6 23:40:34 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Sun, 7 Jun 2026 00:40:34 -0600 (MDT)
Subject: [PATCH v2 0/5] riscv: kfence: Handle the spurious fault after
 kfence_unprotect(), and related fixes
In-Reply-To: <20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d@iscas.ac.cn>
References: <20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d@iscas.ac.cn>
Message-ID: <85e01c4c-6616-3ece-520f-30c6f8e53974@kernel.org>

On Tue, 3 Mar 2026, Vivian Wang wrote:

> kfence_unprotect() on RISC-V doesn't flush TLBs, because we can't send
> IPIs in some contexts where kfence objects are allocated. This leads to
> spurious faults and kfence false positives.
> 
> Avoid these spurious faults using the same "new_vmalloc" mechanism,
> which I have renamed new_valid_map_cpus to avoid confusion, since the
> kfence pool comes from the linear mapping, not vmalloc.
> 
> Commit b3431a8bb336 ("riscv: Fix IPIs usage in kfence_protect_page()")
> only seemed to consider false negatives, which are indeed tolerable.
> False positives on the other hand are not okay since they waste
> developer time (or just my time somehow?) and spam kmsg making
> diagnosing other problems difficult.
> 
> Patch 2 is the implementation to poke (what was called) new_vmalloc upon
> kfence_unprotect(). Patch 1 is some refactoring that patch 2 depends on.
> Patch 3 through 5 are some additional refactoring and minor fixes.

Thanks, queued for v7.2.


- Paul


From pjw at kernel.org  Sat Jun  6 23:57:46 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Sun, 7 Jun 2026 00:57:46 -0600 (MDT)
Subject: [PATCH v2] riscv: panic if IRQ handler stacks cannot be
 allocated
In-Reply-To: <20260404185522.21767-1-osama.abdelkader@gmail.com>
References: <20260404185522.21767-1-osama.abdelkader@gmail.com>
Message-ID: <773527c2-760d-60c6-23c3-0f1f60cc3fea@kernel.org>

On Sat, 4 Apr 2026, Osama Abdelkader wrote:

> init_irq_stacks() and init_irq_scs() may fail when arch_alloc_vmap_stack
> or scs_alloc return NULL, call panic() in this case.
> 
> Signed-off-by: Osama Abdelkader <osama.abdelkader at gmail.com>

Thanks, queued for v7.2.


- Paul


From pjw at kernel.org  Sun Jun  7 00:08:02 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Sun, 7 Jun 2026 01:08:02 -0600 (MDT)
Subject: [PATCH RESEND] riscv: kexec: use min to simplify
 riscv_kexec_elf_load
In-Reply-To: <ah_0fOD8mNWTKz9f@gmail.com>
References: <20260602224725.1088385-3-thorsten.blum@linux.dev> <ah_0fOD8mNWTKz9f@gmail.com>
Message-ID: <b5de86e2-68a4-33b5-d1a3-62ca52f9a5cd@kernel.org>

On Wed, 3 Jun 2026, Breno Leitao wrote:

> On Wed, Jun 03, 2026 at 12:47:22AM +0200, Thorsten Blum wrote:
> > Use min() to replace the open-coded version and assign the result
> > directly to kbuf.bufsz. Drop the now-unused local size variable.
> > 
> > Signed-off-by: Thorsten Blum <thorsten.blum at linux.dev>
> 
> Reviewed-by: Breno Leitao <leitao at debian.org>

Thanks, queued for v7.2.

- Paul


From patchwork-bot+linux-riscv at kernel.org  Sun Jun  7 01:00:06 2026
From: patchwork-bot+linux-riscv at kernel.org (patchwork-bot+linux-riscv at kernel.org)
Date: Sun, 07 Jun 2026 08:00:06 +0000
Subject: [PATCH 0/4] riscv: alternative: Also patch the CFI vDSO
In-Reply-To: <20260504-riscv-cfi-vdso-alternative-v1-0-bcdf3d37f62e@linutronix.de>
References: <20260504-riscv-cfi-vdso-alternative-v1-0-bcdf3d37f62e@linutronix.de>
Message-ID: <178081920690.147064.6320265225927754862.git-patchwork-notify@kernel.org>

Hello:

This series was applied to riscv/linux.git (for-next)
by Paul Walmsley <pjw at kernel.org>:

On Mon, 04 May 2026 08:30:49 +0200 you wrote:
> The dedicated vDSO for CFI-enabled userspace can also contain
> alternative entries.
> 
> It seems the vDSO alternative patching is actually dead code since
> commit 0b1d60d6dd9e ("riscv: Fix build with
> CONFIG_CC_OPTIMIZE_FOR_SIZE=y"). However new usages will be added
> soonish.
> 
> [...]

Here is the summary with links:
  - [1/4] riscv: vdso: Always declare vdso_start symbols
    https://git.kernel.org/riscv/c/499578e22ae0
  - [2/4] riscv: alternative: Use IS_ENABLED() over ifdeffery for apply_vdso_alternatives()
    https://git.kernel.org/riscv/c/4fd6505f189d
  - [3/4] riscv: alternative: Pass vDSO start as parameter to apply_vdso_alternatives()
    https://git.kernel.org/riscv/c/6386161abb02
  - [4/4] riscv: alternative: Also patch the CFI vDSO
    https://git.kernel.org/riscv/c/d3e0634787a2

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html




From inochiama at gmail.com  Sun Jun  7 01:10:56 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:10:56 +0800
Subject: [PATCH v3 0/8] RISC-V: KVM: Add Svadu/Zicfiss/Zicfilp FWFT support
Message-ID: <20260607081105.993908-1-inochiama@gmail.com>

This patchset based on the patchset "RISC-V: KVM: Add Zicfiss/Zicfilp
support".

The patch includes all the function of original patchset from Quan:
adding the Svadu/Zicfiss/Zicfilp FWFT for the RISC-V KVM. And this
patchset already passes the KVM unit test.

Follow the patchset (Which is queued for v7.2)
https://lore.kernel.org/kvm/20260601-kvm-get_reg_list-v2-v5-0-415d08a2813b at sifive.com/

Test with the patch applied
https://lore.kernel.org/all/20260522142358.87589-1-cuiyunhui at bytedance.com

Changed from v2:
- https://lore.kernel.org/kvm/20260601084336.2601675-1-inochiama at gmail.com/
1. rebase with Yong-Xuan's patch set
2. Add SSP CSR context switch/set/get
3. Move the software-check exception set/unset into FWFT
4. Only delegate software-check exception when Zicfiss/Zicfilp is enabled.
5. Make KVM SBI_FWFT_PTE_AD_HW_UPDATING depends on both Svadu and Svade
   enabled.

Changed from Quan's v1:
- https://lore.kernel.org/kvm/cover.1764509485.git.zhouquan at iscas.ac.cn/
1. rebase to the latest master.
2. Split Svadu change as separate patch
3. Fix all build error from the original series
4. Remove the Svadu check in kvm_riscv_vcpu_config_ran_once() and in
   favor of the FWFT.
5. Remove the LPE/SSE setting bit in kvm_riscv_vcpu_config_ran_once()
   (kvm_riscv_vcpu_setup_config() in original patchset)

Inochi Amaoto (8):
  RISC-V: KVM: Add support for Svadu FWFT features
  KVM: riscv: selftests: add Svadu FWFT extension to get-reg-list test
  RISC-V: KVM: Allow Zicfiss/Zicfilp extensions for Guest/VM
  RISC-V: KVM: Add ssp context save/restore
  RISC-V: KVM: Handle software-check exits for VCPU
  RISC-V: KVM: Delegate SPELP bit to VS/VU mode if landing pad is
    enabled.
  RISC-V: KVM: Add support for control-flow integrity FWFT features
  KVM: riscv: selftests: add Zicfiss/Zicfilp extension to get-reg-list
    test

 arch/riscv/include/asm/csr.h                  |   1 +
 arch/riscv/include/asm/kvm_host.h             |   7 +
 arch/riscv/include/uapi/asm/kvm.h             |  13 ++
 arch/riscv/kvm/isa.c                          |   2 +
 arch/riscv/kvm/vcpu.c                         |   6 +
 arch/riscv/kvm/vcpu_exit.c                    |  10 +
 arch/riscv/kvm/vcpu_onereg.c                  |  66 ++++++-
 arch/riscv/kvm/vcpu_sbi_fwft.c                | 182 ++++++++++++++++++
 .../selftests/kvm/riscv/get-reg-list.c        |  88 +++++++++
 9 files changed, 373 insertions(+), 2 deletions(-)

--
2.54.0



From inochiama at gmail.com  Sun Jun  7 01:10:57 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:10:57 +0800
Subject: [PATCH v3 1/8] RISC-V: KVM: Add support for Svadu FWFT features
In-Reply-To: <20260607081105.993908-1-inochiama@gmail.com>
References: <20260607081105.993908-1-inochiama@gmail.com>
Message-ID: <20260607081105.993908-2-inochiama@gmail.com>

Hardware updating of PTE A/D bits is controlled through ADUE bit in
henvcfg Expose the feature only if both Svadu and Svade are supported
for VS-mode.

Allow the VMM to enable/disable this feature by change the ISA
extension state in the guest.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/include/uapi/asm/kvm.h |  1 +
 arch/riscv/kvm/vcpu_sbi_fwft.c    | 75 +++++++++++++++++++++++++++++++
 2 files changed, 76 insertions(+)

diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
index 504e73305343..7bbea8812d92 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -240,6 +240,7 @@ struct kvm_riscv_sbi_fwft_feature {
 struct kvm_riscv_sbi_fwft {
 	struct kvm_riscv_sbi_fwft_feature misaligned_deleg;
 	struct kvm_riscv_sbi_fwft_feature pointer_masking;
+	struct kvm_riscv_sbi_fwft_feature pte_ad_hw_updating;
 };
 
 /* If you need to interpret the index values, here is the key: */
diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index ab39ac464ffd..7192c229a19e 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -94,6 +94,45 @@ static bool kvm_fwft_is_defined_feature(enum sbi_fwft_feature_t feature)
 	return false;
 }
 
+static void kvm_sbi_fwft_env_flag_reset_helper(struct kvm_vcpu *vcpu,
+					       u64 flag)
+{
+	vcpu->arch.cfg.henvcfg &= ~flag;
+}
+
+static long kvm_sbi_fwft_env_flag_set_helper(struct kvm_vcpu *vcpu,
+					     struct kvm_sbi_fwft_config *conf,
+					     bool one_reg_access,
+					     unsigned long value, u64 flag)
+{
+	struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+
+	if (value == 0)
+		cfg->henvcfg &= ~flag;
+	else if (value == 1)
+		cfg->henvcfg |= flag;
+	else
+		return SBI_ERR_INVALID_PARAM;
+
+	if (!one_reg_access) {
+		csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg);
+		if (IS_ENABLED(CONFIG_32BIT))
+			csr_write(CSR_HENVCFGH, vcpu->arch.cfg.henvcfg >> 32);
+	}
+
+	return SBI_SUCCESS;
+}
+
+static long kvm_sbi_fwft_env_flag_get_helper(struct kvm_vcpu *vcpu,
+					     struct kvm_sbi_fwft_config *conf,
+					     bool one_reg_access,
+					     unsigned long *value, u64 flag)
+{
+	*value = (vcpu->arch.cfg.henvcfg & flag) == flag;
+
+	return SBI_SUCCESS;
+}
+
 static bool kvm_sbi_fwft_misaligned_delegation_supported(struct kvm_vcpu *vcpu)
 {
 	return misaligned_traps_can_delegate();
@@ -137,6 +176,33 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
 	return SBI_SUCCESS;
 }
 
+static bool kvm_sbi_fwft_pte_ad_hw_updating_supported(struct kvm_vcpu *vcpu)
+{
+	return riscv_isa_extension_available(vcpu->arch.isa, SVADU) &&
+		riscv_isa_extension_available(vcpu->arch.isa, SVADE);
+}
+
+static void kvm_sbi_fwft_reset_pte_ad_hw_updating(struct kvm_vcpu *vcpu)
+{
+	kvm_sbi_fwft_env_flag_reset_helper(vcpu, ENVCFG_ADUE);
+}
+
+static long kvm_sbi_fwft_set_pte_ad_hw_updating(struct kvm_vcpu *vcpu,
+						struct kvm_sbi_fwft_config *conf,
+						bool one_reg_access, unsigned long value)
+{
+	return kvm_sbi_fwft_env_flag_set_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_ADUE);
+}
+
+static long kvm_sbi_fwft_get_pte_ad_hw_updating(struct kvm_vcpu *vcpu,
+						struct kvm_sbi_fwft_config *conf,
+						bool one_reg_access, unsigned long *value)
+{
+	return kvm_sbi_fwft_env_flag_get_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_ADUE);
+}
+
 #ifndef CONFIG_32BIT
 
 static bool try_to_set_pmm(unsigned long value)
@@ -246,6 +312,15 @@ static const struct kvm_sbi_fwft_feature features[] = {
 		.set = kvm_sbi_fwft_set_misaligned_delegation,
 		.get = kvm_sbi_fwft_get_misaligned_delegation,
 	},
+	{
+		.id = SBI_FWFT_PTE_AD_HW_UPDATING,
+		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pte_ad_hw_updating.enable) /
+				 sizeof(unsigned long),
+		.supported = kvm_sbi_fwft_pte_ad_hw_updating_supported,
+		.reset = kvm_sbi_fwft_reset_pte_ad_hw_updating,
+		.set = kvm_sbi_fwft_set_pte_ad_hw_updating,
+		.get = kvm_sbi_fwft_get_pte_ad_hw_updating,
+	},
 #ifndef CONFIG_32BIT
 	{
 		.id = SBI_FWFT_POINTER_MASKING_PMLEN,
-- 
2.54.0



From inochiama at gmail.com  Sun Jun  7 01:10:58 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:10:58 +0800
Subject: [PATCH v3 2/8] KVM: riscv: selftests: add Svadu FWFT extension to get-reg-list test
In-Reply-To: <20260607081105.993908-1-inochiama@gmail.com>
References: <20260607081105.993908-1-inochiama@gmail.com>
Message-ID: <20260607081105.993908-3-inochiama@gmail.com>

The KVM RISC-V allows Svadu FWFT for Guest/VM so add this extension
to get-reg-list test.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 .../selftests/kvm/riscv/get-reg-list.c        | 21 +++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index cb86cb6b3635..94e33b2ee796 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -745,6 +745,9 @@ static const char *sbi_fwft_id_to_str(__u64 reg_off)
 	case 3: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.enable)";
 	case 4: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.flags)";
 	case 5: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value)";
+	case 6: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.enable)";
+	case 7: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.flags)";
+	case 8: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.value)";
 	}
 	return strdup_printf("KVM_REG_RISCV_SBI_FWFT | %lld /* UNKNOWN */", reg_off);
 }
@@ -944,6 +947,13 @@ static __u64 sbi_fwft_pointer_masking_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pointer_masking.value),
 };
 
+static __u64 sbi_fwft_pte_ad_hw_updating_regs[] = {
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_EXT | KVM_REG_RISCV_SBI_SINGLE | KVM_RISCV_SBI_EXT_FWFT,
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.enable),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.flags),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.value),
+};
+
 static __u64 zicbom_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicbom_block_size),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM,
@@ -1259,6 +1269,16 @@ static struct vcpu_reg_list config_sbi_fwft_pointer_masking = {
 	},
 };
 
+static struct vcpu_reg_list config_sbi_fwft_pte_ad_hw_updating = {
+	.sublists = {
+		SUBLIST_BASE,
+		SUBLIST_ISA(svade, SVADE),
+		SUBLIST_ISA(svadu, SVADU),
+		SUBLIST_SBI(fwft_pte_ad_hw_updating, FWFT),
+		{0},
+	},
+};
+
 struct vcpu_reg_list *vcpu_configs[] = {
 	&config_sbi_base,
 	&config_sbi_sta,
@@ -1268,6 +1288,7 @@ struct vcpu_reg_list *vcpu_configs[] = {
 	&config_sbi_mpxy,
 	&config_sbi_fwft_misaligned_deleg,
 	&config_sbi_fwft_pointer_masking,
+	&config_sbi_fwft_pte_ad_hw_updating,
 	&config_aia,
 	&config_fp_f,
 	&config_fp_d,
-- 
2.54.0



From inochiama at gmail.com  Sun Jun  7 01:10:59 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:10:59 +0800
Subject: [PATCH v3 3/8] RISC-V: KVM: Allow Zicfiss/Zicfilp extensions for Guest/VM
In-Reply-To: <20260607081105.993908-1-inochiama@gmail.com>
References: <20260607081105.993908-1-inochiama@gmail.com>
Message-ID: <20260607081105.993908-4-inochiama@gmail.com>

Extend the KVM ISA extension array to allow KVM userspace to
detect and enable Zicfiss/Zicfilp extensions for Guest/VM.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/include/uapi/asm/kvm.h | 2 ++
 arch/riscv/kvm/isa.c              | 2 ++
 2 files changed, 4 insertions(+)

diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
index 7bbea8812d92..a27de850fa4c 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -199,6 +199,8 @@ enum KVM_RISCV_ISA_EXT_ID {
 	KVM_RISCV_ISA_EXT_ZCLSD,
 	KVM_RISCV_ISA_EXT_ZILSD,
 	KVM_RISCV_ISA_EXT_ZALASR,
+	KVM_RISCV_ISA_EXT_ZICFILP,
+	KVM_RISCV_ISA_EXT_ZICFISS,
 	KVM_RISCV_ISA_EXT_MAX,
 };
 
diff --git a/arch/riscv/kvm/isa.c b/arch/riscv/kvm/isa.c
index 1132d909cc25..9852a91fdecc 100644
--- a/arch/riscv/kvm/isa.c
+++ b/arch/riscv/kvm/isa.c
@@ -65,6 +65,8 @@ static const unsigned long kvm_isa_ext_arr[] = {
 	KVM_ISA_EXT_ARR(ZICBOP),
 	KVM_ISA_EXT_ARR(ZICBOZ),
 	KVM_ISA_EXT_ARR(ZICCRSE),
+	KVM_ISA_EXT_ARR(ZICFILP),
+	KVM_ISA_EXT_ARR(ZICFISS),
 	KVM_ISA_EXT_ARR(ZICNTR),
 	KVM_ISA_EXT_ARR(ZICOND),
 	KVM_ISA_EXT_ARR(ZICSR),
-- 
2.54.0



From inochiama at gmail.com  Sun Jun  7 01:11:00 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:11:00 +0800
Subject: [PATCH v3 4/8] RISC-V: KVM: Add ssp context save/restore
In-Reply-To: <20260607081105.993908-1-inochiama@gmail.com>
References: <20260607081105.993908-1-inochiama@gmail.com>
Message-ID: <20260607081105.993908-5-inochiama@gmail.com>

Add ssp context save/restore for guest VCPUs and also add it to the
ONE_REG interface to allow its access from user space.

Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/include/asm/kvm_host.h |  7 ++++
 arch/riscv/include/uapi/asm/kvm.h |  8 ++++
 arch/riscv/kvm/vcpu.c             |  6 +++
 arch/riscv/kvm/vcpu_onereg.c      | 66 ++++++++++++++++++++++++++++++-
 4 files changed, 85 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 75b0a951c1bc..54ef83ac2d1e 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -161,6 +161,10 @@ struct kvm_vcpu_smstateen_csr {
 	unsigned long sstateen0;
 };
 
+struct kvm_vcpu_zicfiss_csr {
+	unsigned long ssp;
+};
+
 struct kvm_vcpu_reset_state {
 	spinlock_t lock;
 	unsigned long pc;
@@ -201,6 +205,9 @@ struct kvm_vcpu_arch {
 	/* CPU Smstateen CSR context of Guest VCPU */
 	struct kvm_vcpu_smstateen_csr smstateen_csr;
 
+	/* CPU Zicfiss CSR context of Guest VCPU */
+	struct kvm_vcpu_zicfiss_csr zicfiss_csr;
+
 	/* CPU reset state of Guest VCPU */
 	struct kvm_vcpu_reset_state reset_state;
 
diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
index a27de850fa4c..fd4c81697617 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -102,6 +102,11 @@ struct kvm_riscv_smstateen_csr {
 	unsigned long sstateen0;
 };
 
+/* Zicfiss CSR for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
+struct kvm_riscv_zicfiss_csr {
+	unsigned long ssp;
+};
+
 /* TIMER registers for KVM_GET_ONE_REG and KVM_SET_ONE_REG */
 struct kvm_riscv_timer {
 	__u64 frequency;
@@ -266,12 +271,15 @@ struct kvm_riscv_sbi_fwft {
 #define KVM_REG_RISCV_CSR_GENERAL	(0x0 << KVM_REG_RISCV_SUBTYPE_SHIFT)
 #define KVM_REG_RISCV_CSR_AIA		(0x1 << KVM_REG_RISCV_SUBTYPE_SHIFT)
 #define KVM_REG_RISCV_CSR_SMSTATEEN	(0x2 << KVM_REG_RISCV_SUBTYPE_SHIFT)
+#define KVM_REG_RISCV_CSR_ZICFISS	(0x3 << KVM_REG_RISCV_SUBTYPE_SHIFT)
 #define KVM_REG_RISCV_CSR_REG(name)	\
 		(offsetof(struct kvm_riscv_csr, name) / sizeof(unsigned long))
 #define KVM_REG_RISCV_CSR_AIA_REG(name)	\
 	(offsetof(struct kvm_riscv_aia_csr, name) / sizeof(unsigned long))
 #define KVM_REG_RISCV_CSR_SMSTATEEN_REG(name)  \
 	(offsetof(struct kvm_riscv_smstateen_csr, name) / sizeof(unsigned long))
+#define KVM_REG_RISCV_CSR_ZICFISS_REG(name)  \
+	(offsetof(struct kvm_riscv_zicfiss_csr, name) / sizeof(unsigned long))
 
 /* Timer registers are mapped as type 4 */
 #define KVM_REG_RISCV_TIMER		(0x04 << KVM_REG_RISCV_TYPE_SHIFT)
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index a73690eda84b..783455db1d4d 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -719,6 +719,7 @@ static void kvm_riscv_update_hvip(struct kvm_vcpu *vcpu)
 
 static __always_inline void kvm_riscv_vcpu_swap_in_guest_state(struct kvm_vcpu *vcpu)
 {
+	struct kvm_vcpu_zicfiss_csr *zicficsr = &vcpu->arch.zicfiss_csr;
 	struct kvm_vcpu_smstateen_csr *smcsr = &vcpu->arch.smstateen_csr;
 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
 
@@ -726,10 +727,13 @@ static __always_inline void kvm_riscv_vcpu_swap_in_guest_state(struct kvm_vcpu *
 	vcpu->arch.host_senvcfg = csr_swap(CSR_SENVCFG, csr->senvcfg);
 	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
 		vcpu->arch.host_sstateen0 = csr_swap(CSR_SSTATEEN0, smcsr->sstateen0);
+	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFISS))
+		csr_write(CSR_SSP, zicficsr->ssp);
 }
 
 static __always_inline void kvm_riscv_vcpu_swap_in_host_state(struct kvm_vcpu *vcpu)
 {
+	struct kvm_vcpu_zicfiss_csr *zicficsr = &vcpu->arch.zicfiss_csr;
 	struct kvm_vcpu_smstateen_csr *smcsr = &vcpu->arch.smstateen_csr;
 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
 
@@ -737,6 +741,8 @@ static __always_inline void kvm_riscv_vcpu_swap_in_host_state(struct kvm_vcpu *v
 	csr->senvcfg = csr_swap(CSR_SENVCFG, vcpu->arch.host_senvcfg);
 	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SMSTATEEN))
 		smcsr->sstateen0 = csr_swap(CSR_SSTATEEN0, vcpu->arch.host_sstateen0);
+	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_ZICFISS))
+		zicficsr->ssp = csr_swap(CSR_SSP, 0);
 }
 
 /*
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index bb920e8923c9..bd59aebc8b2e 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -355,6 +355,44 @@ static int kvm_riscv_vcpu_smstateen_get_csr(struct kvm_vcpu *vcpu,
 	return 0;
 }
 
+static inline int kvm_riscv_vcpu_zicfiss_set_csr(struct kvm_vcpu *vcpu,
+						 unsigned long reg_num,
+						 unsigned long reg_val)
+{
+	struct kvm_vcpu_zicfiss_csr *csr = &vcpu->arch.zicfiss_csr;
+	unsigned long regs_max = sizeof(struct kvm_vcpu_zicfiss_csr) /
+		sizeof(unsigned long);
+
+	if (!riscv_isa_extension_available(vcpu->arch.isa, ZICFISS))
+		return -ENOENT;
+	if (reg_num >= regs_max)
+		return -ENOENT;
+
+	reg_num = array_index_nospec(reg_num, regs_max);
+
+	((unsigned long *)csr)[reg_num] = reg_val;
+	return 0;
+}
+
+static int kvm_riscv_vcpu_zicfiss_get_csr(struct kvm_vcpu *vcpu,
+					  unsigned long reg_num,
+					  unsigned long *out_val)
+{
+	struct kvm_vcpu_zicfiss_csr *csr = &vcpu->arch.zicfiss_csr;
+	unsigned long regs_max = sizeof(struct kvm_vcpu_zicfiss_csr) /
+		sizeof(unsigned long);
+
+	if (!riscv_isa_extension_available(vcpu->arch.isa, ZICFISS))
+		return -ENOENT;
+	if (reg_num >= regs_max)
+		return -ENOENT;
+
+	reg_num = array_index_nospec(reg_num, regs_max);
+
+	*out_val = ((unsigned long *)csr)[reg_num];
+	return 0;
+}
+
 static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu,
 				      const struct kvm_one_reg *reg)
 {
@@ -381,6 +419,9 @@ static int kvm_riscv_vcpu_get_reg_csr(struct kvm_vcpu *vcpu,
 	case KVM_REG_RISCV_CSR_SMSTATEEN:
 		rc = kvm_riscv_vcpu_smstateen_get_csr(vcpu, reg_num, &reg_val);
 		break;
+	case KVM_REG_RISCV_CSR_ZICFISS:
+		rc = kvm_riscv_vcpu_zicfiss_get_csr(vcpu, reg_num, &reg_val);
+		break;
 	default:
 		rc = -ENOENT;
 		break;
@@ -423,6 +464,9 @@ static int kvm_riscv_vcpu_set_reg_csr(struct kvm_vcpu *vcpu,
 	case KVM_REG_RISCV_CSR_SMSTATEEN:
 		rc = kvm_riscv_vcpu_smstateen_set_csr(vcpu, reg_num, reg_val);
 		break;
+	case KVM_REG_RISCV_CSR_ZICFISS:
+		rc = kvm_riscv_vcpu_zicfiss_set_csr(vcpu, reg_num, reg_val);
+		break;
 	default:
 		rc = -ENOENT;
 		break;
@@ -688,7 +732,7 @@ static int copy_csr_reg_indices(const struct kvm_vcpu *vcpu,
 				u64 __user *uindices)
 {
 	int n1 = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
-	int n2 = 0, n3 = 0;
+	int n2 = 0, n3 = 0, n4 = 0;
 
 	/* copy general csr regs */
 	for (int i = 0; i < n1; i++) {
@@ -740,7 +784,25 @@ static int copy_csr_reg_indices(const struct kvm_vcpu *vcpu,
 		}
 	}
 
-	return n1 + n2 + n3;
+	/* copy Zicfiss csr regs */
+	if (riscv_isa_extension_available(vcpu->arch.isa, ZICFISS)) {
+		n4 = sizeof(struct kvm_riscv_zicfiss_csr) / sizeof(unsigned long);
+
+		for (int i = 0; i < n4; i++) {
+			u64 size = IS_ENABLED(CONFIG_32BIT) ?
+				   KVM_REG_SIZE_U32 : KVM_REG_SIZE_U64;
+			u64 reg = KVM_REG_RISCV | size | KVM_REG_RISCV_CSR |
+					  KVM_REG_RISCV_CSR_ZICFISS | i;
+
+			if (uindices) {
+				if (put_user(reg, uindices))
+					return -EFAULT;
+				uindices++;
+			}
+		}
+	}
+
+	return n1 + n2 + n3 + n4;
 }
 
 static inline unsigned long num_timer_regs(void)
-- 
2.54.0



From inochiama at gmail.com  Sun Jun  7 01:11:01 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:11:01 +0800
Subject: [PATCH v3 5/8] RISC-V: KVM: Handle software-check exits for VCPU
In-Reply-To: <20260607081105.993908-1-inochiama@gmail.com>
References: <20260607081105.993908-1-inochiama@gmail.com>
Message-ID: <20260607081105.993908-6-inochiama@gmail.com>

The extension Zicfiss/Zicfilp introduces a software-check exception
to the privilege architecture. Delegate this exception to VS mode
when vCPU enable Zicfiss/Zicfilp so the CFI violations in VU/VS could
be reported.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/include/asm/csr.h | 1 +
 arch/riscv/kvm/vcpu_exit.c   | 4 ++++
 2 files changed, 5 insertions(+)

diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 31b8988f4488..224af9facf1f 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -117,6 +117,7 @@
 #define EXC_INST_PAGE_FAULT	12
 #define EXC_LOAD_PAGE_FAULT	13
 #define EXC_STORE_PAGE_FAULT	15
+#define EXC_SOFTWARE_CHECK		18
 #define EXC_INST_GUEST_PAGE_FAULT	20
 #define EXC_LOAD_GUEST_PAGE_FAULT	21
 #define EXC_VIRTUAL_INST_FAULT		22
diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c
index 0bb0c51e3c89..12eebeabdf14 100644
--- a/arch/riscv/kvm/vcpu_exit.c
+++ b/arch/riscv/kvm/vcpu_exit.c
@@ -243,6 +243,10 @@ int kvm_riscv_vcpu_exit(struct kvm_vcpu *vcpu, struct kvm_run *run,
 		run->exit_reason = KVM_EXIT_DEBUG;
 		ret = 0;
 		break;
+	case EXC_SOFTWARE_CHECK:
+		if (vcpu->arch.cfg.henvcfg & (ENVCFG_LPE | ENVCFG_SSE))
+			ret = vcpu_redirect(vcpu, trap);
+		break;
 	default:
 		break;
 	}
-- 
2.54.0



From inochiama at gmail.com  Sun Jun  7 01:11:02 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:11:02 +0800
Subject: [PATCH v3 6/8] RISC-V: KVM: Delegate SPELP bit to VS/VU mode if landing pad is enabled.
In-Reply-To: <20260607081105.993908-1-inochiama@gmail.com>
References: <20260607081105.993908-1-inochiama@gmail.com>
Message-ID: <20260607081105.993908-7-inochiama@gmail.com>

Delegate the newly added SPELP bit from Zicfilp extension to VS/VU mode
if it enables landing pad support.

Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/kvm/vcpu_exit.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/riscv/kvm/vcpu_exit.c b/arch/riscv/kvm/vcpu_exit.c
index 12eebeabdf14..61305da5256d 100644
--- a/arch/riscv/kvm/vcpu_exit.c
+++ b/arch/riscv/kvm/vcpu_exit.c
@@ -154,6 +154,12 @@ void kvm_riscv_vcpu_trap_redirect(struct kvm_vcpu *vcpu,
 	/* Clear Guest SSTATUS.SIE bit */
 	vsstatus &= ~SR_SIE;
 
+	/* Change Guest SSTATUS.SPELP bit */
+	if (vcpu->arch.cfg.henvcfg & ENVCFG_LPE) {
+		vsstatus &= ~SR_SPELP;
+		vsstatus |= vcpu->arch.guest_context.sstatus & SR_SPELP;
+	}
+
 	/* Update Guest SSTATUS */
 	ncsr_write(CSR_VSSTATUS, vsstatus);
 
-- 
2.54.0



From inochiama at gmail.com  Sun Jun  7 01:11:03 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:11:03 +0800
Subject: [PATCH v3 7/8] RISC-V: KVM: Add support for control-flow integrity FWFT features
In-Reply-To: <20260607081105.993908-1-inochiama@gmail.com>
References: <20260607081105.993908-1-inochiama@gmail.com>
Message-ID: <20260607081105.993908-8-inochiama@gmail.com>

Control-flow integrity is controlled through a WARL field in henvcfg.
Expose the feature only if the Zicfilp/Zicfiss is supported for VS-mode.
Allow the VMM to block access to the feature by disabling the ISA
extension in the guest.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 arch/riscv/include/uapi/asm/kvm.h |   2 +
 arch/riscv/kvm/vcpu_sbi_fwft.c    | 107 ++++++++++++++++++++++++++++++
 2 files changed, 109 insertions(+)

diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
index fd4c81697617..20d9959ca44f 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -248,6 +248,8 @@ struct kvm_riscv_sbi_fwft {
 	struct kvm_riscv_sbi_fwft_feature misaligned_deleg;
 	struct kvm_riscv_sbi_fwft_feature pointer_masking;
 	struct kvm_riscv_sbi_fwft_feature pte_ad_hw_updating;
+	struct kvm_riscv_sbi_fwft_feature landing_pad;
+	struct kvm_riscv_sbi_fwft_feature shadow_stack;
 };
 
 /* If you need to interpret the index values, here is the key: */
diff --git a/arch/riscv/kvm/vcpu_sbi_fwft.c b/arch/riscv/kvm/vcpu_sbi_fwft.c
index 7192c229a19e..cb9b9721ec88 100644
--- a/arch/riscv/kvm/vcpu_sbi_fwft.c
+++ b/arch/riscv/kvm/vcpu_sbi_fwft.c
@@ -176,6 +176,95 @@ static long kvm_sbi_fwft_get_misaligned_delegation(struct kvm_vcpu *vcpu,
 	return SBI_SUCCESS;
 }
 
+static long kvm_sbi_fwft_set_cfi(struct kvm_vcpu *vcpu,
+				 struct kvm_sbi_fwft_config *conf,
+				 bool one_reg_access, unsigned long value,
+				 u64 flag)
+{
+	struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+
+	if (value == 0)
+		cfg->henvcfg &= ~flag;
+	else if (value == 1)
+		cfg->henvcfg |= flag;
+	else
+		return SBI_ERR_INVALID_PARAM;
+
+	if (cfg->henvcfg & (ENVCFG_LPE | ENVCFG_SSE))
+		cfg->hedeleg |= EXC_SOFTWARE_CHECK;
+	else
+		cfg->hedeleg &= ~EXC_SOFTWARE_CHECK;
+
+	if (!one_reg_access) {
+		csr_write(CSR_HEDELEG, cfg->hedeleg);
+		/*
+		 * Both Bit LPE and SSE are in the lower part, so it is safe
+		 * to only write the henvcfg
+		 */
+		csr_write(CSR_HENVCFG, vcpu->arch.cfg.henvcfg);
+	}
+
+	return SBI_SUCCESS;
+}
+
+static bool kvm_sbi_fwft_landing_pad_supported(struct kvm_vcpu *vcpu)
+{
+	return riscv_isa_extension_available(vcpu->arch.isa, ZICFILP);
+}
+
+static void kvm_sbi_fwft_reset_landing_pad(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+
+	kvm_sbi_fwft_env_flag_reset_helper(vcpu, ENVCFG_LPE);
+	if ((cfg->henvcfg & (ENVCFG_LPE | ENVCFG_SSE)) == 0)
+		cfg->hedeleg &= ~EXC_SOFTWARE_CHECK;
+}
+
+static long kvm_sbi_fwft_set_landing_pad(struct kvm_vcpu *vcpu,
+					 struct kvm_sbi_fwft_config *conf,
+					 bool one_reg_access, unsigned long value)
+{
+	return kvm_sbi_fwft_set_cfi(vcpu, conf, one_reg_access, value, ENVCFG_LPE);
+}
+
+static long kvm_sbi_fwft_get_landing_pad(struct kvm_vcpu *vcpu,
+					 struct kvm_sbi_fwft_config *conf,
+					 bool one_reg_access, unsigned long *value)
+{
+	return kvm_sbi_fwft_env_flag_get_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_LPE);
+}
+
+static bool kvm_sbi_fwft_shadow_stack_supported(struct kvm_vcpu *vcpu)
+{
+	return riscv_isa_extension_available(vcpu->arch.isa, ZICFISS);
+}
+
+static void kvm_sbi_fwft_reset_shadow_stack(struct kvm_vcpu *vcpu)
+{
+	struct kvm_vcpu_config *cfg = &vcpu->arch.cfg;
+
+	kvm_sbi_fwft_env_flag_reset_helper(vcpu, ENVCFG_SSE);
+	if ((cfg->henvcfg & (ENVCFG_LPE | ENVCFG_SSE)) == 0)
+		cfg->hedeleg &= ~EXC_SOFTWARE_CHECK;
+}
+
+static long kvm_sbi_fwft_set_shadow_stack(struct kvm_vcpu *vcpu,
+					  struct kvm_sbi_fwft_config *conf,
+					  bool one_reg_access, unsigned long value)
+{
+	return kvm_sbi_fwft_set_cfi(vcpu, conf, one_reg_access, value, ENVCFG_SSE);
+}
+
+static long kvm_sbi_fwft_get_shadow_stack(struct kvm_vcpu *vcpu,
+					  struct kvm_sbi_fwft_config *conf,
+					  bool one_reg_access, unsigned long *value)
+{
+	return kvm_sbi_fwft_env_flag_get_helper(vcpu, conf, one_reg_access,
+						value, ENVCFG_SSE);
+}
+
 static bool kvm_sbi_fwft_pte_ad_hw_updating_supported(struct kvm_vcpu *vcpu)
 {
 	return riscv_isa_extension_available(vcpu->arch.isa, SVADU) &&
@@ -312,6 +401,24 @@ static const struct kvm_sbi_fwft_feature features[] = {
 		.set = kvm_sbi_fwft_set_misaligned_delegation,
 		.get = kvm_sbi_fwft_get_misaligned_delegation,
 	},
+	{
+		.id = SBI_FWFT_LANDING_PAD,
+		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, landing_pad.enable) /
+				 sizeof(unsigned long),
+		.supported = kvm_sbi_fwft_landing_pad_supported,
+		.reset = kvm_sbi_fwft_reset_landing_pad,
+		.set = kvm_sbi_fwft_set_landing_pad,
+		.get = kvm_sbi_fwft_get_landing_pad,
+	},
+	{
+		.id = SBI_FWFT_SHADOW_STACK,
+		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, shadow_stack.enable) /
+				 sizeof(unsigned long),
+		.supported = kvm_sbi_fwft_shadow_stack_supported,
+		.reset = kvm_sbi_fwft_reset_shadow_stack,
+		.set = kvm_sbi_fwft_set_shadow_stack,
+		.get = kvm_sbi_fwft_get_shadow_stack,
+	},
 	{
 		.id = SBI_FWFT_PTE_AD_HW_UPDATING,
 		.first_reg_num = offsetof(struct kvm_riscv_sbi_fwft, pte_ad_hw_updating.enable) /
-- 
2.54.0



From inochiama at gmail.com  Sun Jun  7 01:11:04 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Sun,  7 Jun 2026 16:11:04 +0800
Subject: [PATCH v3 8/8] KVM: riscv: selftests: add Zicfiss/Zicfilp extension to get-reg-list test
In-Reply-To: <20260607081105.993908-1-inochiama@gmail.com>
References: <20260607081105.993908-1-inochiama@gmail.com>
Message-ID: <20260607081105.993908-9-inochiama@gmail.com>

The KVM RISC-V allows Zicfiss/Zicfilp extensions for Guest/VM so
add these extensions to get-reg-list test.

Assisted-by: YuanSheng:claude-4.7-opus
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 .../selftests/kvm/riscv/get-reg-list.c        | 67 +++++++++++++++++++
 1 file changed, 67 insertions(+)

diff --git a/tools/testing/selftests/kvm/riscv/get-reg-list.c b/tools/testing/selftests/kvm/riscv/get-reg-list.c
index 94e33b2ee796..5963f62ce730 100644
--- a/tools/testing/selftests/kvm/riscv/get-reg-list.c
+++ b/tools/testing/selftests/kvm/riscv/get-reg-list.c
@@ -90,6 +90,8 @@ bool filter_reg(__u64 reg)
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOP:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOZ:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICCRSE:
+	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICFILP:
+	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICFISS:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICNTR:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICOND:
 	case KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICSR:
@@ -358,6 +360,8 @@ static const char *core_id_to_str(const char *prefix, __u64 id)
 	"KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_REG(" #csr ")"
 #define RISCV_CSR_SMSTATEEN(csr) \
 	"KVM_REG_RISCV_CSR_SMSTATEEN | KVM_REG_RISCV_CSR_REG(" #csr ")"
+#define RISCV_CSR_ZICFISS(csr) \
+	"KVM_REG_RISCV_CSR_ZICFISS | KVM_REG_RISCV_CSR_REG(" #csr ")"
 
 static const char *general_csr_id_to_str(__u64 reg_off)
 {
@@ -425,6 +429,18 @@ static const char *smstateen_csr_id_to_str(__u64 reg_off)
 	return NULL;
 }
 
+static const char *zicfiss_csr_id_to_str(__u64 reg_off)
+{
+	/* reg_off is the offset into struct kvm_riscv_cfi_csr */
+	switch (reg_off) {
+	case KVM_REG_RISCV_CSR_ZICFISS_REG(ssp):
+		return RISCV_CSR_ZICFISS(ssp);
+	}
+
+	TEST_FAIL("Unknown zicfiss csr reg: 0x%llx", reg_off);
+	return NULL;
+}
+
 static const char *csr_id_to_str(const char *prefix, __u64 id)
 {
 	__u64 reg_off = id & ~(REG_MASK | KVM_REG_RISCV_CSR);
@@ -441,6 +457,8 @@ static const char *csr_id_to_str(const char *prefix, __u64 id)
 		return aia_csr_id_to_str(reg_off);
 	case KVM_REG_RISCV_CSR_SMSTATEEN:
 		return smstateen_csr_id_to_str(reg_off);
+	case KVM_REG_RISCV_CSR_ZICFISS:
+		return zicfiss_csr_id_to_str(reg_off);
 	}
 
 	return strdup_printf("%lld | %lld /* UNKNOWN */", reg_subtype, reg_off);
@@ -585,6 +603,8 @@ static const char *isa_ext_single_id_to_str(__u64 reg_off)
 		KVM_ISA_EXT_ARR(ZICBOP),
 		KVM_ISA_EXT_ARR(ZICBOZ),
 		KVM_ISA_EXT_ARR(ZICCRSE),
+		KVM_ISA_EXT_ARR(ZICFILP),
+		KVM_ISA_EXT_ARR(ZICFISS),
 		KVM_ISA_EXT_ARR(ZICNTR),
 		KVM_ISA_EXT_ARR(ZICOND),
 		KVM_ISA_EXT_ARR(ZICSR),
@@ -748,6 +768,12 @@ static const char *sbi_fwft_id_to_str(__u64 reg_off)
 	case 6: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.enable)";
 	case 7: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.flags)";
 	case 8: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.value)";
+	case 9: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.enable)";
+	case 10: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.flags)";
+	case 11: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.value)";
+	case 12: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.enable)";
+	case 13: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.flags)";
+	case 14: return "KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.value)";
 	}
 	return strdup_printf("KVM_REG_RISCV_SBI_FWFT | %lld /* UNKNOWN */", reg_off);
 }
@@ -954,6 +980,18 @@ static __u64 sbi_fwft_pte_ad_hw_updating_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(pte_ad_hw_updating.value),
 };
 
+static __u64 sbi_fwft_landing_pad_regs[] = {
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.enable),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.flags),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(landing_pad.value),
+};
+
+static __u64 sbi_fwft_shadow_stack_regs[] = {
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.enable),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.flags),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_SBI_STATE | KVM_REG_RISCV_SBI_FWFT | KVM_REG_RISCV_SBI_FWFT_REG(shadow_stack.value),
+};
+
 static __u64 zicbom_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CONFIG | KVM_REG_RISCV_CONFIG_REG(zicbom_block_size),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOM,
@@ -969,6 +1007,11 @@ static __u64 zicboz_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICBOZ,
 };
 
+static __u64 zicfiss_regs[] = {
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_ZICFISS | KVM_REG_RISCV_CSR_ZICFISS_REG(ssp),
+	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_ISA_EXT | KVM_REG_RISCV_ISA_SINGLE | KVM_RISCV_ISA_EXT_ZICFISS,
+};
+
 static __u64 aia_regs[] = {
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(siselect),
 	KVM_REG_RISCV | KVM_REG_SIZE_ULONG | KVM_REG_RISCV_CSR | KVM_REG_RISCV_CSR_AIA | KVM_REG_RISCV_CSR_AIA_REG(iprio1),
@@ -1220,6 +1263,8 @@ KVM_ISA_EXT_SUBLIST_CONFIG(zicbom, ZICBOM);
 KVM_ISA_EXT_SUBLIST_CONFIG(zicbop, ZICBOP);
 KVM_ISA_EXT_SUBLIST_CONFIG(zicboz, ZICBOZ);
 KVM_ISA_EXT_SIMPLE_CONFIG(ziccrse, ZICCRSE);
+KVM_ISA_EXT_SIMPLE_CONFIG(zicfilp, ZICFILP);
+KVM_ISA_EXT_SUBLIST_CONFIG(zicfiss, ZICFISS);
 KVM_ISA_EXT_SIMPLE_CONFIG(zicntr, ZICNTR);
 KVM_ISA_EXT_SIMPLE_CONFIG(zicond, ZICOND);
 KVM_ISA_EXT_SIMPLE_CONFIG(zicsr, ZICSR);
@@ -1279,6 +1324,24 @@ static struct vcpu_reg_list config_sbi_fwft_pte_ad_hw_updating = {
 	},
 };
 
+static struct vcpu_reg_list config_sbi_fwft_landing_pad = {
+	.sublists = {
+		SUBLIST_BASE,
+		SUBLIST_ISA(zicfilp, ZICFILP),
+		SUBLIST_SBI(fwft_landing_pad, FWFT),
+		{0},
+	},
+};
+
+static struct vcpu_reg_list config_sbi_fwft_shadow_stack = {
+	.sublists = {
+		SUBLIST_BASE,
+		SUBLIST_ISA(zicfiss, ZICFISS),
+		SUBLIST_SBI(fwft_shadow_stack, FWFT),
+		{0},
+	},
+};
+
 struct vcpu_reg_list *vcpu_configs[] = {
 	&config_sbi_base,
 	&config_sbi_sta,
@@ -1289,6 +1352,8 @@ struct vcpu_reg_list *vcpu_configs[] = {
 	&config_sbi_fwft_misaligned_deleg,
 	&config_sbi_fwft_pointer_masking,
 	&config_sbi_fwft_pte_ad_hw_updating,
+	&config_sbi_fwft_landing_pad,
+	&config_sbi_fwft_shadow_stack,
 	&config_aia,
 	&config_fp_f,
 	&config_fp_d,
@@ -1332,6 +1397,8 @@ struct vcpu_reg_list *vcpu_configs[] = {
 	&config_zicbop,
 	&config_zicboz,
 	&config_ziccrse,
+	&config_zicfilp,
+	&config_zicfiss,
 	&config_zicntr,
 	&config_zicond,
 	&config_zicsr,
-- 
2.54.0



From krzk at kernel.org  Sun Jun  7 01:25:11 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Sun, 7 Jun 2026 10:25:11 +0200
Subject: [PATCH v4 1/3] dt-bindings: arm: sunxi: Add NetCube Systems
 OpenNMC (dobermann)
In-Reply-To: <20260606205452.2386930-2-lukas.schmid@netcube.li>
References: <20260606205452.2386930-1-lukas.schmid@netcube.li>
 <20260606205452.2386930-2-lukas.schmid@netcube.li>
Message-ID: <20260607-fractal-turtle-of-valor-db1c13@quoll>

On Sat, Jun 06, 2026 at 10:54:41PM +0200, Lukas Schmid wrote:
> The OpenNMC is an open replacement for APC SmartSlot management cards
> based on the Nagami System-on-Module.
> 
> Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
> ---
>  Documentation/devicetree/bindings/arm/sunxi.yaml | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>

Best regards,
Krzysztof



From docular.xu at gmail.com  Sun Jun  7 10:41:29 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Sun, 07 Jun 2026 13:41:29 -0400
Subject: [PATCH 0/2] dt-bindings: Add SpacemiT K1 PDMA request-number
 header and use it in DT
Message-ID: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>

Currently, K1 device trees specify PDMA peripheral requests as raw numbers.
Add a dt-bindings header naming those request lines, point the binding's
dma-cells description at it, and convert the current user (the K1 SPI3
node) to the new K1_PDMA_* macros.

Patch 1 adds include/dt-bindings/dma/spacemit,k1-pdma.h with the
  K1_PDMA_* request-number macros and update the spacemit,k1-pdma binding's
  dma-cells description.
Patch 2 updates the current pdma user in k1.dtsi to use these request
  number macros.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
Guodong Xu (2):
      dt-bindings: dmaengine: Add SpacemiT K1 PDMA request numbers
      riscv: dts: spacemit: Use symbolic PDMA request numbers on K1

 .../devicetree/bindings/dma/spacemit,k1-pdma.yaml  |  4 +-
 arch/riscv/boot/dts/spacemit/k1.dtsi               |  3 +-
 include/dt-bindings/dma/spacemit,k1-pdma.h         | 56 ++++++++++++++++++++++
 3 files changed, 61 insertions(+), 2 deletions(-)
---
base-commit: 793cc54475b49b5b558902b5c13e4bfe66530a50
change-id: 20260607-b4-k1-pdma-req-macros-8d276d0126df

Best regards,
--  
Guodong Xu <docular.xu at gmail.com>



From docular.xu at gmail.com  Sun Jun  7 10:41:30 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Sun, 07 Jun 2026 13:41:30 -0400
Subject: [PATCH 1/2] dt-bindings: dmaengine: Add SpacemiT K1 PDMA request
 numbers
In-Reply-To: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>
References: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>
Message-ID: <20260607-b4-k1-pdma-req-macros-v1-1-5b2a3955007c@gmail.com>

Add a dt-bindings header that gives symbolic names to the SpacemiT K1
PDMA request lines of the non-secure peripherals. Device trees can use
these K1_PDMA_* macros instead of magic numbers.

Point the spacemit,k1-pdma binding's #dma-cells description at the new
header.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
 .../devicetree/bindings/dma/spacemit,k1-pdma.yaml  |  4 +-
 include/dt-bindings/dma/spacemit,k1-pdma.h         | 56 ++++++++++++++++++++++
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
index ec06235baf5ca..0d4ac9849e27b 100644
--- a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
+++ b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
@@ -35,7 +35,9 @@ properties:
   '#dma-cells':
     const: 1
     description:
-      The DMA request number for the peripheral device.
+      The single cell is the DMA request number for the peripheral device.
+      See <dt-bindings/dma/spacemit,k1-pdma.h> for the list of valid request
+      numbers.
 
 required:
   - compatible
diff --git a/include/dt-bindings/dma/spacemit,k1-pdma.h b/include/dt-bindings/dma/spacemit,k1-pdma.h
new file mode 100644
index 0000000000000..491976516550a
--- /dev/null
+++ b/include/dt-bindings/dma/spacemit,k1-pdma.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * This header provides DMA request number for non-secure peripherals of
+ * SpacemiT K1 PDMA.
+ *
+ * Copyright (c) 2026 Guodong Xu <docular.xu at gmail.com>
+ */
+
+#ifndef _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
+#define _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
+
+#define K1_PDMA_UART0_TX	3
+#define K1_PDMA_UART0_RX	4
+#define K1_PDMA_UART2_TX	5
+#define K1_PDMA_UART2_RX	6
+#define K1_PDMA_UART3_TX	7
+#define K1_PDMA_UART3_RX	8
+#define K1_PDMA_UART4_TX	9
+#define K1_PDMA_UART4_RX	10
+#define K1_PDMA_I2C0_TX		11
+#define K1_PDMA_I2C0_RX		12
+#define K1_PDMA_I2C1_TX		13
+#define K1_PDMA_I2C1_RX		14
+#define K1_PDMA_I2C2_TX		15
+#define K1_PDMA_I2C2_RX		16
+#define K1_PDMA_I2C4_TX		17
+#define K1_PDMA_I2C4_RX		18
+#define K1_PDMA_SPI3_TX		19
+#define K1_PDMA_SPI3_RX		20
+#define K1_PDMA_I2S0_TX		21
+#define K1_PDMA_I2S0_RX		22
+#define K1_PDMA_I2S1_TX		23
+#define K1_PDMA_I2S1_RX		24
+#define K1_PDMA_UART5_TX	25
+#define K1_PDMA_UART5_RX	26
+#define K1_PDMA_UART6_TX	27
+#define K1_PDMA_UART6_RX	28
+#define K1_PDMA_UART7_TX	29
+#define K1_PDMA_UART7_RX	30
+#define K1_PDMA_UART8_TX	31
+#define K1_PDMA_UART8_RX	32
+#define K1_PDMA_UART9_TX	33
+#define K1_PDMA_UART9_RX	34
+#define K1_PDMA_I2C5_TX		35
+#define K1_PDMA_I2C5_RX		36
+#define K1_PDMA_I2C6_TX		37
+#define K1_PDMA_I2C6_RX		38
+#define K1_PDMA_I2C7_TX		39
+#define K1_PDMA_I2C7_RX		40
+#define K1_PDMA_I2C8_TX		41
+#define K1_PDMA_I2C8_RX		42
+#define K1_PDMA_CAN0_RX		43
+#define K1_PDMA_QSPI_RX		44
+#define K1_PDMA_QSPI_TX		45
+
+#endif /* _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_ */

-- 
2.43.0



From docular.xu at gmail.com  Sun Jun  7 10:41:31 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Sun, 07 Jun 2026 13:41:31 -0400
Subject: [PATCH 2/2] riscv: dts: spacemit: Use symbolic PDMA request
 numbers on K1
In-Reply-To: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>
References: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>
Message-ID: <20260607-b4-k1-pdma-req-macros-v1-2-5b2a3955007c@gmail.com>

The K1 SPI3 node's "dmas" property hard-codes its PDMA request numbers.
Include <dt-bindings/dma/spacemit,k1-pdma.h> and use the K1_PDMA_SPI3_RX/TX
macros instead, for better code readability and easy for future
maintenance.

No functional change.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
 arch/riscv/boot/dts/spacemit/k1.dtsi | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index 08a0f28d011fe..c413a64d5560c 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/spacemit,k1-syscon.h>
+#include <dt-bindings/dma/spacemit,k1-pdma.h>
 #include <dt-bindings/phy/phy.h>
 
 /dts-v1/;
@@ -1094,7 +1095,7 @@ spi3: spi at d401c000 {
 				clock-names = "core", "bus";
 				resets = <&syscon_apbc RESET_SSP3>;
 				interrupts = <55>;
-				dmas = <&pdma 20>, <&pdma 19>;
+				dmas = <&pdma K1_PDMA_SPI3_RX>, <&pdma K1_PDMA_SPI3_TX>;
 				dma-names = "rx", "tx";
 				status = "disabled";
 			};

-- 
2.43.0



From mssola at mssola.com  Sun Jun  7 13:38:05 2026
From: mssola at mssola.com (=?utf-8?Q?Miquel_Sabat=C3=A9_Sol=C3=A0?=)
Date: Sun, 07 Jun 2026 22:38:05 +0200
Subject: [PATCH RESEND] riscv: enable HAVE_CMPXCHG_{DOUBLE,LOCAL}
In-Reply-To: <f63eefc9-769d-409c-4099-274254432129@kernel.org> (Paul
	Walmsley's message of "Sat, 6 Jun 2026 18:50:55 -0600 (MDT)")
References: <20260605141247.253315-1-mssola@mssola.com>
	<f63eefc9-769d-409c-4099-274254432129@kernel.org>
Message-ID: <87a4t6w0gi.fsf@>

Hi,

Paul Walmsley @ 2026-06-06 18:50 -06:

> Hi,
>
> On Fri, 5 Jun 2026, Miquel Sabat? Sol? wrote:
>
>> Support for atomic Compare-And-Swap instructions has been in the RISC-V
>> port of the Linux kernel for a long time. That being said, we apparently
>> never bothered to set HAVE_CMPXCHG_DOUBLE and HAVE_CMPXCHG_LOCAL in the
>> Kconfig, despite having all the framework to support them.
>>
>> Signed-off-by: Miquel Sabat? Sol? <mssola at mssola.com>
>> ---
>> This is a resend of [1], rebased on top of the latest commit from the
>> for-next branch.
>>
>> I have built this patch with multiple configurations and ran it with KVM
>> (the VisionFive2 board that I have lacks the needed extensions). All seems
>> to work, but I do wonder if we did not enable these for a reason or this
>> just slipped through. So far in the code I believe everything is in place,
>> and I haven't seen any commit in the git log stating otherwise.
>>
>> [1] https://lore.kernel.org/all/20260220074449.8526-1-mssola at mssola.com/
>
> Thanks for the patch.  Your comments above are why I've been hesitant to
> merge it.  I'm not aware of any publicly available hardware that supports
> Zacas/Zabha.  No one has stepped forward to provide any Tested-by:s on
> hardware that hasn't been released yet.  You mention that you tested on
> your VisionFive2 board, but it would not have exercised those code paths.

No, I mention that I ran it _only_ on KVM, as my VisionFive2 board lacks
these extensions and hence I couldn't possible have tested this there :)

>
> Of course, we already have Zacas/Zabha support, merged back in 2024, in
> cmpxchg.h.  I assume (?) that it was tested in QEMU, but I don't see any
> comments about that in the patch series.  No one sent any Tested-by:s
> then, either.
>
> It would be good if you (and ideally others) could put this patch through
> some testing on QEMU with Zacas and Zabha enabled, before we merge it.
> The affected code paths for HAVE_CMPXCHG_LOCAL seem to primarily involve
> per-CPU counters and MM zone counters, so those would be the areas to
> focus.  HAVE_CMPXCHG_DOUBLE seems to do nothing useful other than
> preventing the AMD IOMMU driver from being selected if it's not present,
> so that part of the patch seems fairly useless.  In fact I'd suggest
> dropping that from the patch and just sending a separate patch to remove
> HAVE_CMPXCHG_DOUBLE from the kernel completely.

To be fair, on QEMU I only "tested" it by booting it, running a few
things for some time and ensuring that nothing got totally broken in the
process while taking a look at the kernel logs.

In any case, let me double check with QEMU with these extensions enabled
and I'll try to be more thorough about it. I'll do just that whenever I
have some spare time during the following week :)

As for HAVE_CMPXCHG_DOUBLE, removing it makes sense. Let me just take
another look and I will send a separate patch whenever I'm ready for it.

>
>
> - Paul

Thanks for your input!
Miquel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 897 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260607/4ccc02e4/attachment.sig>

From linux at roeck-us.net  Sun Jun  7 16:56:39 2026
From: linux at roeck-us.net (Guenter Roeck)
Date: Sun, 7 Jun 2026 16:56:39 -0700
Subject: [RFC] hwmon: add a driver for the temp/voltage sensor on
 PolarFire SoC
In-Reply-To: <20260528-defog-lasso-84891a72775a@spud>
References: <20260527-earring-bully-eb4a268c2e68@spud>
 <b49d4781-0827-4f26-9ca2-ccd177f90237@roeck-us.net>
 <20260528-defog-lasso-84891a72775a@spud>
Message-ID: <73557336-94d6-4eef-bcc3-da59af188f86@roeck-us.net>

On 5/28/26 15:34, Conor Dooley wrote:
> On Wed, May 27, 2026 at 09:07:20PM -0700, Guenter Roeck wrote:
>> On Wed, May 27, 2026 at 10:06:11AM +0100, Conor Dooley wrote:
>>> From: Lars Randers <lranders at mail.dk>
>>>
>>> Add a driver for the temperature and voltage sensors on PolarFire SoC.
>>> The temperature reports how hot the die is, and the voltages are the
>>> SoC's 1.05, 1.8 and 2.5 volt rails respectively.
>>>
>>> The hardware supports alarms in theory, but there is an unconfirmed
>>> erratum that prevents clearing them once triggered, so no support is
>>> added.
>>>
>>> The hardware measures voltage with 16 bits, of which 1 is a sign bit and
>>> the remainder holds the voltage as a fixed point integer value. It's
>>> improbable that the hardware will work if the voltages are negative, so
>>> the driver ignores the sign bits.
>>>
>>> There's no dt support etc here because this is the child of a simple-mfd
>>> syscon.
>>>
>>> Signed-off-by: Lars Randers <lranders at mail.dk>
>>> Co-developed-by: Conor Dooley <conor.dooley at microchip.com>
>>> Signed-off-by: Conor Dooley <conor.dooley at microchip.com>
>>> ---
>>> Guenter, there's one question here about the unit that update_interval
>>> is in, I didn't see anyone else using us, but I assume that's okay since
>>> the resolution that ms would give would be 8 steps only?
>>> RFC cos the question is also in the driver as a comment.
>>>
>>
>> That just came up in a different context. We'll add a new standard attribute
>> update_interval_us. The existing attribute MUST use ms. Everything else
>> would be an ABI violation.
> 
> Cool. Sounds like Ferdinand is working on that based on the other
> thread.
> 
> Do you think I should support both update_interval and update_interval_us in
> this driver?
> 

I have been thinking about only supporting one for a given driver, but that
doesn't work because there are existing drivers which would benefit from
supporting microsecond-based intervals, so both it is (unless you want to
wait for _us support to be available and then just support that).

> If yes, should I do the ms version now and add the us version later once
> Ferdinand's work is complete?
> 

Yes, that is what I would recommend.

Thanks,
Guenter



From troy.mitchell at linux.dev  Sun Jun  7 18:21:01 2026
From: troy.mitchell at linux.dev (Troy Mitchell)
Date: Mon, 08 Jun 2026 09:21:01 +0800
Subject: [PATCH v3] riscv: disable local interrupts and stop other CPUs
 before reboot/shutdown
In-Reply-To: <DI5M2DY419FY.7DUCXZDHR22V@linux.dev>
References: <20260330-v7-0-rc1-rv-dis-int-before-restart-v3-1-5a0577fcd136@linux.spacemit.com> <DI5M2DY419FY.7DUCXZDHR22V@linux.dev>
Message-ID: <DJ39V0ZUPDG5.3UJO3VMV0J502@linux.dev>

On Wed Apr 29, 2026 at 7:44 PM CST, Troy Mitchell wrote:
> Hi all,
>
> On Mon Mar 30, 2026 at 5:58 PM CST, Troy Mitchell wrote:
>> From: Troy Mitchell <troy.mitchell at linux.dev>
>>
>> Currently, the RISC-V implementation of machine_restart(), machine_halt(),
>> and machine_power_off() invokes the kernel teardown chains (e.g.,
>> do_kernel_restart()) with local interrupts enabled and other CPUs still
>> running.
>>
>> This implementation fails to provide a deterministic execution environment
>> for registered handlers in the restart or power-off notifier chains. These
>> chains are intended to be executed in a strict atomic and single-threaded
>> context.
>>
>> Specifically, under CONFIG_PREEMPT_RCU, rcu_read_lock() does not increment
>> the preempt_count. If local interrupts remain enabled, the environment
>> is not guaranteed to be atomic. This can lead to a context misidentification
>> within generic kernel teardown code, causing it to incorrectly enter
>> non-atomic paths (such as attempting to acquire sleeping locks), which
>> results in fatal "scheduling while atomic" splats or system hangs.
>>
>> Additionally, stopping other CPUs ensures the primary CPU has exclusive
>> access to the hardware state during the final teardown phase, preventing
>> unpredictable interference from other active cores.
>>
>> Align RISC-V with other major architectures by disabling local interrupts
>> and stopping other CPUs at the beginning of the shutdown sequences. This
>> guarantees the architectural expectations of the kernel's restart and
>> power-off handlers are met.
>>
>> Signed-off-by: Troy Mitchell <troy.mitchell at linux.dev>
>> Tested-by: Aurelien Jarno <aurelien at aurel32.net>
> Gentle ping on this patch. Is there anything I should change or any
> concerns with the approach?
Just a gentle ping on this series. 

Please let me know if anyone has any feedback or if there is anything 
I should update.

                                  - Troy


From troy.mitchell at linux.dev  Sun Jun  7 18:22:03 2026
From: troy.mitchell at linux.dev (Troy Mitchell)
Date: Mon, 08 Jun 2026 09:22:03 +0800
Subject: [PATCH v2] riscv: mm: fix SWIOTLB initialization for systems
 with DRAM above 4GB
In-Reply-To: <20260429-fix-riscv-swiotlb-v2-1-fa99dfdfc94d@linux.dev>
References: <20260429-fix-riscv-swiotlb-v2-1-fa99dfdfc94d@linux.dev>
Message-ID: <DJ39VTKU26KY.108UFYXIALHBC@linux.dev>

On Wed Apr 29, 2026 at 7:41 PM CST, Troy Mitchell wrote:
> On RISC-V platforms where the entire physical memory (DRAM) resides
> above the 32-bit address space (i.e., above dma32_phys_limit), the
> current SWIOTLB initialization logic fails.
>
> This patch addresses two interconnected issues on such platforms:
>
> 1. Incorrect 32-bit DMA bounce assumption:
> The existing condition `max_pfn > PFN_DOWN(dma32_phys_limit)` assumes
> that a 32-bit DMA bounce buffer is required simply because the maximum
> PFN exceeds the 32-bit limit. However, if all DRAM starts above 4GB,
> no memory exists below the limit to satisfy this allocation. Fix
> this by adding a check to ensure `memblock_start_of_DRAM()` is actually
> below the 32-bit limit before enforcing 32-bit SWIOTLB.
>
> 2. kmalloc() bounce buffer allocation failure on non-coherent systems:
> For non-coherent hardware, a bounce buffer is still mandatory for
> cache-line-aligned kmalloc(), even if 32-bit DMA bouncing is skipped.
> Without the `SWIOTLB_ANY` flag, swiotlb_init() defaults to allocating
> from low memory, which fails completely when DRAM only exists in high
> memory. By appending `SWIOTLB_ANY` to swiotlb_flags, the allocator is
> permitted to allocate this alignment buffer from high memory.
>
> With this patch, systems with non-coherent DMA and DRAM entirely above
> 4GB can successfully map the software IO TLB in high memory and boot
> normally.
>
> Tested-by: Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>
> Signed-off-by: Troy Mitchell <troy.mitchell at linux.dev>
Just a gentle ping on this series. 

Please let me know if anyone has any feedback or if there is anything 
I should update.

                                  - Troy


From wangruikang at iscas.ac.cn  Sun Jun  7 19:24:33 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Mon, 8 Jun 2026 10:24:33 +0800
Subject: [PATCH v3] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
In-Reply-To: <da19ffcf-8042-4f96-9c2d-649468dc6a0a@kernel.org>
References: <20260605-mark-after-vmemmap-populate-v3-1-a06001ac9264@iscas.ac.cn>
 <da19ffcf-8042-4f96-9c2d-649468dc6a0a@kernel.org>
Message-ID: <953d7a60-456d-4629-b133-afce62cc5b3e@iscas.ac.cn>

On 6/5/26 17:16, David Hildenbrand (Arm) wrote:
> On 6/5/26 07:23, Vivian Wang wrote:
>> section_activate() does not flush TLB after populating new vmemmap
>> pages. On most architectures, this is okay. However it is a problem on
>> RISC-V since there the TLB caching non-present entries is permitted,
>> which causes spurious faults on some hardwares.
>>
>> This seems to be most easily reproduced with DEBUG_VM=y and
>> PAGE_POISONING=y, which causes these newly mapped struct pages to be
>> poisoned i.e. written to immediately after mapping.
>>
>> Add a hook vmemmap_populate_finalize() in __populate_section_memmap()
>> after population, to allow architectures to handle such situations as
>> needed. Then implement it on RISC-V to arrange for the existing
>> exception handler code to deal with these faults if they happen.
>>
>> Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
>> ---
>> Depends on my earlier kfence fixes for mark_new_valid_map() [1].
>>
>> Found while testing AMD_HSA/ZONE_DEVICE on SpacemiT K3. Using
>> ZONE_DEVICE requires another fix [2].
>>
>> [1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn
>> [2]: https://lore.kernel.org/linux-riscv/20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd at iscas.ac.cn
>> ---
>> Changes in v3:
>> - Merged back into one patch (Mike)
>> - (No code changes otherwise.)
>> - Link to v2: https://patch.msgid.link/20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434 at iscas.ac.cn
>>
>> Changes in v2:
>> - Split patch in two, hook point and riscv hook 
>> - Explain hook necessity in patch 1 message (Mike)
>> - Make hook #define based (Mike)
>> - Call finalize hook only on populate success
>> - Link to v1: https://patch.msgid.link/20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16 at iscas.ac.cn
>> ---
>>  arch/riscv/include/asm/pgtable.h | 4 ++++
>>  arch/riscv/mm/init.c             | 6 ++++++
>>  mm/sparse-vmemmap.c              | 8 ++++++++
>>  3 files changed, 18 insertions(+)
>>
>> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
>> index a1a7c6520a09..aa0f50e3d534 100644
>> --- a/arch/riscv/include/asm/pgtable.h
>> +++ b/arch/riscv/include/asm/pgtable.h
>> @@ -1243,6 +1243,10 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
>>  #define TASK_SIZE	FIXADDR_START
>>  #endif
>>  
>> +/* Needed on SPARSEMEM_VMEMMAP */
>> +#define vmemmap_populate_finalize vmemmap_populate_finalize
>> +void __meminit vmemmap_populate_finalize(void);
>> +
>>  #else /* CONFIG_MMU */
>>  
>>  #define PAGE_SHARED		__pgprot(0)
>> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
>> index 706f43523935..cf9ae4099f82 100644
>> --- a/arch/riscv/mm/init.c
>> +++ b/arch/riscv/mm/init.c
>> @@ -1360,6 +1360,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
>>  	 */
>>  	return vmemmap_populate_hugepages(start, end, node, altmap);
>>  }
>> +
>> +void __meminit vmemmap_populate_finalize(void)
>> +{
>> +	/* Avoid faults on cached non-present TLB entries. */
>> +	mark_new_valid_map();
>> +}
>>  #endif
> How does mark_new_valid_map() handle concurrent access?
>
> There is some comment in there, but I am not sure if that actually implies that
> mark_new_valid_map() can be called concurrently from arbitrary context?

AFAICT, yes, it is intended to be used concurrently from arbitrary
context, and this is why I used them.

I had not originally written the code, so some riscv maintainer can
maybe chime in on this, but as I understand it the idea is that we only
ever set bits in the bitmap in mark_new_valid_map() while "allocating",
whereas the assembly code in handle_exception in
arch/riscv/kernel/entry.S only ever clears individual bits. So at least
the access to the bitmap itself should be fine.

This was added in commit 503638e0babf ("riscv: Stop emitting preventive
sfence.vma for new vmalloc mappings").

Do you think the mark_new_valid_map() function needs extra
synchronization like smp_wmb()?

Regards,
Vivian "dramforever" Wang



From liangzhen at linux.spacemit.com  Mon Jun  8 00:28:10 2026
From: liangzhen at linux.spacemit.com (Zane Leung)
Date: Mon, 8 Jun 2026 15:28:10 +0800
Subject: [RFC PATCH 00/12] Add Linux RISC-V trace support via CoreSight
In-Reply-To: <20260414034153.3272485-1-liangzhen@linux.spacemit.com>
References: <20260414034153.3272485-1-liangzhen@linux.spacemit.com>
Message-ID: <5C63EC7A33D2DA48+643f07be-c1e1-4527-9d4a-17faf646a8f5@linux.spacemit.com>

Hi, all
I plan to extracting CoreSight's architecture-independent framework code
into a shared layer (drivers/hwtracing/trace-common/) to support multiple
trace implementations (ARM CoreSight, RISC-V trace, etc.).

? ## Proposed Structure

? drivers/hwtracing/
? ??? trace-common/? ? ? ? ? # New: Generic framework layer
? ?? ???? trace-core.c? ? ? ?# Device reg, path building/enable/disable
? ?? ???? trace-core.h? ? ? ?# Public interfaces
? ?? ???? Makefile/Kconfig (CONFIG_TRACE_FRAMEWORK)
? ?
? ??? coresight/? ? ? ? ? ? ?# Modified: ARM-specific only
? ?? ???? coresight-core.c? ?# ARM CTI, claim/disclaim, module init
? ?? ???? Makefile/Kconfig? ?# select TRACE_FRAMEWORK
? ?? ???? [existing ARM drivers]
? ?
? ??? rvtrace/? ? ? ? ? ? ? ?# New: RISC-V trace
? ? ? ??? [RISC-V components]
? ? ? ??? Makefile/Kconfig? ?# select TRACE_FRAMEWORK

Is this architectural direction acceptable? Any comments or suggestions are welcome.



From ruanjinjie at huawei.com  Mon Jun  8 00:34:52 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:52 +0800
Subject: [PATCH v16 03/10] crash: Add crash_prepare_headers() to exclude crash kernel memory
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-4-ruanjinjie@huawei.com>

The crash memory alloc, and the exclude of crashk_res, crashk_low_res
and crashk_cma memory are almost identical across different architectures,
handling them in the crash core would eliminate a lot of duplication, so
add crash_prepare_headers() helper to handle them in the common code.

To achieve the above goal, three architecture-specific functions are
introduced:

- arch_get_system_nr_ranges(). Pre-counts the max number of memory ranges.

- arch_crash_populate_cmem(). Collects the memory ranges and fills them
  into cmem.

- arch_crash_exclude_ranges(). Architecture's additional crash memory
  ranges exclusion, defaulting to empty.

Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 include/linux/crash_core.h |  5 +++
 kernel/crash_core.c        | 82 ++++++++++++++++++++++++++++++++++++--
 2 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index c1dee3f971a9..583ffcc703d4 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -59,6 +59,8 @@ extern int crash_exclude_mem_range(struct crash_mem *mem,
 				   unsigned long long mend);
 extern int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
 				       void **addr, unsigned long *sz);
+extern int crash_prepare_headers(int need_kernel_map, void **addr,
+				 unsigned long *sz, unsigned long *nr_mem_ranges);
 
 struct kimage;
 struct kexec_segment;
@@ -76,6 +78,9 @@ int kexec_should_crash(struct task_struct *p);
 int kexec_crash_loaded(void);
 void crash_save_cpu(struct pt_regs *regs, int cpu);
 extern int kimage_crash_copy_vmcoreinfo(struct kimage *image);
+extern unsigned int arch_get_system_nr_ranges(void);
+extern int arch_crash_populate_cmem(struct crash_mem *cmem);
+extern int arch_crash_exclude_ranges(struct crash_mem *cmem);
 
 #else /* !CONFIG_CRASH_DUMP*/
 struct pt_regs;
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 4f21fc3b108b..481babc29131 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -168,9 +168,6 @@ static inline resource_size_t crash_resource_size(const struct resource *res)
 	return !res->end ? 0 : resource_size(res);
 }
 
-
-
-
 int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
 			  void **addr, unsigned long *sz)
 {
@@ -272,6 +269,85 @@ int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_map,
 	return 0;
 }
 
+static struct crash_mem *alloc_cmem(unsigned int nr_ranges)
+{
+	struct crash_mem *cmem;
+
+	cmem = kvzalloc_flex(*cmem, ranges, nr_ranges);
+	if (!cmem)
+		return NULL;
+
+	cmem->max_nr_ranges = nr_ranges;
+	return cmem;
+}
+
+unsigned int __weak arch_get_system_nr_ranges(void) { return 0; }
+int __weak arch_crash_populate_cmem(struct crash_mem *cmem) { return -1; }
+int __weak arch_crash_exclude_ranges(struct crash_mem *cmem) { return 0; }
+
+static int crash_exclude_core_ranges(struct crash_mem *cmem)
+{
+	int ret, i;
+
+	/* Exclude crashkernel region */
+	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
+	if (ret)
+		return ret;
+
+	if (crashk_low_res.end) {
+		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+		if (ret)
+			return ret;
+	}
+
+	for (i = 0; i < crashk_cma_cnt; ++i) {
+		ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
+					      crashk_cma_ranges[i].end);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+int crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
+			  unsigned long *nr_mem_ranges)
+{
+	unsigned int max_nr_ranges;
+	struct crash_mem *cmem;
+	int ret;
+
+	max_nr_ranges = arch_get_system_nr_ranges();
+	if (!max_nr_ranges)
+		return -ENOMEM;
+
+	cmem = alloc_cmem(max_nr_ranges);
+	if (!cmem)
+		return -ENOMEM;
+
+	ret = arch_crash_populate_cmem(cmem);
+	if (ret)
+		goto out;
+
+	ret = crash_exclude_core_ranges(cmem);
+	if (ret)
+		goto out;
+
+	ret = arch_crash_exclude_ranges(cmem);
+	if (ret)
+		goto out;
+
+	/* Return the computed number of memory ranges, for hotplug usage */
+	if (nr_mem_ranges)
+		*nr_mem_ranges = cmem->nr_ranges;
+
+	ret = crash_prepare_elf64_headers(cmem, need_kernel_map, addr, sz);
+
+out:
+	kvfree(cmem);
+	return ret;
+}
+
 /**
  * crash_exclude_mem_range - exclude a mem range for existing ranges
  * @mem: mem->range contains an array of ranges sorted in ascending order
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:49 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:49 +0800
Subject: [PATCH v16 00/10] arm64/riscv: Add support for crashkernel CMA reservation
Message-ID: <20260608073459.3119290-1-ruanjinjie@huawei.com>

The crash memory allocation, and the exclude of crashk_res, crashk_low_res
and crashk_cma memory are almost identical across different architectures,
This patch set handle them in crash core in a general way, which eliminate
a lot of duplication code.

And add support for crashkernel CMA reservation for arm64 and riscv.

This patch set is rebased on v7.1-rc1.

Basic second kernel boot test were performed on QEMU platforms for x86,
ARM64 and RISC-V architectures with the following parameters:

        "cma=256M crashkernel=4G crashkernel=64M,cma"

For first kernel, there will be such log:

        # dmesg | grep crash
        [    0.000000] crashkernel low memory reserved: 0xe8000000 - 0xf0000000 (128 MB)
        [    0.000000] crashkernel reserved: 0x000000023e600000 - 0x000000033e600000 (4096 MB)
        [    0.000000] crashkernel CMA reserved: 64 MB in 1 ranges

        # dmesg | grep cma
        [    0.000000] cma: Reserved 256 MiB at 0x00000000f0000000
        [    0.000000] cma: Reserved 64 MiB at 0x0000000100000000

For second kernel, there will be such log:

        [    0.000000] OF: fdt: Looking for usable-memory-range property...
        [    0.000000] OF: fdt: cap_mem_regions[0]: base=0x000000023e600000, size=0x0000000100000000
        [    0.000000] OF: fdt: cap_mem_regions[1]: base=0x00000000e8000000, size=0x0000000008000000
        [    0.000000] OF: fdt: cap_mem_regions[2]: base=0x0000000100000000, size=0x0000000004000000

Changes in v16:
- Split out the unrelated bugfixes as Baoquan suggested, which will
  be a separate patch set later.
- Link to v15: https://lore.kernel.org/all/20260601094805.2928614-1-ruanjinjie at huawei.com/

Changes in v15:
- Unify the subject prefix formats as Huacai suggested.
- Fix powerpc pre-existing NULL pointer dereference [Sashiko [1]]
- Fix powerpc pre-existing __merge_memory_ranges() memory range
  truncation [Sashiko [1]].
- Fix pre-existing arm64 CMA page leaks [Sashiko[2]].
- Fix pre-existing crash_load_dm_crypt_keys() Use-After-Free and
  Double Free issue [Sashiko[3]].
- Fix vfree(headers) and uninitialized variables issue
  and simplify the fix [Sashiko[2]].
- As walk_system_ram_res() and for_each_mem_range() use different
  lock, unify and simplify the fix of TOCTOU buffer overflow via memory
  region padding [Sashiko[4]].
- Fix the arm64 crash dump issues in Sashiko[5].
- Link to v14: https://lore.kernel.org/all/20260525084932.934910-1-ruanjinjie at huawei.com/

[1]: https://lore.kernel.org/all/20260525092207.96B9D1F000E9 at smtp.kernel.org/
[2]: https://lore.kernel.org/all/20260525091149.1A1E01F00A3D at smtp.kernel.org/
[3]: https://lore.kernel.org/all/20260525105227.3C2421F000E9 at smtp.kernel.org/
[4]: https://lore.kernel.org/all/20260525095447.944E11F000E9 at smtp.kernel.org/
[5]: https://lore.kernel.org/all/20260525101746.9959D1F000E9 at smtp.kernel.org/

Changes in v14:
- Fix image->elf_headers memory leak during retry loop for arm64 as Sashiko
  AI code review pointed out.
- Solve the hotplug notifier arch_crash_handle_hotplug_event() AA
  self-deadlock problem as Sashiko AI code review pointed out.
- Fix the TOCTOU issue in prepare_elf_headers() by get_online_mems().
- -ENOMEM -> -EAGAIN as Breno suggested.
- Add support for arm64 crash hotplug.
- Link to v13: https://lore.kernel.org/all/20260511030454.1730881-1-ruanjinjie at huawei.com/

Changes in v13:
- Rebased on v7.1-rc1.
- Update the commit message.
- Add Reviewed-by.
- Link to v12: https://lore.kernel.org/all/20260402072701.628293-1-ruanjinjie at huawei.com/

Changes in v12:
- Remove the unused "nr_mem_ranges" for x86.
- Add "Fix crashk_low_res not exclude bug" test log.
- Provide a separate patch for each architecture for using
  crash_prepare_headers(), which will make the review more convenient.
- Add Reviewed-by and Tested-by.
- Link to v11: https://lore.kernel.org/all/20260328074013.3589544-1-ruanjinjie at huawei.com/

Changes in v11:
- Avoid silently drop crash memory if the crash kernel is built without
  CONFIG_CMA.
- Remove unnecessary "cmem->nr_ranges = 0" for arch_crash_populate_cmem()
  as we use kvzalloc().
- Provide a separate patch for each architecture to fix the existing
  buffer overflow issue.
- Add Acked-bys for arm64.

Changes in v10:
- Fix crashk_low_res not excluded bug in the existing
  RISC-V code.
- Fix an existing memory leak issue in the existing PowerPC code.
- Fix the ordering issue of adding CMA ranges to
  "linux,usable-memory-range".
- Fix an existing concurrency issue. A Concurrent memory hotplug may occur
  between reading memblock and attempting to fill cmem during kexec_load()
  for almost all existing architectures.
- Link to v9: https://lore.kernel.org/all/20260323072745.2481719-1-ruanjinjie at huawei.com/

Changes in v9:
- Collect Reviewed-by and Acked-by, and prepare for Sashiko AI review.
- Link to v8: https://lore.kernel.org/all/20260302035315.3892241-1-ruanjinjie at huawei.com/

Changes in v8:
- Fix the build issues reported by kernel test robot and Sourabh.
- Link to v7: https://lore.kernel.org/all/20260226130437.1867658-1-ruanjinjie at huawei.com/

Changes in v7:
- Correct the inclusion of CMA-reserved ranges for kdump kernel in of/kexec
  for arm64 and riscv.
- Add Acked-by.
- Link to v6: https://lore.kernel.org/all/20260224085342.387996-1-ruanjinjie at huawei.com/

Changes in v6:
- Update the crash core exclude code as Mike suggested.
- Rebased on v7.0-rc1.
- Add acked-by.
- Link to v5: https://lore.kernel.org/all/20260212101001.343158-1-ruanjinjie at huawei.com/

Jinjie Ruan (9):
  riscv: kexec_file: Fix crashk_low_res not exclude bug
  crash: Add crash_prepare_headers() to exclude crash kernel memory
  arm64: kexec_file: Use crash_prepare_headers() helper to simplify code
  x86: kexec_file: Use crash_prepare_headers() helper to simplify code
  riscv: kexec_file: Use crash_prepare_headers() helper to simplify code
  LoongArch: kexec_file: Use crash_prepare_headers() helper to simplify
    code
  powerpc/kexec_file: Use crash_exclude_core_ranges() helper
  arm64: kexec_file: Add support for crashkernel CMA reservation
  riscv: kexec_file: Add support for crashkernel CMA reservation

Sourabh Jain (1):
  powerpc/crash: sort crash memory ranges before preparing elfcorehdr

 .../admin-guide/kernel-parameters.txt         |  16 +--
 arch/arm64/kernel/machine_kexec_file.c        |  40 +++----
 arch/arm64/mm/init.c                          |   5 +-
 arch/loongarch/kernel/machine_kexec_file.c    |  40 +++----
 arch/powerpc/include/asm/kexec_ranges.h       |   1 -
 arch/powerpc/kexec/crash.c                    |   5 +-
 arch/powerpc/kexec/ranges.c                   | 101 +-----------------
 arch/riscv/kernel/machine_kexec_file.c        |  39 +++----
 arch/riscv/mm/init.c                          |   5 +-
 arch/x86/kernel/crash.c                       |  89 ++-------------
 drivers/of/fdt.c                              |   9 +-
 drivers/of/kexec.c                            |   9 ++
 include/linux/crash_core.h                    |   9 ++
 include/linux/crash_reserve.h                 |   4 +-
 kernel/crash_core.c                           |  89 ++++++++++++++-
 15 files changed, 180 insertions(+), 281 deletions(-)

-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:51 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:51 +0800
Subject: [PATCH v16 02/10] powerpc/crash: sort crash memory ranges before preparing elfcorehdr
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-3-ruanjinjie@huawei.com>

From: Sourabh Jain <sourabhjain at linux.ibm.com>

During a memory hot-remove event, the elfcorehdr is rebuilt to exclude
the removed memory. While updating the crash memory ranges for this
operation, the crash memory ranges array can become unsorted. This
happens because remove_mem_range() may split a memory range into two
parts and append the higher-address part as a separate range at the end
of the array.

So far, no issues have been observed due to the unsorted crash memory
ranges. However, this could lead to problems once crash memory range
removal is handled by generic code, as introduced in the upcoming
patches in this series.

Currently, powerpc uses a platform-specific function,
remove_mem_range(), to exclude hot-removed memory from the crash memory
ranges. This function performs the same task as the generic
crash_exclude_mem_range() in crash_core.c. The generic helper also
ensures that the crash memory ranges remain sorted. So remove the
redundant powerpc-specific implementation and instead call
crash_exclude_mem_range_guarded() (which internally calls
crash_exclude_mem_range()) to exclude the hot-removed memory ranges.

Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Baoquan he <bhe at redhat.com>
Cc: Jinjie Ruan <ruanjinjie at huawei.com>
Cc: Hari Bathini <hbathini at linux.ibm.com>
Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
Cc: Mahesh Salgaonkar <mahesh at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Cc: Shivang Upadhyay <shivangu at linux.ibm.com>
Cc: linux-kernel at vger.kernel.org
Acked-by: Baoquan He <bhe at redhat.com>
Reviewed-by: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/powerpc/include/asm/kexec_ranges.h |  4 +-
 arch/powerpc/kexec/crash.c              |  5 +-
 arch/powerpc/kexec/ranges.c             | 87 +------------------------
 3 files changed, 7 insertions(+), 89 deletions(-)

diff --git a/arch/powerpc/include/asm/kexec_ranges.h b/arch/powerpc/include/asm/kexec_ranges.h
index 14055896cbcb..ad95e3792d10 100644
--- a/arch/powerpc/include/asm/kexec_ranges.h
+++ b/arch/powerpc/include/asm/kexec_ranges.h
@@ -7,7 +7,9 @@
 void sort_memory_ranges(struct crash_mem *mrngs, bool merge);
 struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges);
 int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
-int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
+int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
+				    unsigned long long mstart,
+				    unsigned long long mend);
 int get_exclude_memory_ranges(struct crash_mem **mem_ranges);
 int get_reserved_memory_ranges(struct crash_mem **mem_ranges);
 int get_crash_memory_ranges(struct crash_mem **mem_ranges);
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index e6539f213b3d..2e88ec5c4356 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -493,7 +493,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
 	struct crash_mem *cmem = NULL;
 	struct kexec_segment *ksegment;
 	void *ptr, *mem, *elfbuf = NULL;
-	unsigned long elfsz, memsz, base_addr, size;
+	unsigned long elfsz, memsz, base_addr, size, end;
 
 	ksegment = &image->segment[image->elfcorehdr_index];
 	mem = (void *) ksegment->mem;
@@ -512,7 +512,8 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
 	if (image->hp_action == KEXEC_CRASH_HP_REMOVE_MEMORY) {
 		base_addr = PFN_PHYS(mn->start_pfn);
 		size = mn->nr_pages * PAGE_SIZE;
-		ret = remove_mem_range(&cmem, base_addr, size);
+		end = base_addr + size - 1;
+		ret = crash_exclude_mem_range_guarded(&cmem, base_addr, end);
 		if (ret) {
 			pr_err("Failed to remove hot-unplugged memory from crash memory ranges\n");
 			goto out;
diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c
index 867135560e5c..6c58bcc3e130 100644
--- a/arch/powerpc/kexec/ranges.c
+++ b/arch/powerpc/kexec/ranges.c
@@ -553,7 +553,7 @@ int get_usable_memory_ranges(struct crash_mem **mem_ranges)
 #endif /* CONFIG_KEXEC_FILE */
 
 #ifdef CONFIG_CRASH_DUMP
-static int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
+int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
 					   unsigned long long mstart,
 					   unsigned long long mend)
 {
@@ -641,89 +641,4 @@ int get_crash_memory_ranges(struct crash_mem **mem_ranges)
 		pr_err("Failed to setup crash memory ranges\n");
 	return ret;
 }
-
-/**
- * remove_mem_range - Removes the given memory range from the range list.
- * @mem_ranges:    Range list to remove the memory range to.
- * @base:          Base address of the range to remove.
- * @size:          Size of the memory range to remove.
- *
- * (Re)allocates memory, if needed.
- *
- * Returns 0 on success, negative errno on error.
- */
-int remove_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size)
-{
-	u64 end;
-	int ret = 0;
-	unsigned int i;
-	u64 mstart, mend;
-	struct crash_mem *mem_rngs = *mem_ranges;
-
-	if (!size)
-		return 0;
-
-	/*
-	 * Memory range are stored as start and end address, use
-	 * the same format to do remove operation.
-	 */
-	end = base + size - 1;
-
-	for (i = 0; i < mem_rngs->nr_ranges; i++) {
-		mstart = mem_rngs->ranges[i].start;
-		mend = mem_rngs->ranges[i].end;
-
-		/*
-		 * Memory range to remove is not part of this range entry
-		 * in the memory range list
-		 */
-		if (!(base >= mstart && end <= mend))
-			continue;
-
-		/*
-		 * Memory range to remove is equivalent to this entry in the
-		 * memory range list. Remove the range entry from the list.
-		 */
-		if (base == mstart && end == mend) {
-			for (; i < mem_rngs->nr_ranges - 1; i++) {
-				mem_rngs->ranges[i].start = mem_rngs->ranges[i+1].start;
-				mem_rngs->ranges[i].end = mem_rngs->ranges[i+1].end;
-			}
-			mem_rngs->nr_ranges--;
-			goto out;
-		}
-		/*
-		 * Start address of the memory range to remove and the
-		 * current memory range entry in the list is same. Just
-		 * move the start address of the current memory range
-		 * entry in the list to end + 1.
-		 */
-		else if (base == mstart) {
-			mem_rngs->ranges[i].start = end + 1;
-			goto out;
-		}
-		/*
-		 * End address of the memory range to remove and the
-		 * current memory range entry in the list is same.
-		 * Just move the end address of the current memory
-		 * range entry in the list to base - 1.
-		 */
-		else if (end == mend)  {
-			mem_rngs->ranges[i].end = base - 1;
-			goto out;
-		}
-		/*
-		 * Memory range to remove is not at the edge of current
-		 * memory range entry. Split the current memory entry into
-		 * two half.
-		 */
-		else {
-			size = mem_rngs->ranges[i].end - end + 1;
-			mem_rngs->ranges[i].end = base - 1;
-			ret = add_mem_range(mem_ranges, end + 1, size);
-		}
-	}
-out:
-	return ret;
-}
 #endif /* CONFIG_CRASH_DUMP */
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:50 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:50 +0800
Subject: [PATCH v16 01/10] riscv: kexec_file: Fix crashk_low_res not exclude bug
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-2-ruanjinjie@huawei.com>

As done in commit 944a45abfabc ("arm64: kdump: Reimplement crashkernel=X")
and commit 4831be702b95 ("arm64/kexec: Fix missing extra range for
crashkres_low.") for arm64, while implementing crashkernel=X,[high,low],
riscv should have excluded the "crashk_low_res" reserved ranges from
the crash kernel memory to prevent them from being exported through
/proc/vmcore, and the exclusion would need an extra crash_mem range.

Just simply tested on qemu with crashkernel=4G with kexec in [1] mentioned
in [2]. And the second kernel can be started normally.

	# dmesg | grep crash
	[    0.000000] crashkernel low memory reserved: 0xf8000000 - 0x100000000 (128 MB)
	[    0.000000] crashkernel reserved: 0x000000017fe00000 - 0x000000027fe00000 (4096 MB)

Cc: Guo Ren <guoren at kernel.org>
Cc: Baoquan He <bhe at redhat.com>
[1]: https://github.com/chenjh005/kexec-tools/tree/build-test-riscv-v2
[2]: https://lore.kernel.org/all/20230726175000.2536220-1-chenjiahao16 at huawei.com/
Fixes: 5882e5acf18d ("riscv: kdump: Implement crashkernel=X,[high,low]")
Reviewed-by: Guo Ren <guoren at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/riscv/kernel/machine_kexec_file.c | 14 +++++++++++---
 1 file changed, 11 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 54e2d9552e93..3f7766057cac 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -61,7 +61,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
 	unsigned int nr_ranges;
 	int ret;
 
-	nr_ranges = 1; /* For exclusion of crashkernel region */
+	nr_ranges = 2; /* For exclusion of crashkernel region */
 	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
 
 	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
@@ -76,8 +76,16 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
 
 	/* Exclude crashkernel region */
 	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (!ret)
-		ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
+	if (ret)
+		goto out;
+
+	if (crashk_low_res.end) {
+		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+		if (ret)
+			goto out;
+	}
+
+	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
 
 out:
 	kfree(cmem);
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:53 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:53 +0800
Subject: [PATCH v16 04/10] arm64: kexec_file: Use crash_prepare_headers() helper to simplify code
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-5-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash
kernel memory in the crash core, which reduce code duplication.

Only the following two architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Use for_each_mem_range() to traverse
  and pre-count the max number of memory ranges.

- arch_crash_populate_cmem(). Use for_each_mem_range to traverse
  and collect the memory ranges and fills them into cmem.

Acked-by: Catalin Marinas <catalin.marinas at arm.com>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/machine_kexec_file.c | 40 ++++++++------------------
 1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index e31fabed378a..b019b31df48c 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -40,46 +40,30 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 }
 
 #ifdef CONFIG_CRASH_DUMP
-static int prepare_elf_headers(void **addr, unsigned long *sz)
+unsigned int arch_get_system_nr_ranges(void)
 {
-	struct crash_mem *cmem;
-	unsigned int nr_ranges;
-	int ret;
-	u64 i;
+	unsigned int nr_ranges = 2; /* for exclusion of crashkernel region */
 	phys_addr_t start, end;
+	u64 i;
 
-	nr_ranges = 2; /* for exclusion of crashkernel region */
 	for_each_mem_range(i, &start, &end)
 		nr_ranges++;
 
-	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
-	if (!cmem)
-		return -ENOMEM;
+	return nr_ranges;
+}
+
+int arch_crash_populate_cmem(struct crash_mem *cmem)
+{
+	phys_addr_t start, end;
+	u64 i;
 
-	cmem->max_nr_ranges = nr_ranges;
-	cmem->nr_ranges = 0;
 	for_each_mem_range(i, &start, &end) {
 		cmem->ranges[cmem->nr_ranges].start = start;
 		cmem->ranges[cmem->nr_ranges].end = end - 1;
 		cmem->nr_ranges++;
 	}
 
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret)
-		goto out;
-
-	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
-		if (ret)
-			goto out;
-	}
-
-	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
-
-out:
-	kfree(cmem);
-	return ret;
+	return 0;
 }
 #endif
 
@@ -109,7 +93,7 @@ int load_other_segments(struct kimage *image,
 	void *headers;
 	unsigned long headers_sz;
 	if (image->type == KEXEC_TYPE_CRASH) {
-		ret = prepare_elf_headers(&headers, &headers_sz);
+		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
 		if (ret) {
 			pr_err("Preparing elf core header failed\n");
 			goto out_err;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:54 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:54 +0800
Subject: [PATCH v16 05/10] x86: kexec_file: Use crash_prepare_headers() helper to simplify code
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-6-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
memory in the crash core, which reduce code duplication.

Only the following three architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Call get_nr_ram_ranges_callback()
  to pre-count the max number of memory ranges.

- arch_crash_populate_cmem(). Use prepare_elf64_ram_headers_callback()
  to collect the memory ranges and fills them into cmem.

- arch_crash_exclude_ranges(). Exclude the low 1M for x86.

By the way, remove the unused "nr_mem_ranges" in
arch_crash_handle_hotplug_event().

Cc: Thomas Gleixner <tglx at kernel.org>
Cc: Ingo Molnar <mingo at redhat.com>
Cc: Borislav Petkov <bp at alien8.de>
Cc: Dave Hansen <dave.hansen at linux.intel.com>
Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Vivek Goyal <vgoyal at redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/x86/kernel/crash.c | 89 +++++------------------------------------
 1 file changed, 11 insertions(+), 78 deletions(-)

diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
index cd796818d94d..cb2ce7acfec4 100644
--- a/arch/x86/kernel/crash.c
+++ b/arch/x86/kernel/crash.c
@@ -153,16 +153,8 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
 	return 0;
 }
 
-/* Gather all the required information to prepare elf headers for ram regions */
-static struct crash_mem *fill_up_crash_elf_data(void)
+unsigned int arch_get_system_nr_ranges(void)
 {
-	unsigned int nr_ranges = 0;
-	struct crash_mem *cmem;
-
-	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
-	if (!nr_ranges)
-		return NULL;
-
 	/*
 	 * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges
 	 * may cause range splits. So add extra slots here.
@@ -177,49 +169,16 @@ static struct crash_mem *fill_up_crash_elf_data(void)
 	 * But in order to lest the low 1M could be changed in the future,
 	 * (e.g. [start, 1M]), add a extra slot.
 	 */
-	nr_ranges += 3 + crashk_cma_cnt;
-	cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
-	if (!cmem)
-		return NULL;
-
-	cmem->max_nr_ranges = nr_ranges;
+	unsigned int nr_ranges = 3 + crashk_cma_cnt;
 
-	return cmem;
+	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
+	return nr_ranges;
 }
 
-/*
- * Look for any unwanted ranges between mstart, mend and remove them. This
- * might lead to split and split ranges are put in cmem->ranges[] array
- */
-static int elf_header_exclude_ranges(struct crash_mem *cmem)
+int arch_crash_exclude_ranges(struct crash_mem *cmem)
 {
-	int ret = 0;
-	int i;
-
 	/* Exclude the low 1M because it is always reserved */
-	ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
-	if (ret)
-		return ret;
-
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret)
-		return ret;
-
-	if (crashk_low_res.end)
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start,
-					      crashk_low_res.end);
-	if (ret)
-		return ret;
-
-	for (i = 0; i < crashk_cma_cnt; ++i) {
-		ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
-					      crashk_cma_ranges[i].end);
-		if (ret)
-			return ret;
-	}
-
-	return 0;
+	return crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
 }
 
 static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
@@ -233,35 +192,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 	return 0;
 }
 
-/* Prepare elf headers. Return addr and size */
-static int prepare_elf_headers(void **addr, unsigned long *sz,
-			       unsigned long *nr_mem_ranges)
+int arch_crash_populate_cmem(struct crash_mem *cmem)
 {
-	struct crash_mem *cmem;
-	int ret;
-
-	cmem = fill_up_crash_elf_data();
-	if (!cmem)
-		return -ENOMEM;
-
-	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
-	if (ret)
-		goto out;
-
-	/* Exclude unwanted mem ranges */
-	ret = elf_header_exclude_ranges(cmem);
-	if (ret)
-		goto out;
-
-	/* Return the computed number of memory ranges, for hotplug usage */
-	*nr_mem_ranges = cmem->nr_ranges;
-
-	/* By default prepare 64bit headers */
-	ret = crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), addr, sz);
-
-out:
-	vfree(cmem);
-	return ret;
+	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
 }
 #endif
 
@@ -419,7 +352,8 @@ int crash_load_segments(struct kimage *image)
 				  .buf_max = ULONG_MAX, .top_down = false };
 
 	/* Prepare elf headers and add a segment */
-	ret = prepare_elf_headers(&kbuf.buffer, &kbuf.bufsz, &pnum);
+	ret = crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &kbuf.buffer,
+				    &kbuf.bufsz, &pnum);
 	if (ret)
 		return ret;
 
@@ -512,7 +446,6 @@ unsigned int arch_crash_get_elfcorehdr_size(void)
 void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
 {
 	void *elfbuf = NULL, *old_elfcorehdr;
-	unsigned long nr_mem_ranges;
 	unsigned long mem, memsz;
 	unsigned long elfsz = 0;
 
@@ -530,7 +463,7 @@ void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
 	 * Create the new elfcorehdr reflecting the changes to CPU and/or
 	 * memory resources.
 	 */
-	if (prepare_elf_headers(&elfbuf, &elfsz, &nr_mem_ranges)) {
+	if (crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &elfbuf, &elfsz, NULL)) {
 		pr_err("unable to create new elfcorehdr");
 		goto out;
 	}
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:55 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:55 +0800
Subject: [PATCH v16 06/10] riscv: kexec_file: Use crash_prepare_headers() helper to simplify code
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-7-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
memory in the crash core, which reduce code duplication.

Only the following two architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Call get_nr_ram_ranges_callback()
  to pre-counts the max number of memory ranges.

- arch_crash_populate_cmem(). Use prepare_elf64_ram_headers_callback()
  to collects the memory ranges and fills them into cmem.

Cc: Paul Walmsley <pjw at kernel.org>
Cc: Palmer Dabbelt <palmer at dabbelt.com>
Cc: Albert Ou <aou at eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex at ghiti.fr>
Cc: Guo Ren <guoren at kernel.org>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/riscv/kernel/machine_kexec_file.c | 47 +++++++-------------------
 1 file changed, 12 insertions(+), 35 deletions(-)

diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 3f7766057cac..439cbc50dfa6 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -44,6 +44,15 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
 	return 0;
 }
 
+unsigned int arch_get_system_nr_ranges(void)
+{
+	unsigned int nr_ranges = 2; /* For exclusion of crashkernel region */
+
+	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
+
+	return nr_ranges;
+}
+
 static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 {
 	struct crash_mem *cmem = arg;
@@ -55,41 +64,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
 	return 0;
 }
 
-static int prepare_elf_headers(void **addr, unsigned long *sz)
+int arch_crash_populate_cmem(struct crash_mem *cmem)
 {
-	struct crash_mem *cmem;
-	unsigned int nr_ranges;
-	int ret;
-
-	nr_ranges = 2; /* For exclusion of crashkernel region */
-	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
-
-	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
-	if (!cmem)
-		return -ENOMEM;
-
-	cmem->max_nr_ranges = nr_ranges;
-	cmem->nr_ranges = 0;
-	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
-	if (ret)
-		goto out;
-
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret)
-		goto out;
-
-	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
-		if (ret)
-			goto out;
-	}
-
-	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
-
-out:
-	kfree(cmem);
-	return ret;
+	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
 }
 
 static char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
@@ -281,7 +258,7 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start,
 	if (image->type == KEXEC_TYPE_CRASH) {
 		void *headers;
 		unsigned long headers_sz;
-		ret = prepare_elf_headers(&headers, &headers_sz);
+		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
 		if (ret) {
 			pr_err("Preparing elf core header failed\n");
 			goto out;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:56 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:56 +0800
Subject: [PATCH v16 07/10] LoongArch: kexec_file: Use crash_prepare_headers() helper to simplify code
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-8-ruanjinjie@huawei.com>

Use the newly introduced crash_prepare_headers() function to replace
the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
memory in the crash core, which reduce code duplication.

Only the following two architecture functions need to be implemented:
- arch_get_system_nr_ranges(). Use for_each_mem_range to traverse
  and pre-count the max number of memory ranges.

- arch_crash_populate_cmem(). Use for_each_mem_range to traverse
  and collect the memory ranges and fills them into cmem.

Cc: Huacai Chen <chenhuacai at kernel.org>
Cc: WANG Xuerui <kernel at xen0n.name>
Cc: Youling Tang <tangyouling at kylinos.cn>
Cc: Baoquan He <bhe at redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/loongarch/kernel/machine_kexec_file.c | 40 +++++++---------------
 1 file changed, 12 insertions(+), 28 deletions(-)

diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
index 5584b798ba46..5412aa9f3568 100644
--- a/arch/loongarch/kernel/machine_kexec_file.c
+++ b/arch/loongarch/kernel/machine_kexec_file.c
@@ -56,46 +56,30 @@ static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl
 }
 
 #ifdef CONFIG_CRASH_DUMP
-
-static int prepare_elf_headers(void **addr, unsigned long *sz)
+unsigned int arch_get_system_nr_ranges(void)
 {
-	int ret, nr_ranges;
-	uint64_t i;
+	int nr_ranges = 2; /* for exclusion of crashkernel region */
 	phys_addr_t start, end;
-	struct crash_mem *cmem;
+	uint64_t i;
 
-	nr_ranges = 2; /* for exclusion of crashkernel region */
 	for_each_mem_range(i, &start, &end)
 		nr_ranges++;
 
-	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
-	if (!cmem)
-		return -ENOMEM;
+	return nr_ranges;
+}
+
+int arch_crash_populate_cmem(struct crash_mem *cmem)
+{
+	phys_addr_t start, end;
+	uint64_t i;
 
-	cmem->max_nr_ranges = nr_ranges;
-	cmem->nr_ranges = 0;
 	for_each_mem_range(i, &start, &end) {
 		cmem->ranges[cmem->nr_ranges].start = start;
 		cmem->ranges[cmem->nr_ranges].end = end - 1;
 		cmem->nr_ranges++;
 	}
 
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
-	if (ret < 0)
-		goto out;
-
-	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
-		if (ret < 0)
-			goto out;
-	}
-
-	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
-
-out:
-	kfree(cmem);
-	return ret;
+	return 0;
 }
 
 /*
@@ -163,7 +147,7 @@ int load_other_segments(struct kimage *image,
 		void *headers;
 		unsigned long headers_sz;
 
-		ret = prepare_elf_headers(&headers, &headers_sz);
+		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
 		if (ret < 0) {
 			pr_err("Preparing elf core header failed\n");
 			goto out_err;
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:57 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:57 +0800
Subject: [PATCH v16 08/10] powerpc/kexec_file: Use crash_exclude_core_ranges() helper
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-9-ruanjinjie@huawei.com>

The crash memory exclude of crashk_res and crashk_cma memory on powerpc
are almost identical to the generic crash_exclude_core_ranges().

By introducing the architecture-specific arch_crash_exclude_mem_range()
function with a default implementation of crash_exclude_mem_range(),
and using crash_exclude_mem_range_guarded as powerpc's separate
implementation, the generic crash_exclude_core_ranges() helper function
can be reused.

Cc: Andrew Morton <akpm at linux-foundation.org>
Cc: Hari Bathini <hbathini at linux.ibm.com>
Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
Cc: Mahesh Salgaonkar <mahesh at linux.ibm.com>
Cc: Michael Ellerman <mpe at ellerman.id.au>
Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
Cc: Shivang Upadhyay <shivangu at linux.ibm.com>
Acked-by: Baoquan He <bhe at redhat.com>
Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/powerpc/include/asm/kexec_ranges.h |  3 ---
 arch/powerpc/kexec/crash.c              |  2 +-
 arch/powerpc/kexec/ranges.c             | 16 ++++------------
 include/linux/crash_core.h              |  4 ++++
 kernel/crash_core.c                     | 19 +++++++++++++------
 5 files changed, 22 insertions(+), 22 deletions(-)

diff --git a/arch/powerpc/include/asm/kexec_ranges.h b/arch/powerpc/include/asm/kexec_ranges.h
index ad95e3792d10..8489e844b447 100644
--- a/arch/powerpc/include/asm/kexec_ranges.h
+++ b/arch/powerpc/include/asm/kexec_ranges.h
@@ -7,9 +7,6 @@
 void sort_memory_ranges(struct crash_mem *mrngs, bool merge);
 struct crash_mem *realloc_mem_ranges(struct crash_mem **mem_ranges);
 int add_mem_range(struct crash_mem **mem_ranges, u64 base, u64 size);
-int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
-				    unsigned long long mstart,
-				    unsigned long long mend);
 int get_exclude_memory_ranges(struct crash_mem **mem_ranges);
 int get_reserved_memory_ranges(struct crash_mem **mem_ranges);
 int get_crash_memory_ranges(struct crash_mem **mem_ranges);
diff --git a/arch/powerpc/kexec/crash.c b/arch/powerpc/kexec/crash.c
index 2e88ec5c4356..60a917a6beaa 100644
--- a/arch/powerpc/kexec/crash.c
+++ b/arch/powerpc/kexec/crash.c
@@ -513,7 +513,7 @@ static void update_crash_elfcorehdr(struct kimage *image, struct memory_notify *
 		base_addr = PFN_PHYS(mn->start_pfn);
 		size = mn->nr_pages * PAGE_SIZE;
 		end = base_addr + size - 1;
-		ret = crash_exclude_mem_range_guarded(&cmem, base_addr, end);
+		ret = arch_crash_exclude_mem_range(&cmem, base_addr, end);
 		if (ret) {
 			pr_err("Failed to remove hot-unplugged memory from crash memory ranges\n");
 			goto out;
diff --git a/arch/powerpc/kexec/ranges.c b/arch/powerpc/kexec/ranges.c
index 6c58bcc3e130..e5fea23b191b 100644
--- a/arch/powerpc/kexec/ranges.c
+++ b/arch/powerpc/kexec/ranges.c
@@ -553,9 +553,9 @@ int get_usable_memory_ranges(struct crash_mem **mem_ranges)
 #endif /* CONFIG_KEXEC_FILE */
 
 #ifdef CONFIG_CRASH_DUMP
-int crash_exclude_mem_range_guarded(struct crash_mem **mem_ranges,
-					   unsigned long long mstart,
-					   unsigned long long mend)
+int arch_crash_exclude_mem_range(struct crash_mem **mem_ranges,
+				 unsigned long long mstart,
+				 unsigned long long mend)
 {
 	struct crash_mem *tmem = *mem_ranges;
 
@@ -604,18 +604,10 @@ int get_crash_memory_ranges(struct crash_mem **mem_ranges)
 			sort_memory_ranges(*mem_ranges, true);
 	}
 
-	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_res.start, crashk_res.end);
+	ret = crash_exclude_core_ranges(mem_ranges);
 	if (ret)
 		goto out;
 
-	for (i = 0; i < crashk_cma_cnt; ++i) {
-		ret = crash_exclude_mem_range_guarded(mem_ranges, crashk_cma_ranges[i].start,
-					      crashk_cma_ranges[i].end);
-		if (ret)
-			goto out;
-	}
-
 	/*
 	 * FIXME: For now, stay in parity with kexec-tools but if RTAS/OPAL
 	 *        regions are exported to save their context at the time of
diff --git a/include/linux/crash_core.h b/include/linux/crash_core.h
index 583ffcc703d4..bc087124cd78 100644
--- a/include/linux/crash_core.h
+++ b/include/linux/crash_core.h
@@ -61,6 +61,7 @@ extern int crash_prepare_elf64_headers(struct crash_mem *mem, int need_kernel_ma
 				       void **addr, unsigned long *sz);
 extern int crash_prepare_headers(int need_kernel_map, void **addr,
 				 unsigned long *sz, unsigned long *nr_mem_ranges);
+extern int crash_exclude_core_ranges(struct crash_mem **cmem);
 
 struct kimage;
 struct kexec_segment;
@@ -81,6 +82,9 @@ extern int kimage_crash_copy_vmcoreinfo(struct kimage *image);
 extern unsigned int arch_get_system_nr_ranges(void);
 extern int arch_crash_populate_cmem(struct crash_mem *cmem);
 extern int arch_crash_exclude_ranges(struct crash_mem *cmem);
+extern int arch_crash_exclude_mem_range(struct crash_mem **mem,
+					unsigned long long mstart,
+					unsigned long long mend);
 
 #else /* !CONFIG_CRASH_DUMP*/
 struct pt_regs;
diff --git a/kernel/crash_core.c b/kernel/crash_core.c
index 481babc29131..2b36aa9fade0 100644
--- a/kernel/crash_core.c
+++ b/kernel/crash_core.c
@@ -285,24 +285,31 @@ unsigned int __weak arch_get_system_nr_ranges(void) { return 0; }
 int __weak arch_crash_populate_cmem(struct crash_mem *cmem) { return -1; }
 int __weak arch_crash_exclude_ranges(struct crash_mem *cmem) { return 0; }
 
-static int crash_exclude_core_ranges(struct crash_mem *cmem)
+int __weak arch_crash_exclude_mem_range(struct crash_mem **mem,
+					unsigned long long mstart,
+					unsigned long long mend)
+{
+	return crash_exclude_mem_range(*mem, mstart, mend);
+}
+
+int crash_exclude_core_ranges(struct crash_mem **cmem)
 {
 	int ret, i;
 
 	/* Exclude crashkernel region */
-	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
+	ret = arch_crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
 	if (ret)
 		return ret;
 
 	if (crashk_low_res.end) {
-		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
+		ret = arch_crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
 		if (ret)
 			return ret;
 	}
 
 	for (i = 0; i < crashk_cma_cnt; ++i) {
-		ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
-					      crashk_cma_ranges[i].end);
+		ret = arch_crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
+						   crashk_cma_ranges[i].end);
 		if (ret)
 			return ret;
 	}
@@ -329,7 +336,7 @@ int crash_prepare_headers(int need_kernel_map, void **addr, unsigned long *sz,
 	if (ret)
 		goto out;
 
-	ret = crash_exclude_core_ranges(cmem);
+	ret = crash_exclude_core_ranges(&cmem);
 	if (ret)
 		goto out;
 
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:58 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:58 +0800
Subject: [PATCH v16 09/10] arm64: kexec_file: Add support for crashkernel CMA reservation
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-10-ruanjinjie@huawei.com>

Commit 35c18f2933c5 ("Add a new optional ",cma" suffix to the
crashkernel= command line option") and commit ab475510e042 ("kdump:
implement reserve_crashkernel_cma") added CMA support for kdump
crashkernel reservation.

Crash kernel memory reservation wastes production resources if too
large, risks kdump failure if too small, and faces allocation difficulties
on fragmented systems due to contiguous block constraints. The new
CMA-based crashkernel reservation scheme splits the "large fixed
reservation" into a "small fixed region + large CMA dynamic region": the
CMA memory is available to userspace during normal operation to avoid
waste, and is reclaimed for kdump upon crash?saving memory while
improving reliability.

So extend crashkernel CMA reservation support to arm64. The following
changes are made to enable CMA reservation:

- Parse and obtain the CMA reservation size along with other crashkernel
  parameters.
- Call reserve_crashkernel_cma() to allocate the CMA region for kdump.
- Include the CMA-reserved ranges for kdump kernel to use.
- Exclude the CMA-reserved ranges from the crash kernel memory to
  prevent them from being exported through /proc/vmcore, which is already
  done in the crash core.

Update kernel-parameters.txt to document CMA support for crashkernel on
arm64 architecture.

Tested-by: Breno Leitao <leitao at debian.org>
Acked-by: Catalin Marinas <catalin.marinas at arm.com>
Acked-by: Rob Herring (Arm) <robh at kernel.org>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Acked-by: Ard Biesheuvel <ardb at kernel.org>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
v7:
- Correct the inclusion of CMA-reserved ranges for kdump
  kernel in of/kexec.
v3:
- Add Acked-by.
v2:
- Free cmem in prepare_elf_headers()
- Add the mtivation.
---
 Documentation/admin-guide/kernel-parameters.txt | 2 +-
 arch/arm64/kernel/machine_kexec_file.c          | 2 +-
 arch/arm64/mm/init.c                            | 5 +++--
 drivers/of/fdt.c                                | 9 +++++----
 drivers/of/kexec.c                              | 9 +++++++++
 include/linux/crash_reserve.h                   | 4 +++-
 6 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 4d0f545fb3ec..52742fab49a9 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1119,7 +1119,7 @@ Kernel parameters
 			It will be ignored when crashkernel=X,high is not used
 			or memory reserved is below 4G.
 	crashkernel=size[KMG],cma
-			[KNL, X86, ppc] Reserve additional crash kernel memory from
+			[KNL, X86, ARM64, PPC] Reserve additional crash kernel memory from
 			CMA. This reservation is usable by the first system's
 			userspace memory and kernel movable allocations (memory
 			balloon, zswap). Pages allocated from this memory range
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index b019b31df48c..854d872dfd0f 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -42,7 +42,7 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 #ifdef CONFIG_CRASH_DUMP
 unsigned int arch_get_system_nr_ranges(void)
 {
-	unsigned int nr_ranges = 2; /* for exclusion of crashkernel region */
+	unsigned int nr_ranges = 2 + crashk_cma_cnt; /* for exclusion of crashkernel region */
 	phys_addr_t start, end;
 	u64 i;
 
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 97987f850a33..227f58522dad 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -96,8 +96,8 @@ phys_addr_t __ro_after_init arm64_dma_phys_limit;
 
 static void __init arch_reserve_crashkernel(void)
 {
+	unsigned long long crash_base, crash_size, cma_size = 0;
 	unsigned long long low_size = 0;
-	unsigned long long crash_base, crash_size;
 	bool high = false;
 	int ret;
 
@@ -106,11 +106,12 @@ static void __init arch_reserve_crashkernel(void)
 
 	ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
 				&crash_size, &crash_base,
-				&low_size, NULL, &high);
+				&low_size, &cma_size, &high);
 	if (ret)
 		return;
 
 	reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
+	reserve_crashkernel_cma(cma_size);
 }
 
 static phys_addr_t __init max_zone_phys(phys_addr_t zone_limit)
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 82f7327c59ea..0470acbd1fcf 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -880,11 +880,12 @@ static unsigned long chosen_node_offset = -FDT_ERR_NOTFOUND;
 /*
  * The main usage of linux,usable-memory-range is for crash dump kernel.
  * Originally, the number of usable-memory regions is one. Now there may
- * be two regions, low region and high region.
- * To make compatibility with existing user-space and older kdump, the low
- * region is always the last range of linux,usable-memory-range if exist.
+ * be 2 + CRASHK_CMA_RANGES_MAX regions, low region, high region and cma
+ * regions. To make compatibility with existing user-space and older kdump,
+ * the high and low region are always the first two ranges of
+ * linux,usable-memory-range if exist.
  */
-#define MAX_USABLE_RANGES		2
+#define MAX_USABLE_RANGES		(2 + CRASHK_CMA_RANGES_MAX)
 
 /**
  * early_init_dt_check_for_usable_mem_range - Decode usable memory range
diff --git a/drivers/of/kexec.c b/drivers/of/kexec.c
index b6837e299e7f..029903b986cb 100644
--- a/drivers/of/kexec.c
+++ b/drivers/of/kexec.c
@@ -458,6 +458,15 @@ void *of_kexec_alloc_and_setup_fdt(const struct kimage *image,
 			if (ret)
 				goto out;
 		}
+
+		for (int i = 0; i < crashk_cma_cnt; i++) {
+			ret = fdt_appendprop_addrrange(fdt, 0, chosen_node,
+					"linux,usable-memory-range",
+					crashk_cma_ranges[i].start,
+					crashk_cma_ranges[i].end - crashk_cma_ranges[i].start + 1);
+			if (ret)
+				goto out;
+		}
 #endif
 	}
 
diff --git a/include/linux/crash_reserve.h b/include/linux/crash_reserve.h
index f0dc03d94ca2..30864d90d7f5 100644
--- a/include/linux/crash_reserve.h
+++ b/include/linux/crash_reserve.h
@@ -14,9 +14,11 @@
 extern struct resource crashk_res;
 extern struct resource crashk_low_res;
 extern struct range crashk_cma_ranges[];
+
+#define CRASHK_CMA_RANGES_MAX 4
 #if defined(CONFIG_CMA) && defined(CONFIG_ARCH_HAS_GENERIC_CRASHKERNEL_RESERVATION)
 #define CRASHKERNEL_CMA
-#define CRASHKERNEL_CMA_RANGES_MAX 4
+#define CRASHKERNEL_CMA_RANGES_MAX (CRASHK_CMA_RANGES_MAX)
 extern int crashk_cma_cnt;
 #else
 #define crashk_cma_cnt 0
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 00:34:59 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 15:34:59 +0800
Subject: [PATCH v16 10/10] riscv: kexec_file: Add support for crashkernel CMA reservation
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608073459.3119290-11-ruanjinjie@huawei.com>

Commit 35c18f2933c5 ("Add a new optional ",cma" suffix to the
crashkernel= command line option") and commit ab475510e042 ("kdump:
implement reserve_crashkernel_cma") added CMA support for kdump
crashkernel reservation. This allows the kernel to dynamically allocate
contiguous memory for crash dumping when needed, rather than permanently
reserving a fixed region at boot time.

So extend crashkernel CMA reservation support to riscv. The following
changes are made to enable CMA reservation:

- Parse and obtain the CMA reservation size along with other crashkernel
  parameters.
- Call reserve_crashkernel_cma() to allocate the CMA region for kdump.
- Include the CMA-reserved ranges for kdump kernel to use, which was
  already done in of_kexec_alloc_and_setup_fdt().
- Exclude the CMA-reserved ranges from the crash kernel memory to
  prevent them from being exported through /proc/vmcore, which was
  already done in the crash core.

Update kernel-parameters.txt to document CMA support for crashkernel on
riscv architecture.

Cc: Paul Walmsley <pjw at kernel.org>
Cc: Palmer Dabbelt <palmer at dabbelt.com>
Cc: Albert Ou <aou at eecs.berkeley.edu>
Cc: Alexandre Ghiti <alex at ghiti.fr>
Acked-by: Baoquan He <bhe at redhat.com>
Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
Acked-by: Paul Walmsley <pjw at kernel.org> # arch/riscv
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 Documentation/admin-guide/kernel-parameters.txt | 16 ++++++++--------
 arch/riscv/kernel/machine_kexec_file.c          |  2 +-
 arch/riscv/mm/init.c                            |  5 +++--
 3 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 52742fab49a9..3ff3ddd516cf 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -1119,14 +1119,14 @@ Kernel parameters
 			It will be ignored when crashkernel=X,high is not used
 			or memory reserved is below 4G.
 	crashkernel=size[KMG],cma
-			[KNL, X86, ARM64, PPC] Reserve additional crash kernel memory from
-			CMA. This reservation is usable by the first system's
-			userspace memory and kernel movable allocations (memory
-			balloon, zswap). Pages allocated from this memory range
-			will not be included in the vmcore so this should not
-			be used if dumping of userspace memory is intended and
-			it has to be expected that some movable kernel pages
-			may be missing from the dump.
+			[KNL, X86, ARM64, RISCV, PPC] Reserve additional crash
+			kernel memory from CMA. This reservation is usable by
+			the first system's userspace memory and kernel movable
+			allocations (memory balloon, zswap). Pages allocated
+			from this memory range will not be included in the vmcore
+			so this should not be used if dumping of userspace memory
+			is intended and it has to be expected that some movable
+			kernel pages may be missing from the dump.
 
 			A standard crashkernel reservation, as described above,
 			is still needed to hold the crash kernel and initrd.
diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
index 439cbc50dfa6..85f14abceb50 100644
--- a/arch/riscv/kernel/machine_kexec_file.c
+++ b/arch/riscv/kernel/machine_kexec_file.c
@@ -46,7 +46,7 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
 
 unsigned int arch_get_system_nr_ranges(void)
 {
-	unsigned int nr_ranges = 2; /* For exclusion of crashkernel region */
+	unsigned int nr_ranges = 2 + crashk_cma_cnt; /* For exclusion of crashkernel region */
 
 	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
 
diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
index decd7df40fa4..c848454b8349 100644
--- a/arch/riscv/mm/init.c
+++ b/arch/riscv/mm/init.c
@@ -1295,7 +1295,7 @@ static inline void setup_vm_final(void)
  */
 static void __init arch_reserve_crashkernel(void)
 {
-	unsigned long long low_size = 0;
+	unsigned long long low_size = 0, cma_size = 0;
 	unsigned long long crash_base, crash_size;
 	bool high = false;
 	int ret;
@@ -1305,11 +1305,12 @@ static void __init arch_reserve_crashkernel(void)
 
 	ret = parse_crashkernel(boot_command_line, memblock_phys_mem_size(),
 				&crash_size, &crash_base,
-				&low_size, NULL, &high);
+				&low_size, &cma_size, &high);
 	if (ret)
 		return;
 
 	reserve_crashkernel_generic(crash_size, crash_base, low_size, high);
+	reserve_crashkernel_cma(cma_size);
 }
 
 void __init paging_init(void)
-- 
2.34.1



From andre.przywara at arm.com  Mon Jun  8 00:38:35 2026
From: andre.przywara at arm.com (Andre Przywara)
Date: Mon, 8 Jun 2026 09:38:35 +0200
Subject: [PATCH v4 2/3] riscv: dts: allwinner: d1s-t113: Add uart4 pinctrl
 required by NetCube Systems OpenNMC
In-Reply-To: <20260606205452.2386930-3-lukas.schmid@netcube.li>
References: <20260606205452.2386930-1-lukas.schmid@netcube.li>
 <20260606205452.2386930-3-lukas.schmid@netcube.li>
Message-ID: <aa0e1539-cc59-4d3c-a0c5-a4f7cc1fe7c5@arm.com>

Hi,

On 6/6/26 22:54, Lukas Schmid wrote:
> Added the "uart4_pb_pins" pinctrl used by the OpenNMC

Checked against the datasheet:

Reviewed-by: Andre Przywara <andre.przywara at arm.com>

Cheers,
Andre

> 
> Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>
> ---
>   arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi | 6 ++++++
>   1 file changed, 6 insertions(+)
> 
> diff --git a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> index 82cc85acccb1..00fddedfa36f 100644
> --- a/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> +++ b/arch/riscv/boot/dts/allwinner/sunxi-d1s-t113.dtsi
> @@ -191,6 +191,12 @@ uart3_pb_pins: uart3-pb-pins {
>   				pins = "PB6", "PB7";
>   				function = "uart3";
>   			};
> +
> +			/omit-if-no-ref/
> +			uart4_pb_pins: uart4-pb-pins {
> +				pins = "PB2", "PB3";
> +				function = "uart4";
> +			};
>   		};
>   
>   		ccu: clock-controller at 2001000 {



From m.szyprowski at samsung.com  Mon Jun  8 00:41:04 2026
From: m.szyprowski at samsung.com (Marek Szyprowski)
Date: Mon,  8 Jun 2026 09:41:04 +0200
Subject: [PATCH v2] riscv: defconfig: thead: enable PCA953X GPIO driver
References: <CGME20260608074116eucas1p15c0f84c280d8645d778e42777bd238d1@eucas1p1.samsung.com>
Message-ID: <20260608074104.2198409-1-m.szyprowski@samsung.com>

Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
LicheePi4a board.

Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
---
v2:
- copile GPIO_PCA953X as a module
v1:
https://lore.kernel.org/all/20260603082132.3200787-1-m.szyprowski at samsung.com/
---
 arch/riscv/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
index 08445df56006..a51a423d53f4 100644
--- a/arch/riscv/configs/defconfig
+++ b/arch/riscv/configs/defconfig
@@ -174,6 +174,8 @@ CONFIG_PINCTRL_SOPHGO_SG2002=y
 CONFIG_GPIO_DWAPB=y
 CONFIG_GPIO_SIFIVE=y
 CONFIG_GPIO_SPACEMIT_K1=y
+CONFIG_GPIO_PCA953X=m
+CONFIG_GPIO_PCA953X_IRQ=y
 CONFIG_POWER_RESET_GPIO_RESTART=y
 CONFIG_SENSORS_SFCTEMP=m
 CONFIG_CPU_THERMAL=y
-- 
2.34.1



From ruanjinjie at huawei.com  Mon Jun  8 01:05:58 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 16:05:58 +0800
Subject: [PATCH v16 01/10] riscv: kexec_file: Fix crashk_low_res not
 exclude bug
In-Reply-To: <20260608073459.3119290-2-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608073459.3119290-2-ruanjinjie@huawei.com>
Message-ID: <45fa93e6-dbeb-4844-bb19-f36fe642f362@huawei.com>



On 6/8/2026 3:34 PM, Jinjie Ruan wrote:
> As done in commit 944a45abfabc ("arm64: kdump: Reimplement crashkernel=X")
> and commit 4831be702b95 ("arm64/kexec: Fix missing extra range for
> crashkres_low.") for arm64, while implementing crashkernel=X,[high,low],
> riscv should have excluded the "crashk_low_res" reserved ranges from
> the crash kernel memory to prevent them from being exported through
> /proc/vmcore, and the exclusion would need an extra crash_mem range.
> 
> Just simply tested on qemu with crashkernel=4G with kexec in [1] mentioned
> in [2]. And the second kernel can be started normally.
> 
> 	# dmesg | grep crash
> 	[    0.000000] crashkernel low memory reserved: 0xf8000000 - 0x100000000 (128 MB)
> 	[    0.000000] crashkernel reserved: 0x000000017fe00000 - 0x000000027fe00000 (4096 MB)
> 
> Cc: Guo Ren <guoren at kernel.org>
> Cc: Baoquan He <bhe at redhat.com>
> [1]: https://github.com/chenjh005/kexec-tools/tree/build-test-riscv-v2
> [2]: https://lore.kernel.org/all/20230726175000.2536220-1-chenjiahao16 at huawei.com/
> Fixes: 5882e5acf18d ("riscv: kdump: Implement crashkernel=X,[high,low]")
> Reviewed-by: Guo Ren <guoren at kernel.org>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>


The below AI reported TOCTOU bug is an existing artifact and completely
unrelated to this fix here. Therefore, we will skip fixing it in this
series to avoid unnecessary noise.

Link:
https://lore.kernel.org/all/20260608074809.EE4201F00893 at smtp.kernel.org/

> ---
>  arch/riscv/kernel/machine_kexec_file.c | 14 +++++++++++---
>  1 file changed, 11 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
> index 54e2d9552e93..3f7766057cac 100644
> --- a/arch/riscv/kernel/machine_kexec_file.c
> +++ b/arch/riscv/kernel/machine_kexec_file.c
> @@ -61,7 +61,7 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
>  	unsigned int nr_ranges;
>  	int ret;
>  
> -	nr_ranges = 1; /* For exclusion of crashkernel region */
> +	nr_ranges = 2; /* For exclusion of crashkernel region */
>  	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
>  
>  	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
> @@ -76,8 +76,16 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
>  
>  	/* Exclude crashkernel region */
>  	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
> -	if (!ret)
> -		ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
> +	if (ret)
> +		goto out;
> +
> +	if (crashk_low_res.end) {
> +		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
> +		if (ret)
> +			goto out;
> +	}
> +
> +	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
>  
>  out:
>  	kfree(cmem);



From ruanjinjie at huawei.com  Mon Jun  8 01:07:06 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 16:07:06 +0800
Subject: [PATCH v16 04/10] arm64: kexec_file: Use crash_prepare_headers()
 helper to simplify code
In-Reply-To: <20260608073459.3119290-5-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608073459.3119290-5-ruanjinjie@huawei.com>
Message-ID: <36979c7f-853f-433a-a31f-4aba3c8242b4@huawei.com>


The below AI reported TOCTOU bug is an existing artifact and completely
unrelated to the core CMA implementation introduced here. Therefore, we
will skip fixing it in this series to avoid unnecessary noise.

Link:
https://lore.kernel.org/all/20260608075628.039FC1F00893 at smtp.kernel.org/

On 6/8/2026 3:34 PM, Jinjie Ruan wrote:
> Use the newly introduced crash_prepare_headers() function to replace
> the existing prepare_elf_headers(), allocate cmem and exclude crash
> kernel memory in the crash core, which reduce code duplication.
> 
> Only the following two architecture functions need to be implemented:
> - arch_get_system_nr_ranges(). Use for_each_mem_range() to traverse
>   and pre-count the max number of memory ranges.
> 
> - arch_crash_populate_cmem(). Use for_each_mem_range to traverse
>   and collect the memory ranges and fills them into cmem.
> 
> Acked-by: Catalin Marinas <catalin.marinas at arm.com>
> Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
> Acked-by: Baoquan He <bhe at redhat.com>
> Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/arm64/kernel/machine_kexec_file.c | 40 ++++++++------------------
>  1 file changed, 12 insertions(+), 28 deletions(-)
> 
> diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
> index e31fabed378a..b019b31df48c 100644
> --- a/arch/arm64/kernel/machine_kexec_file.c
> +++ b/arch/arm64/kernel/machine_kexec_file.c
> @@ -40,46 +40,30 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
>  }
>  
>  #ifdef CONFIG_CRASH_DUMP
> -static int prepare_elf_headers(void **addr, unsigned long *sz)
> +unsigned int arch_get_system_nr_ranges(void)
>  {
> -	struct crash_mem *cmem;
> -	unsigned int nr_ranges;
> -	int ret;
> -	u64 i;
> +	unsigned int nr_ranges = 2; /* for exclusion of crashkernel region */
>  	phys_addr_t start, end;
> +	u64 i;
>  
> -	nr_ranges = 2; /* for exclusion of crashkernel region */
>  	for_each_mem_range(i, &start, &end)
>  		nr_ranges++;
>  
> -	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
> -	if (!cmem)
> -		return -ENOMEM;
> +	return nr_ranges;
> +}
> +
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
> +{
> +	phys_addr_t start, end;
> +	u64 i;
>  
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
>  	for_each_mem_range(i, &start, &end) {
>  		cmem->ranges[cmem->nr_ranges].start = start;
>  		cmem->ranges[cmem->nr_ranges].end = end - 1;
>  		cmem->nr_ranges++;
>  	}
>  
> -	/* Exclude crashkernel region */
> -	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
> -	if (ret)
> -		goto out;
> -
> -	if (crashk_low_res.end) {
> -		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
> -		if (ret)
> -			goto out;
> -	}
> -
> -	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
> -
> -out:
> -	kfree(cmem);
> -	return ret;
> +	return 0;
>  }
>  #endif
>  
> @@ -109,7 +93,7 @@ int load_other_segments(struct kimage *image,
>  	void *headers;
>  	unsigned long headers_sz;
>  	if (image->type == KEXEC_TYPE_CRASH) {
> -		ret = prepare_elf_headers(&headers, &headers_sz);
> +		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
>  		if (ret) {
>  			pr_err("Preparing elf core header failed\n");
>  			goto out_err;



From ruanjinjie at huawei.com  Mon Jun  8 01:08:03 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 16:08:03 +0800
Subject: [PATCH v16 06/10] riscv: kexec_file: Use crash_prepare_headers()
 helper to simplify code
In-Reply-To: <20260608073459.3119290-7-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608073459.3119290-7-ruanjinjie@huawei.com>
Message-ID: <f26bc61d-14ad-450d-bdfa-59b039ae660c@huawei.com>



On 6/8/2026 3:34 PM, Jinjie Ruan wrote:
> Use the newly introduced crash_prepare_headers() function to replace
> the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
> memory in the crash core, which reduce code duplication.
> 
> Only the following two architecture functions need to be implemented:
> - arch_get_system_nr_ranges(). Call get_nr_ram_ranges_callback()
>   to pre-counts the max number of memory ranges.
> 
> - arch_crash_populate_cmem(). Use prepare_elf64_ram_headers_callback()
>   to collects the memory ranges and fills them into cmem.


The below AI reported TOCTOU bug is an existing artifact and completely
unrelated to the core CMA implementation introduced here. Therefore, we
will skip fixing it in this series to avoid unnecessary noise.

Link:
https://lore.kernel.org/all/20260608075420.8C5871F00893 at smtp.kernel.org/

> 
> Cc: Paul Walmsley <pjw at kernel.org>
> Cc: Palmer Dabbelt <palmer at dabbelt.com>
> Cc: Albert Ou <aou at eecs.berkeley.edu>
> Cc: Alexandre Ghiti <alex at ghiti.fr>
> Cc: Guo Ren <guoren at kernel.org>
> Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
> Acked-by: Baoquan He <bhe at redhat.com>
> Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/riscv/kernel/machine_kexec_file.c | 47 +++++++-------------------
>  1 file changed, 12 insertions(+), 35 deletions(-)
> 
> diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
> index 3f7766057cac..439cbc50dfa6 100644
> --- a/arch/riscv/kernel/machine_kexec_file.c
> +++ b/arch/riscv/kernel/machine_kexec_file.c
> @@ -44,6 +44,15 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
>  	return 0;
>  }
>  
> +unsigned int arch_get_system_nr_ranges(void)
> +{
> +	unsigned int nr_ranges = 2; /* For exclusion of crashkernel region */
> +
> +	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
> +
> +	return nr_ranges;
> +}
> +
>  static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
>  {
>  	struct crash_mem *cmem = arg;
> @@ -55,41 +64,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
>  	return 0;
>  }
>  
> -static int prepare_elf_headers(void **addr, unsigned long *sz)
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
>  {
> -	struct crash_mem *cmem;
> -	unsigned int nr_ranges;
> -	int ret;
> -
> -	nr_ranges = 2; /* For exclusion of crashkernel region */
> -	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
> -
> -	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
> -	if (!cmem)
> -		return -ENOMEM;
> -
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
> -	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
> -	if (ret)
> -		goto out;
> -
> -	/* Exclude crashkernel region */
> -	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
> -	if (ret)
> -		goto out;
> -
> -	if (crashk_low_res.end) {
> -		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
> -		if (ret)
> -			goto out;
> -	}
> -
> -	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
> -
> -out:
> -	kfree(cmem);
> -	return ret;
> +	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
>  }
>  
>  static char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
> @@ -281,7 +258,7 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start,
>  	if (image->type == KEXEC_TYPE_CRASH) {
>  		void *headers;
>  		unsigned long headers_sz;
> -		ret = prepare_elf_headers(&headers, &headers_sz);
> +		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
>  		if (ret) {
>  			pr_err("Preparing elf core header failed\n");
>  			goto out;



From ruanjinjie at huawei.com  Mon Jun  8 01:21:53 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 16:21:53 +0800
Subject: [PATCH v16 05/10] x86: kexec_file: Use crash_prepare_headers()
 helper to simplify code
In-Reply-To: <20260608073459.3119290-6-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608073459.3119290-6-ruanjinjie@huawei.com>
Message-ID: <005cff45-895f-40f4-b0ae-62744ce74643@huawei.com>



On 6/8/2026 3:34 PM, Jinjie Ruan wrote:
> Use the newly introduced crash_prepare_headers() function to replace
> the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
> memory in the crash core, which reduce code duplication.
> 
> Only the following three architecture functions need to be implemented:
> - arch_get_system_nr_ranges(). Call get_nr_ram_ranges_callback()
>   to pre-count the max number of memory ranges.
> 
> - arch_crash_populate_cmem(). Use prepare_elf64_ram_headers_callback()
>   to collect the memory ranges and fills them into cmem.
> 
> - arch_crash_exclude_ranges(). Exclude the low 1M for x86.
> 
> By the way, remove the unused "nr_mem_ranges" in
> arch_crash_handle_hotplug_event().

The below AI reported TOCTOU bug is an existing artifact and completely
unrelated to the reowork here. Therefore, we will skip fixing it in this
series to avoid unnecessary noise.

Link:
https://lore.kernel.org/all/20260608074748.58E8E1F00893 at smtp.kernel.org/

> 
> Cc: Thomas Gleixner <tglx at kernel.org>
> Cc: Ingo Molnar <mingo at redhat.com>
> Cc: Borislav Petkov <bp at alien8.de>
> Cc: Dave Hansen <dave.hansen at linux.intel.com>
> Cc: Andrew Morton <akpm at linux-foundation.org>
> Cc: Vivek Goyal <vgoyal at redhat.com>
> Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
> Acked-by: Baoquan He <bhe at redhat.com>
> Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/x86/kernel/crash.c | 89 +++++------------------------------------
>  1 file changed, 11 insertions(+), 78 deletions(-)
> 
> diff --git a/arch/x86/kernel/crash.c b/arch/x86/kernel/crash.c
> index cd796818d94d..cb2ce7acfec4 100644
> --- a/arch/x86/kernel/crash.c
> +++ b/arch/x86/kernel/crash.c
> @@ -153,16 +153,8 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
>  	return 0;
>  }
>  
> -/* Gather all the required information to prepare elf headers for ram regions */
> -static struct crash_mem *fill_up_crash_elf_data(void)
> +unsigned int arch_get_system_nr_ranges(void)
>  {
> -	unsigned int nr_ranges = 0;
> -	struct crash_mem *cmem;
> -
> -	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
> -	if (!nr_ranges)
> -		return NULL;
> -
>  	/*
>  	 * Exclusion of crash region, crashk_low_res and/or crashk_cma_ranges
>  	 * may cause range splits. So add extra slots here.
> @@ -177,49 +169,16 @@ static struct crash_mem *fill_up_crash_elf_data(void)
>  	 * But in order to lest the low 1M could be changed in the future,
>  	 * (e.g. [start, 1M]), add a extra slot.
>  	 */
> -	nr_ranges += 3 + crashk_cma_cnt;
> -	cmem = vzalloc(struct_size(cmem, ranges, nr_ranges));
> -	if (!cmem)
> -		return NULL;
> -
> -	cmem->max_nr_ranges = nr_ranges;
> +	unsigned int nr_ranges = 3 + crashk_cma_cnt;
>  
> -	return cmem;
> +	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
> +	return nr_ranges;
>  }
>  
> -/*
> - * Look for any unwanted ranges between mstart, mend and remove them. This
> - * might lead to split and split ranges are put in cmem->ranges[] array
> - */
> -static int elf_header_exclude_ranges(struct crash_mem *cmem)
> +int arch_crash_exclude_ranges(struct crash_mem *cmem)
>  {
> -	int ret = 0;
> -	int i;
> -
>  	/* Exclude the low 1M because it is always reserved */
> -	ret = crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
> -	if (ret)
> -		return ret;
> -
> -	/* Exclude crashkernel region */
> -	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
> -	if (ret)
> -		return ret;
> -
> -	if (crashk_low_res.end)
> -		ret = crash_exclude_mem_range(cmem, crashk_low_res.start,
> -					      crashk_low_res.end);
> -	if (ret)
> -		return ret;
> -
> -	for (i = 0; i < crashk_cma_cnt; ++i) {
> -		ret = crash_exclude_mem_range(cmem, crashk_cma_ranges[i].start,
> -					      crashk_cma_ranges[i].end);
> -		if (ret)
> -			return ret;
> -	}
> -
> -	return 0;
> +	return crash_exclude_mem_range(cmem, 0, SZ_1M - 1);
>  }
>  
>  static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
> @@ -233,35 +192,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
>  	return 0;
>  }
>  
> -/* Prepare elf headers. Return addr and size */
> -static int prepare_elf_headers(void **addr, unsigned long *sz,
> -			       unsigned long *nr_mem_ranges)
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
>  {
> -	struct crash_mem *cmem;
> -	int ret;
> -
> -	cmem = fill_up_crash_elf_data();
> -	if (!cmem)
> -		return -ENOMEM;
> -
> -	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
> -	if (ret)
> -		goto out;
> -
> -	/* Exclude unwanted mem ranges */
> -	ret = elf_header_exclude_ranges(cmem);
> -	if (ret)
> -		goto out;
> -
> -	/* Return the computed number of memory ranges, for hotplug usage */
> -	*nr_mem_ranges = cmem->nr_ranges;
> -
> -	/* By default prepare 64bit headers */
> -	ret = crash_prepare_elf64_headers(cmem, IS_ENABLED(CONFIG_X86_64), addr, sz);
> -
> -out:
> -	vfree(cmem);
> -	return ret;
> +	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
>  }
>  #endif
>  
> @@ -419,7 +352,8 @@ int crash_load_segments(struct kimage *image)
>  				  .buf_max = ULONG_MAX, .top_down = false };
>  
>  	/* Prepare elf headers and add a segment */
> -	ret = prepare_elf_headers(&kbuf.buffer, &kbuf.bufsz, &pnum);
> +	ret = crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &kbuf.buffer,
> +				    &kbuf.bufsz, &pnum);
>  	if (ret)
>  		return ret;
>  
> @@ -512,7 +446,6 @@ unsigned int arch_crash_get_elfcorehdr_size(void)
>  void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
>  {
>  	void *elfbuf = NULL, *old_elfcorehdr;
> -	unsigned long nr_mem_ranges;
>  	unsigned long mem, memsz;
>  	unsigned long elfsz = 0;
>  
> @@ -530,7 +463,7 @@ void arch_crash_handle_hotplug_event(struct kimage *image, void *arg)
>  	 * Create the new elfcorehdr reflecting the changes to CPU and/or
>  	 * memory resources.
>  	 */
> -	if (prepare_elf_headers(&elfbuf, &elfsz, &nr_mem_ranges)) {
> +	if (crash_prepare_headers(IS_ENABLED(CONFIG_X86_64), &elfbuf, &elfsz, NULL)) {
>  		pr_err("unable to create new elfcorehdr");
>  		goto out;
>  	}



From ruanjinjie at huawei.com  Mon Jun  8 01:23:12 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 8 Jun 2026 16:23:12 +0800
Subject: [PATCH v16 07/10] LoongArch: kexec_file: Use
 crash_prepare_headers() helper to simplify code
In-Reply-To: <20260608073459.3119290-8-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608073459.3119290-8-ruanjinjie@huawei.com>
Message-ID: <4f3ae5f8-abf1-42ef-b613-7d69349f0cc8@huawei.com>



On 6/8/2026 3:34 PM, Jinjie Ruan wrote:
> Use the newly introduced crash_prepare_headers() function to replace
> the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
> memory in the crash core, which reduce code duplication.
> 
> Only the following two architecture functions need to be implemented:
> - arch_get_system_nr_ranges(). Use for_each_mem_range to traverse
>   and pre-count the max number of memory ranges.
> 
> - arch_crash_populate_cmem(). Use for_each_mem_range to traverse
>   and collect the memory ranges and fills them into cmem.
> 
> Cc: Huacai Chen <chenhuacai at kernel.org>
> Cc: WANG Xuerui <kernel at xen0n.name>
> Cc: Youling Tang <tangyouling at kylinos.cn>
> Cc: Baoquan He <bhe at redhat.com>
> Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
> Acked-by: Baoquan He <bhe at redhat.com>
> Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/loongarch/kernel/machine_kexec_file.c | 40 +++++++---------------
>  1 file changed, 12 insertions(+), 28 deletions(-)


The below AI reported TOCTOU bug is an existing artifact and completely
unrelated to the rework here. Therefore, we will skip fixing it in this
series to avoid unnecessary noise.

Link:
https://lore.kernel.org/all/20260608075258.0F6D91F00893 at smtp.kernel.org/

> 
> diff --git a/arch/loongarch/kernel/machine_kexec_file.c b/arch/loongarch/kernel/machine_kexec_file.c
> index 5584b798ba46..5412aa9f3568 100644
> --- a/arch/loongarch/kernel/machine_kexec_file.c
> +++ b/arch/loongarch/kernel/machine_kexec_file.c
> @@ -56,46 +56,30 @@ static void cmdline_add_initrd(struct kimage *image, unsigned long *cmdline_tmpl
>  }
>  
>  #ifdef CONFIG_CRASH_DUMP
> -
> -static int prepare_elf_headers(void **addr, unsigned long *sz)
> +unsigned int arch_get_system_nr_ranges(void)
>  {
> -	int ret, nr_ranges;
> -	uint64_t i;
> +	int nr_ranges = 2; /* for exclusion of crashkernel region */
>  	phys_addr_t start, end;
> -	struct crash_mem *cmem;
> +	uint64_t i;
>  
> -	nr_ranges = 2; /* for exclusion of crashkernel region */
>  	for_each_mem_range(i, &start, &end)
>  		nr_ranges++;
>  
> -	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
> -	if (!cmem)
> -		return -ENOMEM;
> +	return nr_ranges;
> +}
> +
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
> +{
> +	phys_addr_t start, end;
> +	uint64_t i;
>  
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
>  	for_each_mem_range(i, &start, &end) {
>  		cmem->ranges[cmem->nr_ranges].start = start;
>  		cmem->ranges[cmem->nr_ranges].end = end - 1;
>  		cmem->nr_ranges++;
>  	}
>  
> -	/* Exclude crashkernel region */
> -	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
> -	if (ret < 0)
> -		goto out;
> -
> -	if (crashk_low_res.end) {
> -		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
> -		if (ret < 0)
> -			goto out;
> -	}
> -
> -	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
> -
> -out:
> -	kfree(cmem);
> -	return ret;
> +	return 0;
>  }
>  
>  /*
> @@ -163,7 +147,7 @@ int load_other_segments(struct kimage *image,
>  		void *headers;
>  		unsigned long headers_sz;
>  
> -		ret = prepare_elf_headers(&headers, &headers_sz);
> +		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
>  		if (ret < 0) {
>  			pr_err("Preparing elf core header failed\n");
>  			goto out_err;



From leitao at debian.org  Mon Jun  8 01:48:47 2026
From: leitao at debian.org (Breno Leitao)
Date: Mon, 8 Jun 2026 01:48:47 -0700
Subject: [PATCH v16 08/10] powerpc/kexec_file: Use
 crash_exclude_core_ranges() helper
In-Reply-To: <20260608073459.3119290-9-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608073459.3119290-9-ruanjinjie@huawei.com>
Message-ID: <aiaB45VXyCv4pUBW@gmail.com>

On Mon, Jun 08, 2026 at 03:34:57PM +0800, Jinjie Ruan wrote:
> The crash memory exclude of crashk_res and crashk_cma memory on powerpc
> are almost identical to the generic crash_exclude_core_ranges().
> 
> By introducing the architecture-specific arch_crash_exclude_mem_range()
> function with a default implementation of crash_exclude_mem_range(),
> and using crash_exclude_mem_range_guarded as powerpc's separate
> implementation, the generic crash_exclude_core_ranges() helper function
> can be reused.
> 
> Cc: Andrew Morton <akpm at linux-foundation.org>
> Cc: Hari Bathini <hbathini at linux.ibm.com>
> Cc: Madhavan Srinivasan <maddy at linux.ibm.com>
> Cc: Mahesh Salgaonkar <mahesh at linux.ibm.com>
> Cc: Michael Ellerman <mpe at ellerman.id.au>
> Cc: Ritesh Harjani (IBM) <ritesh.list at gmail.com>
> Cc: Shivang Upadhyay <shivangu at linux.ibm.com>
> Acked-by: Baoquan He <bhe at redhat.com>
> Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
> Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>

Acked-by: Breno leitao <leitao at debian.org>


From cp0613 at linux.alibaba.com  Mon Jun  8 02:19:05 2026
From: cp0613 at linux.alibaba.com (Chen Pei)
Date: Mon,  8 Jun 2026 17:19:05 +0800
Subject: [PATCH v3] riscv: mm: Implement arch_within_stack_frames() for HARDENED_USERCOPY
Message-ID: <20260608091906.87543-1-cp0613@linux.alibaba.com>

Implement arch_within_stack_frames() to enable precise per-frame stack
object validation for CONFIG_HARDENED_USERCOPY on RISC-V.

Per the RISC-V ELF psABI Frame Pointer Convention [1], with
-fno-omit-frame-pointer (implied by CONFIG_FRAME_POINTER), the RISC-V
ABI places the saved frame pointer (fp/s0) and return address (ra) at
the top of each frame:

  high addr
    +------------------+  <--- fp (s0) -- frame pointer register
    |   saved ra       |      fp - 1*sizeof(void*) (return address)
    |   saved fp       |      fp - 2*sizeof(void*) (caller's frame pointer)
    +------------------+
    |   local variables|
    |   spilled args   |
    +------------------+  <--- sp
  low addr

The allowed usercopy region within one frame is
[prev_fp, fp-2*sizeof(void*)), covering local variables but excluding
the saved fp/ra slots.

The frame chain is walked from __builtin_frame_address(0), with prev_fp
initialized to current_stack_pointer rather than the thread stack base.
This ensures objects in already-returned frames are correctly detected
as BAD_STACK, since no live frame will cover that region.

[1] https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#frame-pointer-convention

Signed-off-by: Chen Pei <cp0613 at linux.alibaba.com>
Reviewed-by: Vivian Wang <wangruikang at iscas.ac.cn>
---

== Testing ==

Build requirements:
  CONFIG_HARDENED_USERCOPY=y
  CONFIG_FRAME_POINTER=y      (already selected by default on riscv)
  CONFIG_LKDTM=y
  CONFIG_DEBUG_FS=y

Run on QEMU or target board as root:

  # Trigger copy_to_user from a stack frame that has already returned:
  echo USERCOPY_STACK_FRAME_TO > /sys/kernel/debug/provoke-crash/DIRECT

  # Trigger copy_from_user into a stack frame that has already returned:
  echo USERCOPY_STACK_FRAME_FROM > /sys/kernel/debug/provoke-crash/DIRECT

  # Trigger copy beyond current stack bounds:
  echo USERCOPY_STACK_BEYOND > /sys/kernel/debug/provoke-crash/DIRECT

== Kernel test logs ==

  # echo USERCOPY_STACK_FRAME_TO > /sys/kernel/debug/provoke-crash/DIRECT
  lkdtm: Performing direct entry USERCOPY_STACK_FRAME_TO
  lkdtm: good_stack: ff20000000323c98-ff20000000323cb8
  lkdtm: bad_stack : ff20000000323c18-ff20000000323c38
  lkdtm: attempting good copy_to_user of local stack
  lkdtm: attempting bad copy_to_user of distant stack
  usercopy: Kernel memory exposure attempt detected from process stack (offset 38, size 20)!
  ......
  (kernel BUG Call Trace...)
  ......

Changes in v3:
 - Put the psABI reference URL on a single line.
 - Add one Reviewed-by tags.

Changes in v2:
 - Simplify commit messages.
 - Drop the redundant #ifdef CONFIG_HAVE_ARCH_WITHIN_STACK_FRAMES.
 - Corrected RISC-V stack frame layout description for RV32 compatibility.
 - Add a reference link to the RISC-V ELF psABI Frame Pointer Convention.
 - Fix potential out-of-bounds read when fp is too close to the stack bottom.

 arch/riscv/Kconfig                   |  1 +
 arch/riscv/include/asm/thread_info.h | 67 ++++++++++++++++++++++++++++
 2 files changed, 68 insertions(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index c5754942cf85..ef1a8e89b4a9 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -150,6 +150,7 @@ config RISCV
 	select HAVE_ARCH_USERFAULTFD_MINOR if 64BIT && USERFAULTFD
 	select HAVE_ARCH_USERFAULTFD_WP if 64BIT && MMU && USERFAULTFD && RISCV_ISA_SVRSW60T59B
 	select HAVE_ARCH_VMAP_STACK if MMU && 64BIT
+	select HAVE_ARCH_WITHIN_STACK_FRAMES
 	select HAVE_ASM_MODVERSIONS
 	select HAVE_CONTEXT_TRACKING_USER
 	select HAVE_DEBUG_KMEMLEAK
diff --git a/arch/riscv/include/asm/thread_info.h b/arch/riscv/include/asm/thread_info.h
index 55019fdfa9ec..93b467614b19 100644
--- a/arch/riscv/include/asm/thread_info.h
+++ b/arch/riscv/include/asm/thread_info.h
@@ -101,6 +101,73 @@ struct thread_info {
 void arch_release_task_struct(struct task_struct *tsk);
 int arch_dup_task_struct(struct task_struct *dst, struct task_struct *src);
 
+/*
+ * RISC-V stack frame layout (with frame pointer enabled).
+ *
+ * Reference: RISC-V ELF psABI, Frame Pointer Convention
+ *   https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-cc.adoc#frame-pointer-convention
+ *
+ * high addr
+ *   +------------------+  <--- fp (s0) points here
+ *   |   saved ra       |  fp - 1*sizeof(void*) (return address)
+ *   |   saved fp       |  fp - 2*sizeof(void*) (previous frame pointer)
+ *   +------------------+
+ *   |   local vars     |
+ *   |   arguments      |
+ *   +------------------+  <--- sp
+ * low addr
+ *
+ * The struct stackframe { fp, ra } lives at (fp - sizeof(stackframe)),
+ * i.e. fp[-2]=saved_fp and fp[-1]=saved_ra.
+ *
+ * For usercopy safety, we allow copies within [prev_fp, fp - 2*sizeof(void*))
+ * for each frame in the chain, where prev_fp is the fp of the previous
+ * (lower) frame.  This covers local variables and arguments but excludes
+ * the saved ra/fp slots at the top of the frame.
+ *
+ * We walk the frame chain starting from __builtin_frame_address(0) (the
+ * current frame), with prev_fp initialized to current_stack_pointer.
+ * Using current_stack_pointer -- rather than the 'stack' argument (which is
+ * the thread's entire stack base) -- ensures that objects in already-returned
+ * frames (address below current sp) are correctly detected as BAD_STACK,
+ * because no live frame in the chain will claim that region.
+ */
+__no_kmsan_checks
+static inline int arch_within_stack_frames(const void * const stack,
+					   const void * const stackend,
+					   const void *obj, unsigned long len)
+{
+#if defined(CONFIG_FRAME_POINTER)
+	const void *fp = (const void *)__builtin_frame_address(0);
+	const void *prev_fp = (const void *)current_stack_pointer;
+
+	/*
+	 * Walk the frame chain. Each iteration checks whether [obj, obj+len)
+	 * falls within the local-variable area of the current frame:
+	 *
+	 *   [prev_fp, fp - 2*sizeof(void*))
+	 *
+	 * i.e. from the base of this frame (sp of this frame, which equals
+	 * the fp of the frame below) up to (but not including) the saved
+	 * fp/ra area at the top of this frame.
+	 */
+	while (stack + 2 * sizeof(void *) <= fp && fp < stackend) {
+		const void *frame_vars_end = (const char *)fp - 2 * sizeof(void *);
+
+		if (obj + len <= frame_vars_end) {
+			if (obj >= prev_fp)
+				return GOOD_FRAME;
+			return BAD_STACK;
+		}
+		prev_fp = fp;
+		fp = *(const void * const *)frame_vars_end;
+	}
+	return BAD_STACK;
+#else
+	return NOT_STACK;
+#endif
+}
+
 #endif /* !__ASSEMBLER__ */
 
 /*
-- 
2.50.1



From m.wilczynski at samsung.com  Mon Jun  8 03:08:37 2026
From: m.wilczynski at samsung.com (Michal Wilczynski)
Date: Mon, 8 Jun 2026 12:08:37 +0200
Subject: [PATCH v2 2/2] pwm: th1520: Lock clock rate with
 clk_rate_exclusive_get
In-Reply-To: <20260605-rate-exclusive-get-th1520-v2-2-695640bf7249@mailbox.org>
References: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>
	<CGME20260605070115eucas1p14ef31f75a9597be42bda6c6597fc7e38@eucas1p1.samsung.com>
	<20260605-rate-exclusive-get-th1520-v2-2-695640bf7249@mailbox.org>
Message-ID: <2c036c0e-8246-4e55-90b0-97ba8ef46115@samsung.com>



On 6/5/26 09:00, Maurice Hieronymus wrote:
> The driver derives period and duty cycle from the clock rate read at
> probe, so a later rate change would silently miscompute waveforms.
> Switch to the new ExclusiveClk wrapper to hold the rate for the lifetime
> of the driver data and drop the corresponding TODO.
> 
> Reviewed-by: Alice Ryhl <aliceryhl at google.com>
> Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>
> ---
>  drivers/pwm/pwm_th1520.rs | 8 +++-----
>  1 file changed, 3 insertions(+), 5 deletions(-)
> 

Reviewed-by: Michal Wilczynski <m.wilczynski at samsung.com>



From conor at kernel.org  Mon Jun  8 03:14:42 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 8 Jun 2026 11:14:42 +0100
Subject: [GIT PULL] Microchip RISC-V devicetrees for v7.2
Message-ID: <20260608-grumbling-gigantic-b0bb128634f2@spud>

Hey folks,

Please pull my changes for 7.2, all of which are cleanup/low priority
fixes written by yours truly.

It's probable that I will have a second PR, because I am waiting for
Stephen to hopefully merge my Canaan clock driver series that is a
pre-requisite for the addition of the Canaan k230 SoC. I'd have sent
this earlier, but I was hoping that k230 support would be ready in time.

Cheers,
Conor.

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ riscv-dt-for-v7.2

for you to fetch changes up to 3869417f8996fb076998342d0db560fdd795a3a6:

  riscv: dts: microchip: remove redudant enabling of syscontroller (2026-05-15 17:51:09 +0100)

----------------------------------------------------------------
Microchip RISC-V devicetrees for v7.2

This time around, there's nothing other than patches for Microchip
boards. All of this is low priority fixes and cleanup, centred on the
pic64gx and beaglev-fire boards. There is no new support added.

Signed-off-by: Conor Dooley <conor.dooley at microchip.com>

----------------------------------------------------------------
Conor Dooley (10):
      riscv: dts: microchip: add tsu clock to macb on pic64gx
      riscv: dts: microchip: update pic64gx gpio interrupts to better match the SoC
      riscv: dts: microchip: sort pic64gx i2c nodes alphanumerically
      riscv: dts: microchip: gpio controllers on mpfs need 2 interrupt cells
      riscv: dts: microchip: remove gpio hogs from beaglev-fire
      riscv: dts: microchip: clean up beaglev-fire regulator node names
      riscv: dts: microchip: add adc interrupt on beaglev-fire
      riscv: dts: microchip: add gpio line names on beaglev-fire
      riscv: dts: microchip: fix pic64gx gpio interrupt-cells
      riscv: dts: microchip: remove redudant enabling of syscontroller

 .../riscv/boot/dts/microchip/mpfs-beaglev-fire.dts | 37 ++++++------
 arch/riscv/boot/dts/microchip/mpfs-disco-kit.dts   |  4 --
 .../boot/dts/microchip/mpfs-icicle-kit-common.dtsi |  4 --
 arch/riscv/boot/dts/microchip/mpfs-m100pfsevp.dts  |  4 --
 arch/riscv/boot/dts/microchip/mpfs-polarberry.dts  |  4 --
 arch/riscv/boot/dts/microchip/mpfs-sev-kit.dts     |  4 --
 arch/riscv/boot/dts/microchip/mpfs-tysom-m.dts     |  4 --
 arch/riscv/boot/dts/microchip/mpfs.dtsi            |  6 +-
 .../boot/dts/microchip/pic64gx-curiosity-kit.dts   | 67 ++++++++++++----------
 arch/riscv/boot/dts/microchip/pic64gx.dtsi         | 46 +++++++++++----
 10 files changed, 95 insertions(+), 85 deletions(-)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260608/f6bacaec/attachment.sig>

From daniel.almeida at collabora.com  Mon Jun  8 04:08:04 2026
From: daniel.almeida at collabora.com (Daniel Almeida)
Date: Mon, 8 Jun 2026 08:08:04 -0300
Subject: [PATCH v2 0/2] rust: clk: Add ExclusiveClk and use it in
 pwm-th1520
In-Reply-To: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>
References: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>
Message-ID: <140FE1B3-73CA-45EA-B978-648A1A48B577@collabora.com>

Hi Maurice,

There is some ongoing work to convert Clks to a type state pattern [0]

I wonder if you would be willing to rebase on top of that?
I can push a new version if so.

It seems like we are mostly in agreement with that series, and only
a few nits are missing.

? Daniel

[0]: https://lore.kernel.org/rust-for-linux/20260107-clk-type-state-v3-0-77d3e3ee59c2 at collabora.com/

From work at onurozkan.dev  Mon Jun  8 04:09:13 2026
From: work at onurozkan.dev (=?UTF-8?q?Onur=20=C3=96zkan?=)
Date: Mon,  8 Jun 2026 14:09:13 +0300
Subject: [PATCH v2 1/2] rust: clk: Add ExclusiveClk wrapper for clk_rate_exclusive_get
In-Reply-To: <20260605-rate-exclusive-get-th1520-v2-1-695640bf7249@mailbox.org>
References: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org> <20260605-rate-exclusive-get-th1520-v2-1-695640bf7249@mailbox.org>
Message-ID: <20260608110920.422773-1-work@onurozkan.dev>

On Fri, 05 Jun 2026 08:59:59 +0200
Maurice Hieronymus <mhi at mailbox.org> wrote:

> Add Rust bindings for clk_rate_exclusive_get() and
> clk_rate_exclusive_put().
> 
> Clk::rate_exclusive_get() consumes the Clk and returns an ExclusiveClk;
> the matching put is issued from its Drop impl. ExclusiveClk derefs to
> Clk so existing rate / prepare / enable APIs remain available on the
> locked handle.
> 
> Reviewed-by: Alice Ryhl <aliceryhl at google.com>
> Signed-off-by: Maurice Hieronymus <mhi at mailbox.org>
> ---
>  rust/kernel/clk.rs | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 60 insertions(+)
> 
> diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
> index 7abbd0767d8c..f834f4833f18 100644
> --- a/rust/kernel/clk.rs
> +++ b/rust/kernel/clk.rs
> @@ -249,6 +249,22 @@ pub fn set_rate(&self, rate: Hertz) -> Result {
>              // [`clk_set_rate`].
>              to_result(unsafe { bindings::clk_set_rate(self.as_raw(), rate.as_hz()) })
>          }
> +
> +        /// Acquire exclusive control over the clock's rate.
> +        ///
> +        /// Consumes the [`Clk`] and returns an [`ExclusiveClk`] that releases the exclusivity
> +        /// when dropped. While held, no other consumer may change the clock's rate.
> +        ///
> +        /// Equivalent to the kernel's [`clk_rate_exclusive_get`] API. Must not be called from
> +        /// atomic context.
> +        ///
> +        /// [`clk_rate_exclusive_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_rate_exclusive_get
> +        pub fn rate_exclusive_get(self) -> Result<ExclusiveClk> {
> +            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> +            // [`clk_rate_exclusive_get`].
> +            to_result(unsafe { bindings::clk_rate_exclusive_get(self.as_raw()) })?;
> +            Ok(ExclusiveClk(self))
> +        }

We usually inline FFI wrappers.

>      }
>  
>      impl Drop for Clk {
> @@ -329,6 +345,50 @@ fn deref(&self) -> &Clk {
>              &self.0
>          }
>      }
> +
> +    /// A [`Clk`] with exclusive control over its rate.
> +    ///
> +    /// While an [`ExclusiveClk`] exists, no other consumer of the same clock may change its rate.
> +    /// Obtained by calling [`Clk::rate_exclusive_get`]; the exclusivity is released automatically
> +    /// when the value is dropped, after which the inner [`Clk`] is dropped as usual.
> +    ///
> +    /// # Invariants
> +    ///
> +    /// An [`ExclusiveClk`] instance owns a [`Clk`] for which `clk_rate_exclusive_get` has been
> +    /// called and the matching `clk_rate_exclusive_put` has not yet been called.
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// use kernel::clk::{Clk, ExclusiveClk};
> +    /// use kernel::device::Device;
> +    /// use kernel::error::Result;
> +    ///
> +    /// fn lock_rate(dev: &Device) -> Result<ExclusiveClk> {
> +    ///     let clk = Clk::get(dev, None)?;
> +    ///     clk.prepare_enable()?;
> +    ///     clk.rate_exclusive_get()
> +    /// }
> +    /// ```
> +    pub struct ExclusiveClk(Clk);
> +
> +    // Make [`ExclusiveClk`] behave like [`Clk`].
> +    impl Deref for ExclusiveClk {
> +        type Target = Clk;
> +
> +        fn deref(&self) -> &Clk {
> +            &self.0
> +        }
> +    }
> +
> +    impl Drop for ExclusiveClk {
> +        fn drop(&mut self) {
> +            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> +            // [`clk_rate_exclusive_put`] and balances the [`clk_rate_exclusive_get`] call from
> +            // [`Clk::rate_exclusive_get`].

I think [`...`] wouldn't work on regular comments. They are only for
doc-comments.

Thanks,
Onur

> +            unsafe { bindings::clk_rate_exclusive_put(self.as_raw()) };
> +        }
> +    }
>  }
>  
>  #[cfg(CONFIG_COMMON_CLK)]
> 
> -- 
> 2.51.2
> 


From conor at kernel.org  Mon Jun  8 04:16:19 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 8 Jun 2026 12:16:19 +0100
Subject: [GIT PULL] Microchip RISC-V soc drivers for v7.2
Message-ID: <20260608-vacant-slit-9499ba5eb8f2@spud>

Hey folks,

Another single patch PR here, this time with a binding change.

Cheers,
Conor.

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ riscv-soc-drivers-for-v7.2

for you to fetch changes up to 17d9064987ca4e0b05b670da48ca93edb0796810:

  dt-bindings: soc: microchip: document irqmux on pic64gx (2026-05-21 11:00:05 +0100)

----------------------------------------------------------------
Microchip RISC-V soc drivers for v7.2

A single dt-binding compatible addition for the irqmux on pic64gx.

Signed-off-by: Conor Dooley <conor.dooley at microchip.com>

----------------------------------------------------------------
Conor Dooley (1):
      dt-bindings: soc: microchip: document irqmux on pic64gx

 .../devicetree/bindings/soc/microchip/microchip,mpfs-irqmux.yaml    | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260608/c3dad0cc/attachment.sig>

From fanwenhui at masscore.cn  Mon Jun  8 04:59:35 2026
From: fanwenhui at masscore.cn (Wenhui Fan)
Date: Mon,  8 Jun 2026 19:59:35 +0800
Subject: [PATCH] irqchip/riscv-imsic: Fix IPI target CPU mapping for sparse hartid topology
Message-ID: <20260608115935.2194813-1-fanwenhui@masscore.cn>

When the system has sparse hartid topology (e.g., only hart0 and hart8
are online), the current IMSIC driver incorrectly calculates the MSI
MMIO offset for each CPU. This causes IPIs targeting hart8 to be
misdirected to hart1.

The root cause is that in imsic_setup_state(), the MMIO offset is
calculated using the parent interrupt index 'i' rather than the actual
hartid:
    reloff = i * BIT(global->guest_index_bits) * IMSIC_MMIO_PAGE_SZ;

This assumes a contiguous hartid space, which is not guaranteed in all
systems. When only hart0 and hart8 are online, the driver receives
nr_parent_irqs=2, with i=0 for hart0 and i=1 for hart8.

Using i=1 for hart8 results in using the wrong offset which is intended
for hart1, and causes the MSI configured for hart8 to incorrectly access
hart1's MSI page.

Fix this by using the actual hartid for offset calculation:
    reloff = hartid * BIT(global->guest_index_bits) * IMSIC_MMIO_PAGE_SZ;

Fixes: 21a8f8a0eb35 ("irqchip: Add RISC-V incoming MSI controller early driver")
Signed-off-by: Wenhui Fan <fanwenhui at masscore.cn>
---
 drivers/irqchip/irq-riscv-imsic-state.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
index e3ed874d8..5f737ec36 100644
--- a/drivers/irqchip/irq-riscv-imsic-state.c
+++ b/drivers/irqchip/irq-riscv-imsic-state.c
@@ -894,7 +894,7 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
 
 		/* Find MMIO location of MSI page */
 		index = nr_mmios;
-		reloff = i * BIT(global->guest_index_bits) *
+		reloff = hartid * BIT(global->guest_index_bits) *
 			 IMSIC_MMIO_PAGE_SZ;
 		for (j = 0; nr_mmios; j++) {
 			if (reloff < resource_size(&mmios[j])) {
-- 
2.43.0



From josh.milas at gmail.com  Mon Jun  8 05:06:17 2026
From: josh.milas at gmail.com (Joshua Milas)
Date: Mon, 8 Jun 2026 08:06:17 -0400
Subject: [PATCH v5 RESEND 5/5] riscv64: dts: sophgo: add initial Milk-V
 Duo S board support
In-Reply-To: <DJ0ZYF5C8MMH.2GBBY188VVPSH@mailbox.org>
References: <20260530173347.33533-1-josh.milas@gmail.com>
 <20260530173347.33533-6-josh.milas@gmail.com>
 <DJ0ZYF5C8MMH.2GBBY188VVPSH@mailbox.org>
Message-ID: <aiawOUHBcKtMVEZk@sleek>

Hi Shuwei,

Thanks for testing! I am seeing the same wifi issue on my end and have been
looking into it so it may not be a config issue.

I was able to get the chip enumerated by adding some properties to the sdhci1
node and adding some quirks to the kernel source on reset. I was also not able
to get the chip powered without manually toggling PORTA pin 15 in code. Then I
tried using the aic8800 1.0.9 dkms module however it needs some changes because
it is not updated for Linux 7.1. I did find some Milk-V Duo S AIC8800 drivers
and will give it a shot soon.

Thanks again,
- Joshua Milas


From josh.milas at gmail.com  Mon Jun  8 05:06:59 2026
From: josh.milas at gmail.com (Joshua Milas)
Date: Mon, 8 Jun 2026 08:06:59 -0400
Subject: [PATCH v5 RESEND 4/5] riscv64: dts: sophgo: add SG2000 dtsi
In-Reply-To: <DJ10GDDAE672.1N365YARL5KV1@mailbox.org>
References: <20260530173347.33533-1-josh.milas@gmail.com>
 <20260530173347.33533-5-josh.milas@gmail.com>
 <DJ10GDDAE672.1N365YARL5KV1@mailbox.org>
Message-ID: <aiawY8BlHlSFXbSJ@sleek>

Hi Shuwei,

The 256 MB was not intentional and was a holdover from testing. I updated the
DT to use 512 MB of RAM. The issue was only on the riscv side. This will be
fixed in the next patch.

- Joshua Milas


From david at kernel.org  Mon Jun  8 05:43:52 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Mon, 8 Jun 2026 14:43:52 +0200
Subject: [PATCH v3] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
In-Reply-To: <953d7a60-456d-4629-b133-afce62cc5b3e@iscas.ac.cn>
References: <20260605-mark-after-vmemmap-populate-v3-1-a06001ac9264@iscas.ac.cn>
 <da19ffcf-8042-4f96-9c2d-649468dc6a0a@kernel.org>
 <953d7a60-456d-4629-b133-afce62cc5b3e@iscas.ac.cn>
Message-ID: <3c88dee8-6fcd-4f72-9a73-17044214b087@kernel.org>

On 6/8/26 04:24, Vivian Wang wrote:
> On 6/5/26 17:16, David Hildenbrand (Arm) wrote:
>> On 6/5/26 07:23, Vivian Wang wrote:
>>> section_activate() does not flush TLB after populating new vmemmap
>>> pages. On most architectures, this is okay. However it is a problem on
>>> RISC-V since there the TLB caching non-present entries is permitted,
>>> which causes spurious faults on some hardwares.
>>>
>>> This seems to be most easily reproduced with DEBUG_VM=y and
>>> PAGE_POISONING=y, which causes these newly mapped struct pages to be
>>> poisoned i.e. written to immediately after mapping.
>>>
>>> Add a hook vmemmap_populate_finalize() in __populate_section_memmap()
>>> after population, to allow architectures to handle such situations as
>>> needed. Then implement it on RISC-V to arrange for the existing
>>> exception handler code to deal with these faults if they happen.
>>>
>>> Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
>>> ---
>>> Depends on my earlier kfence fixes for mark_new_valid_map() [1].
>>>
>>> Found while testing AMD_HSA/ZONE_DEVICE on SpacemiT K3. Using
>>> ZONE_DEVICE requires another fix [2].
>>>
>>> [1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn
>>> [2]: https://lore.kernel.org/linux-riscv/20260309-riscv-sparsemem-vmemmap-limits-v1-2-f40efe18e3cd at iscas.ac.cn
>>> ---
>>> Changes in v3:
>>> - Merged back into one patch (Mike)
>>> - (No code changes otherwise.)
>>> - Link to v2: https://patch.msgid.link/20260604-mark-after-vmemmap-populate-v2-0-ab6a7d03b434 at iscas.ac.cn
>>>
>>> Changes in v2:
>>> - Split patch in two, hook point and riscv hook 
>>> - Explain hook necessity in patch 1 message (Mike)
>>> - Make hook #define based (Mike)
>>> - Call finalize hook only on populate success
>>> - Link to v1: https://patch.msgid.link/20260525-mark-after-vmemmap-populate-v1-1-e698d859ba16 at iscas.ac.cn
>>> ---
>>>  arch/riscv/include/asm/pgtable.h | 4 ++++
>>>  arch/riscv/mm/init.c             | 6 ++++++
>>>  mm/sparse-vmemmap.c              | 8 ++++++++
>>>  3 files changed, 18 insertions(+)
>>>
>>> diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
>>> index a1a7c6520a09..aa0f50e3d534 100644
>>> --- a/arch/riscv/include/asm/pgtable.h
>>> +++ b/arch/riscv/include/asm/pgtable.h
>>> @@ -1243,6 +1243,10 @@ static inline pte_t pte_swp_clear_exclusive(pte_t pte)
>>>  #define TASK_SIZE	FIXADDR_START
>>>  #endif
>>>  
>>> +/* Needed on SPARSEMEM_VMEMMAP */
>>> +#define vmemmap_populate_finalize vmemmap_populate_finalize
>>> +void __meminit vmemmap_populate_finalize(void);
>>> +
>>>  #else /* CONFIG_MMU */
>>>  
>>>  #define PAGE_SHARED		__pgprot(0)
>>> diff --git a/arch/riscv/mm/init.c b/arch/riscv/mm/init.c
>>> index 706f43523935..cf9ae4099f82 100644
>>> --- a/arch/riscv/mm/init.c
>>> +++ b/arch/riscv/mm/init.c
>>> @@ -1360,6 +1360,12 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
>>>  	 */
>>>  	return vmemmap_populate_hugepages(start, end, node, altmap);
>>>  }
>>> +
>>> +void __meminit vmemmap_populate_finalize(void)
>>> +{
>>> +	/* Avoid faults on cached non-present TLB entries. */
>>> +	mark_new_valid_map();
>>> +}
>>>  #endif
>> How does mark_new_valid_map() handle concurrent access?
>>
>> There is some comment in there, but I am not sure if that actually implies that
>> mark_new_valid_map() can be called concurrently from arbitrary context?
> 
> AFAICT, yes, it is intended to be used concurrently from arbitrary
> context, and this is why I used them.
> 
> I had not originally written the code, so some riscv maintainer can
> maybe chime in on this, but as I understand it the idea is that we only
> ever set bits in the bitmap in mark_new_valid_map() while "allocating",
> whereas the assembly code in handle_exception in
> arch/riscv/kernel/entry.S only ever clears individual bits. So at least
> the access to the bitmap itself should be fine.

Right, flush_cache_vmap() looks like a bitmap_set() -- non-atomically.

.Lnew_vmalloc_kernel_address does an atomic bitmap clearing ("Atomically reset
the current cpu bit in new_vmalloc").

I am primarily wondering whether we'd want atomic bit-setting as well?

> 
> This was added in commit 503638e0babf ("riscv: Stop emitting preventive
> sfence.vma for new vmalloc mappings").
> 
> Do you think the mark_new_valid_map() function needs extra
> synchronization like smp_wmb()?

Right, I wonder about atomic access, but also about memory barriers.

-- 
Cheers,

David


From rafael at kernel.org  Mon Jun  8 05:50:32 2026
From: rafael at kernel.org (Rafael J. Wysocki)
Date: Mon, 8 Jun 2026 14:50:32 +0200
Subject: [PATCH v2 5/6] ACPI/IORT: Implement ACPI infrastructure to enable
 GICv5 IWB probe deferral
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-5-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-5-23ffa16b6ebb@kernel.org>
Message-ID: <CAJZ5v0g86XVdkFE0W9xii1XdUMPX0tOd83_SvYDao+YjvYo4kg@mail.gmail.com>

On Wed, Jun 3, 2026 at 10:21?AM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
>
> Implement an IORT ACPI hook to retrieve the acpi_handle of the interrupt
> controller handling a specific GSI (if any, on GICv5 systems only the IWB
> is represented in firmware with an ACPI device object) and add the IWB to
> the list of devices whose dependencies can be detected (and cleared) in
> ACPI core to guarantee that probe dependencies for the IWB can be
> satisfied.
>
> Enable autodep detection for arm64 by adding the arch_acpi_add_auto_dep()
> callback in the ACPI IORT driver.
>
> Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> Cc: Hanjun Guo <guohanjun at huawei.com>
> Cc: Sudeep Holla <sudeep.holla at kernel.org>
> Cc: "Rafael J. Wysocki" <rafael at kernel.org>

Acked-by: "Rafael J. Wysocki" (Intel) <rafael at kernel.org> # ACPI: scan.c

The rest of the series is kind of outside my scope and all of the
previous patches would at least require an ACK from the RISC-V people.

> ---
>  drivers/acpi/arm64/iort.c | 22 +++++++++++++++++++---
>  drivers/acpi/scan.c       |  1 +
>  include/linux/acpi_iort.h |  3 ++-
>  3 files changed, 22 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/acpi/arm64/iort.c b/drivers/acpi/arm64/iort.c
> index af7a9b2fd5bc..34412cd697d8 100644
> --- a/drivers/acpi/arm64/iort.c
> +++ b/drivers/acpi/arm64/iort.c
> @@ -789,11 +789,9 @@ struct irq_domain *iort_get_device_domain(struct device *dev, u32 id,
>         return irq_find_matching_fwnode(handle, bus_token);
>  }
>
> -struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
> +acpi_handle iort_iwb_handle(u32 iwb_id)
>  {
> -       struct fwnode_handle *fwnode;
>         struct acpi_iort_node *node;
> -       struct acpi_device *device;
>         struct acpi_iort_iwb *iwb;
>         acpi_status status;
>         acpi_handle handle;
> @@ -808,6 +806,19 @@ struct fwnode_handle *iort_iwb_handle(u32 iwb_id)
>         if (ACPI_FAILURE(status))
>                 return NULL;
>
> +       return handle;
> +}
> +
> +struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id)
> +{
> +       struct fwnode_handle *fwnode;
> +       struct acpi_device *device;
> +       acpi_handle handle;
> +
> +       handle = iort_iwb_handle(iwb_id);
> +       if (!handle)
> +               return NULL;
> +
>         device = acpi_get_acpi_dev(handle);
>         if (!device)
>                 return NULL;
> @@ -2090,6 +2101,11 @@ static void __init iort_init_platform_devices(void)
>         }
>  }
>
> +u32 arch_acpi_add_auto_dep(acpi_handle handle)
> +{
> +       return acpi_irq_add_auto_dep(handle);
> +}
> +
>  void __init acpi_iort_init(void)
>  {
>         acpi_status status;
> diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
> index 530547cda8b2..ba15da9058dc 100644
> --- a/drivers/acpi/scan.c
> +++ b/drivers/acpi/scan.c
> @@ -856,6 +856,7 @@ static const char * const acpi_ignore_dep_ids[] = {
>
>  /* List of HIDs for which we honor deps of matching ACPI devs, when checking _DEP lists. */
>  static const char * const acpi_honor_dep_ids[] = {
> +       "ARMH0003", /* ARM GICv5 IWB */
>         "INT3472", /* Camera sensor PMIC / clk and regulator info */
>         "INTC1059", /* IVSC (TGL) driver must be loaded to allow i2c access to camera sensors */
>         "INTC1095", /* IVSC (ADL) driver must be loaded to allow i2c access to camera sensors */
> diff --git a/include/linux/acpi_iort.h b/include/linux/acpi_iort.h
> index 17bb3374f4ca..931eaa7bbf6a 100644
> --- a/include/linux/acpi_iort.h
> +++ b/include/linux/acpi_iort.h
> @@ -27,7 +27,8 @@ int iort_register_domain_token(int trans_id, phys_addr_t base,
>                                struct fwnode_handle *fw_node);
>  void iort_deregister_domain_token(int trans_id);
>  struct fwnode_handle *iort_find_domain_token(int trans_id);
> -struct fwnode_handle *iort_iwb_handle(u32 iwb_id);
> +acpi_handle iort_iwb_handle(u32 iwb_id);
> +struct fwnode_handle *iort_iwb_handle_fwnode(u32 iwb_id);
>
>  #ifdef CONFIG_ACPI_IORT
>  u32 iort_msi_map_id(struct device *dev, u32 id);
>
> --
> 2.54.0
>


From david at kernel.org  Mon Jun  8 06:18:40 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Mon, 8 Jun 2026 15:18:40 +0200
Subject: [PATCH v3] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
In-Reply-To: <3c88dee8-6fcd-4f72-9a73-17044214b087@kernel.org>
References: <20260605-mark-after-vmemmap-populate-v3-1-a06001ac9264@iscas.ac.cn>
 <da19ffcf-8042-4f96-9c2d-649468dc6a0a@kernel.org>
 <953d7a60-456d-4629-b133-afce62cc5b3e@iscas.ac.cn>
 <3c88dee8-6fcd-4f72-9a73-17044214b087@kernel.org>
Message-ID: <6a92f2c6-3b67-44fb-b645-91164118d8fb@kernel.org>

On 6/8/26 14:43, David Hildenbrand (Arm) wrote:
> On 6/8/26 04:24, Vivian Wang wrote:
>> On 6/5/26 17:16, David Hildenbrand (Arm) wrote:
>>> How does mark_new_valid_map() handle concurrent access?
>>>
>>> There is some comment in there, but I am not sure if that actually implies that
>>> mark_new_valid_map() can be called concurrently from arbitrary context?
>>
>> AFAICT, yes, it is intended to be used concurrently from arbitrary
>> context, and this is why I used them.
>>
>> I had not originally written the code, so some riscv maintainer can
>> maybe chime in on this, but as I understand it the idea is that we only
>> ever set bits in the bitmap in mark_new_valid_map() while "allocating",
>> whereas the assembly code in handle_exception in
>> arch/riscv/kernel/entry.S only ever clears individual bits. So at least
>> the access to the bitmap itself should be fine.
> 
> Right, flush_cache_vmap() looks like a bitmap_set() -- non-atomically.
> 
> .Lnew_vmalloc_kernel_address does an atomic bitmap clearing ("Atomically reset
> the current cpu bit in new_vmalloc").
> 
> I am primarily wondering whether we'd want atomic bit-setting as well?
> 
>>
>> This was added in commit 503638e0babf ("riscv: Stop emitting preventive
>> sfence.vma for new vmalloc mappings").
>>
>> Do you think the mark_new_valid_map() function needs extra
>> synchronization like smp_wmb()?
> 
> Right, I wonder about atomic access, but also about memory barriers.
> 

BTW, does riscv support a better mechanism to avoid such spurious faults?

E.g., on arm64 we have emit_pte_barriers() where we issue some barriers:

"The isb ensures that any previous speculative "invalid translation" marker that
is in the CPU's pipeline gets cleared, so that any access to that address after
setting the pte to valid won't cause a spurious fault."

I assume the riscv case is different, as it's about actual TLB entries, and not
just translation markers in the pipeline?

-- 
Cheers,

David


From josh.milas at gmail.com  Mon Jun  8 06:28:10 2026
From: josh.milas at gmail.com (Joshua Milas)
Date: Mon, 8 Jun 2026 09:28:10 -0400
Subject: [PATCH v5 RESEND 0/5] Add initial Milk-V Duo S board support
In-Reply-To: <ahteTfYC5QMlpjF2@inochi.infowork>
References: <20260530173347.33533-1-josh.milas@gmail.com>
 <ahteTfYC5QMlpjF2@inochi.infowork>
Message-ID: <aibDam5mwkaIJhHw@sleek>

Hi Inochi,

Thanks for the feedback. The next patch will have a large change with the
pinctrl, I believe I will have to drop the tags for that. For my reference
would the tags be applied to the commits or the top level patch?

I have the pinctrl configs staged in my tree but I am having some issues.

1. spi3 conflicts with sdhci1 (wifi) when enabled since they share pins,
   I am not sure how the original DT had it working. Im assuming they had it
   enabled and the user controlled it through the pinmux program? We originally
   tried to enable only what the vendor had in their DT. Taking another look
   at the vendor DT spi3 is the only SPI enabled, so we probably should not
   choose a different spi node. Should we just disable spi3?
2. I am having trouble getting the card to enumerate with just the DT. I was
   able to get it enumerated with some kernel changes and I am trying
   to translate those changes into the DT.
3. I added at least one pinctrl config for each device. For the devices that
   have multiple selections, should I add all the configs?

Have a great day,
- Joshua Milas


From thecharlesjenkins at gmail.com  Mon Jun  8 06:54:48 2026
From: thecharlesjenkins at gmail.com (Charlie Jenkins)
Date: Mon, 8 Jun 2026 06:54:48 -0700
Subject: [PATCH v7 1/2] clocksource/drivers/timer-clint: Add ZICNTR
 support
In-Reply-To: <20260525182124.19402-1-jtaubepe@redhat.com>
References: <20260525182124.19402-1-jtaubepe@redhat.com>
Message-ID: <aibJqFKQjCe30ejT@blinky>

On Mon, May 25, 2026 at 02:21:23PM -0400, Jesse Taube wrote:
> ZICNTR allows the CPU time to be read using CSRs, which used to be the
> default. If ZICNTR is supported prefer using CSRs over MMIO.
> This may also be faster as CSRs are not emulated in M-mode.

I think the rationale can be cleaned up a bit here. You say it "may" be
faster, if it's not guaranteed to be faster, why prefer it over mmio?

The patch d5be89a8d118 ("RISC-V: Resurrect the MMIO timer implementation
for M-mode systems") is the one that changed this behavior, can you
include a reference to that patch to point out when it was the default?

> 
> Signed-off-by: Jesse Taube <jtaubepe at redhat.com>
> ---
> Treat this as a completely new patch, as it is mostly rewritten.
> Original:
> https://lore.kernel.org/all/20240410142347.964-3-jszhang at kernel.org/
> V3 -> V4:
>  - Add riscv,csr-clint
>  - Allow using of CSRs in S mode
>  - Change if return else return to if return return
>  - Change static_branch_likely to static_branch_unlikely
>  - Fix 32-bit clint_get_cycles64 csr_available check being inverted
>  - Fix is_c900_clint being uninitialized
> V4 -> V5:
>  - Remove riscv,csr-clint
>  - Remove riscv_csr_time_available
>  - Replace all static_branch_unlikely(&riscv_csr_time_available) with
>     riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR)
> V5 -> V6:
>  - Add csr_clock_next_event
>  - Add csr_get_cycles64 to sched_clock_register
>  - Break get_cycles64 into csr_get_cycles64 and clint_get_cycles64
>  - Change default behavior to use CSR time register
> V6 -> V7:
>  - Split csr and c900 parts into different commits
> 
> Posible future work:
>  - Check for SSTC support and use stimercmp
>  - SSTC depends on smode which cpufeature doesnt check for.
> ---
>  arch/riscv/include/asm/timex.h    | 12 ++++++-
>  drivers/clocksource/timer-clint.c | 57 ++++++++++++++++++++++++++++---
>  2 files changed, 64 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/riscv/include/asm/timex.h b/arch/riscv/include/asm/timex.h
> index a06697846e69..d78075351bf4 100644
> --- a/arch/riscv/include/asm/timex.h
> +++ b/arch/riscv/include/asm/timex.h
> @@ -17,17 +17,26 @@ typedef unsigned long cycles_t;
>  #ifdef CONFIG_64BIT
>  static inline cycles_t get_cycles(void)
>  {
> +	if (riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR))
> +		return csr_read(CSR_TIME);
> +
>  	return readq_relaxed(clint_time_val);
>  }
>  #else /* !CONFIG_64BIT */
>  static inline u32 get_cycles(void)
>  {
> +	if (riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR))
> +		return csr_read(CSR_TIME);
> +
>  	return readl_relaxed(((u32 *)clint_time_val));
>  }
>  #define get_cycles get_cycles
>  
>  static inline u32 get_cycles_hi(void)
>  {
> +	if (riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR))
> +		return csr_read(CSR_TIMEH);
> +
>  	return readl_relaxed(((u32 *)clint_time_val) + 1);
>  }
>  #define get_cycles_hi get_cycles_hi
> @@ -40,7 +49,8 @@ static inline u32 get_cycles_hi(void)
>   */
>  static inline unsigned long random_get_entropy(void)
>  {
> -	if (unlikely(clint_time_val == NULL))
> +	if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR) &&
> +	   (unlikely(clint_time_val == NULL)))
>  		return random_get_entropy_fallback();
>  	return get_cycles();
>  }
> diff --git a/drivers/clocksource/timer-clint.c b/drivers/clocksource/timer-clint.c
> index 0bdd9d7ec545..18f7bf7d26c6 100644
> --- a/drivers/clocksource/timer-clint.c
> +++ b/drivers/clocksource/timer-clint.c
> @@ -81,6 +81,12 @@ static u64 notrace clint_get_cycles64(void)
>  {
>  	return clint_get_cycles();
>  }
> +
> +static u64 notrace csr_get_cycles64(void)
> +{
> +	return csr_read(CSR_TIME);
> +}
> +
>  #else /* CONFIG_64BIT */
>  static u64 notrace clint_get_cycles64(void)
>  {
> @@ -93,8 +99,26 @@ static u64 notrace clint_get_cycles64(void)
>  
>  	return ((u64)hi << 32) | lo;
>  }
> +
> +static u64 notrace csr_get_cycles64(void)
> +{
> +	u32 hi, lo;
> +
> +	do {
> +		hi = csr_read(CSR_TIMEH);
> +		lo = csr_read(CSR_TIME);
> +	} while (hi != csr_read(CSR_TIMEH));
> +
> +	return ((u64)hi << 32) | lo;
> +}
> +
>  #endif /* CONFIG_64BIT */
>  
> +static u64 csr_rdtime(struct clocksource *cs)
> +{
> +	return csr_get_cycles64();
> +}
> +
>  static u64 clint_rdtime(struct clocksource *cs)
>  {
>  	return clint_get_cycles64();
> @@ -105,9 +129,20 @@ static struct clocksource clint_clocksource = {
>  	.rating		= 300,
>  	.mask		= CLOCKSOURCE_MASK(64),
>  	.flags		= CLOCK_SOURCE_IS_CONTINUOUS,
> -	.read		= clint_rdtime,
> +	.read		= csr_rdtime,
>  };
>  
> +static int csr_clock_next_event(unsigned long delta,
> +				   struct clock_event_device *ce)
> +{
> +	void __iomem *r = clint_timer_cmp +
> +			  cpuid_to_hartid_map(smp_processor_id());
> +
> +	csr_set(CSR_IE, IE_TIE);
> +	writeq_relaxed(csr_get_cycles64() + delta, r);
> +	return 0;
> +}
> +
>  static int clint_clock_next_event(unsigned long delta,
>  				   struct clock_event_device *ce)
>  {
> @@ -123,13 +158,16 @@ static DEFINE_PER_CPU(struct clock_event_device, clint_clock_event) = {
>  	.name		= "clint_clockevent",
>  	.features	= CLOCK_EVT_FEAT_ONESHOT,
>  	.rating		= 100,
> -	.set_next_event	= clint_clock_next_event,
> +	.set_next_event	= csr_clock_next_event,
>  };
>  
>  static int clint_timer_starting_cpu(unsigned int cpu)
>  {
>  	struct clock_event_device *ce = per_cpu_ptr(&clint_clock_event, cpu);
>  
> +	if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR))
> +		ce->set_next_event = clint_clock_next_event;
> +
>  	ce->cpumask = cpumask_of(cpu);
>  	clockevents_config_and_register(ce, clint_timer_freq, 100, ULONG_MAX);
>  
> @@ -161,7 +199,7 @@ static irqreturn_t clint_timer_interrupt(int irq, void *dev_id)
>  	return IRQ_HANDLED;
>  }
>  
> -static int __init clint_timer_init_dt(struct device_node *np)
> +static int __init clint_timer_init(struct device_node *np)
>  {
>  	int rc;
>  	u32 i, nr_irqs;
> @@ -227,13 +265,19 @@ static int __init clint_timer_init_dt(struct device_node *np)
>  
>  	pr_info("%pOFP: timer running at %ld Hz\n", np, clint_timer_freq);
>  
> +	if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR))
> +		clint_clocksource.read = clint_rdtime;
> +
>  	rc = clocksource_register_hz(&clint_clocksource, clint_timer_freq);
>  	if (rc) {
>  		pr_err("%pOFP: clocksource register failed [%d]\n", np, rc);
>  		goto fail_iounmap;
>  	}
>  
> -	sched_clock_register(clint_get_cycles64, 64, clint_timer_freq);
> +	if (riscv_has_extension_likely(RISCV_ISA_EXT_ZICNTR))
> +		sched_clock_register(csr_get_cycles64, 64, clint_timer_freq);
> +	else
> +		sched_clock_register(clint_get_cycles64, 64, clint_timer_freq);
>  
>  	rc = request_percpu_irq(clint_timer_irq, clint_timer_interrupt,
>  				 "clint-timer", &clint_clock_event);
> @@ -273,5 +317,10 @@ static int __init clint_timer_init_dt(struct device_node *np)
>  	return rc;
>  }
>  
> +static int __init clint_timer_init_dt(struct device_node *np)
> +{
> +	return clint_timer_init(np);
> +}
> +
>  TIMER_OF_DECLARE(clint_timer, "riscv,clint0", clint_timer_init_dt);
>  TIMER_OF_DECLARE(clint_timer1, "sifive,clint0", clint_timer_init_dt);
> -- 
> 2.54.0
> 
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
> 


From wangruikang at iscas.ac.cn  Mon Jun  8 07:17:33 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Mon, 8 Jun 2026 22:17:33 +0800
Subject: [PATCH v3] riscv: mm: Avoid spurious fault after hotplugging
 vmemmap
In-Reply-To: <6a92f2c6-3b67-44fb-b645-91164118d8fb@kernel.org>
References: <20260605-mark-after-vmemmap-populate-v3-1-a06001ac9264@iscas.ac.cn>
 <da19ffcf-8042-4f96-9c2d-649468dc6a0a@kernel.org>
 <953d7a60-456d-4629-b133-afce62cc5b3e@iscas.ac.cn>
 <3c88dee8-6fcd-4f72-9a73-17044214b087@kernel.org>
 <6a92f2c6-3b67-44fb-b645-91164118d8fb@kernel.org>
Message-ID: <b904d79c-7314-463b-99dc-1fae6d4ccd91@iscas.ac.cn>

On 6/8/26 21:18, David Hildenbrand (Arm) wrote:

> On 6/8/26 14:43, David Hildenbrand (Arm) wrote:
>> On 6/8/26 04:24, Vivian Wang wrote:
>>> On 6/5/26 17:16, David Hildenbrand (Arm) wrote:
>>>> How does mark_new_valid_map() handle concurrent access?
>>>>
>>>> There is some comment in there, but I am not sure if that actually implies that
>>>> mark_new_valid_map() can be called concurrently from arbitrary context?
>>> AFAICT, yes, it is intended to be used concurrently from arbitrary
>>> context, and this is why I used them.
>>>
>>> I had not originally written the code, so some riscv maintainer can
>>> maybe chime in on this, but as I understand it the idea is that we only
>>> ever set bits in the bitmap in mark_new_valid_map() while "allocating",
>>> whereas the assembly code in handle_exception in
>>> arch/riscv/kernel/entry.S only ever clears individual bits. So at least
>>> the access to the bitmap itself should be fine.
>> Right, flush_cache_vmap() looks like a bitmap_set() -- non-atomically.
>>
>> .Lnew_vmalloc_kernel_address does an atomic bitmap clearing ("Atomically reset
>> the current cpu bit in new_vmalloc").
>>
>> I am primarily wondering whether we'd want atomic bit-setting as well?
>>
>>> This was added in commit 503638e0babf ("riscv: Stop emitting preventive
>>> sfence.vma for new vmalloc mappings").
>>>
>>> Do you think the mark_new_valid_map() function needs extra
>>> synchronization like smp_wmb()?
>> Right, I wonder about atomic access, but also about memory barriers.

Oh dear, I've dug up quite the rabbit hole haven't I...

I'm going to leave that at "I don't know" for now. Maybe someone more
confident at their memory ordering knowledge can chime in.

> BTW, does riscv support a better mechanism to avoid such spurious faults?
>
> E.g., on arm64 we have emit_pte_barriers() where we issue some barriers:
>
> "The isb ensures that any previous speculative "invalid translation" marker that
> is in the CPU's pipeline gets cleared, so that any access to that address after
> setting the pte to valid won't cause a spurious fault."
>
> I assume the riscv case is different, as it's about actual TLB entries, and not
> just translation markers in the pipeline?

So yeah, conceptually the "TLB" on RISC-V caches the actual pte_t words,
and RISC-V cores are permitted to cache these valid=0 PTEs indefinitely
(if no "Svvptc" feature bit), or for a finite amount of time (if with
"Svvptc" feature bit).

As mentioned in the kfence patches [1], SpacemiT X60 cores in SpacemiT
K1 appear to be able to cache these valid=0 PTEs across even an WFI, so
the "indefinitely" part is probably real, although that doesn't mean it
isn't pipeline-only if all the WFI does is to stall the pipeline.

Not that it would really help, since RISC-V also has nothing like the
lightweight pipeline clearing stuff you mentioned defined.

Vivian "dramforever" Wang

[1]: https://lore.kernel.org/linux-riscv/20260303-handle-kfence-protect-spurious-fault-v2-0-f80d8354d79d at iscas.ac.cn/




From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Mon Jun  8 07:41:01 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Mon, 08 Jun 2026 16:41:01 +0200
Subject: [PATCH v2] riscv: Add ERRATA_MIPS_P8700_WFI to replace WFI with
 mips.pause
Message-ID: <20260608-p8700-wfi-v2-1-77efc7459f3d@htecgroup.com>

From: Djordje Todorovic <djordje.todorovic at htecgroup.com>

The MIPS P8700 has bugs with the WFI instruction. This errata
uses the RISC-V alternatives framework to patch all WFI
instructions with the MIPS P8700 pause opcode (0x00501013)
at runtime when running on P8700 hardware.

Two call sites are patched:
 - arch/riscv/kernel/head.S: secondary hart parking loop
 - arch/riscv/include/asm/processor.h: wait_for_interrupt()

Signed-off-by: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
---
This patch was tested on QEMU configured with eight P8700 harts,
as well as on the MIPS Boston board, configured with a single P8700 CPU.
Errata application was tested by disassembling with GDB on QEMU
and inserting an illegal instruction on the Boston board.
Correctness was tested with a combination of kselftests
and torture tests (rcu, locktorture), along with coremark testing.
---
Changes in v2:
- Replace .insn with .4byte in ALT_WFI macro
- Add explanatory comments
- Link to v1: https://lore.kernel.org/r/20260511-p8700-wfi-v1-1-099b1d10fcf2 at htecgroup.com
---
 arch/riscv/Kconfig.errata                    | 11 ++++++++++
 arch/riscv/errata/mips/errata.c              | 14 ++++++++++++
 arch/riscv/include/asm/errata_list.h         | 33 ++++++++++++++++++++++++++++
 arch/riscv/include/asm/errata_list_vendors.h |  5 +++--
 arch/riscv/include/asm/processor.h           |  3 ++-
 arch/riscv/kernel/head.S                     |  4 +++-
 6 files changed, 66 insertions(+), 4 deletions(-)

diff --git a/arch/riscv/Kconfig.errata b/arch/riscv/Kconfig.errata
index 3c945d086c7d0266b685f9506d58b0662af071c4..cc75e6f70513d08afeedf650b14dba83eea84632 100644
--- a/arch/riscv/Kconfig.errata
+++ b/arch/riscv/Kconfig.errata
@@ -44,6 +44,17 @@ config ERRATA_MIPS_P8700_PAUSE_OPCODE
 
 	   If you are not using the P8700 processor, say n.
 
+config ERRATA_MIPS_P8700_WFI
+	bool "Replace WFI with mips.pause for MIPS P8700"
+	depends on ERRATA_MIPS && 64BIT
+	default n
+	help
+	   The RISCV MIPS P8700 has bugs with the WFI instruction.
+	   This errata replaces all WFI instructions with the MIPS
+	   P8700 pause opcode to avoid these issues.
+
+	   If you are not using the P8700 processor, say n.
+
 config ERRATA_SIFIVE
 	bool "SiFive errata"
 	depends on RISCV_ALTERNATIVE
diff --git a/arch/riscv/errata/mips/errata.c b/arch/riscv/errata/mips/errata.c
index e984a8152208c34690f89d8101571b097485c360..67b59f8c1708ea8b7a040f7939e111b8f30e6a75 100644
--- a/arch/riscv/errata/mips/errata.c
+++ b/arch/riscv/errata/mips/errata.c
@@ -23,6 +23,17 @@ static inline bool errata_probe_pause(void)
 	return true;
 }
 
+static inline bool errata_probe_wfi(void)
+{
+	if (!IS_ENABLED(CONFIG_ERRATA_MIPS_P8700_WFI))
+		return false;
+
+	if (!riscv_isa_vendor_extension_available(MIPS_VENDOR_ID, XMIPSEXECTL))
+		return false;
+
+	return true;
+}
+
 static u32 mips_errata_probe(void)
 {
 	u32 cpu_req_errata = 0;
@@ -30,6 +41,9 @@ static u32 mips_errata_probe(void)
 	if (errata_probe_pause())
 		cpu_req_errata |= BIT(ERRATA_MIPS_P8700_PAUSE_OPCODE);
 
+	if (errata_probe_wfi())
+		cpu_req_errata |= BIT(ERRATA_MIPS_P8700_WFI);
+
 	return cpu_req_errata;
 }
 
diff --git a/arch/riscv/include/asm/errata_list.h b/arch/riscv/include/asm/errata_list.h
index 6694b5ccdcf85cfe7e767ea4de981b34f2b17b04..5c936882c42a90bac2bf40369a795d067a86d31d 100644
--- a/arch/riscv/include/asm/errata_list.h
+++ b/arch/riscv/include/asm/errata_list.h
@@ -25,6 +25,16 @@ ALTERNATIVE(__stringify(RISCV_PTR do_page_fault),			\
 	    __stringify(RISCV_PTR sifive_cip_453_page_fault_trp),	\
 	    SIFIVE_VENDOR_ID, ERRATA_SIFIVE_CIP_453,			\
 	    CONFIG_ERRATA_SIFIVE_CIP_453)
+
+#ifdef CONFIG_ERRATA_MIPS_P8700_WFI
+#define ALT_WFI								\
+ALTERNATIVE("wfi; .rept 7; nop; .endr;",				\
+	".rept 8; .4byte 0x00501013; .endr;", MIPS_VENDOR_ID,		\
+	ERRATA_MIPS_P8700_WFI, CONFIG_ERRATA_MIPS_P8700_WFI)
+#else
+#define ALT_WFI	wfi
+#endif
+
 #else /* !__ASSEMBLER__ */
 
 #define ALT_SFENCE_VMA_ASID(asid)					\
@@ -53,6 +63,29 @@ asm(ALTERNATIVE(	\
 	: /* no inputs */	\
 	: "memory")
 
+#ifdef CONFIG_ERRATA_MIPS_P8700_WFI
+/*
+ * A WFI instruction after a mispredicted branch can result in erroneous address translation
+ * on the MIPS P8700.
+ * The number of MIPS_PAUSE instructions required was determined by measuring
+ * Coremark performance on a one-core, two-hart configuration.
+ */
+#define ALT_RISCV_WFI()										\
+asm volatile(ALTERNATIVE(									\
+		"wfi\n" /* Original RISC-V wfi insn */						\
+		__nops(7),									\
+		".rept 8;" MIPS_PAUSE ".endr;\n", /* Replacement: mips.pause for P8700 */	\
+		MIPS_VENDOR_ID, /* Vendor ID to match */					\
+		ERRATA_MIPS_P8700_WFI, /* patch_id */						\
+		CONFIG_ERRATA_MIPS_P8700_WFI)							\
+		: /* no outputs */								\
+		: /* no inputs */								\
+		: "memory")
+#else
+#define ALT_RISCV_WFI()		\
+	__asm__ __volatile__ ("wfi")
+#endif
+
 /*
  * _val is marked as "will be overwritten", so need to set it to 0
  * in the default case.
diff --git a/arch/riscv/include/asm/errata_list_vendors.h b/arch/riscv/include/asm/errata_list_vendors.h
index ec7eba3734371a2d8b68fbd4cbd88a8e7135a413..4505317a6b949be602f507547fc9cd495c923e32 100644
--- a/arch/riscv/include/asm/errata_list_vendors.h
+++ b/arch/riscv/include/asm/errata_list_vendors.h
@@ -22,8 +22,9 @@
 #endif
 
 #ifdef CONFIG_ERRATA_MIPS
-#define	ERRATA_MIPS_P8700_PAUSE_OPCODE 0
-#define	ERRATA_MIPS_NUMBER 1
+#define ERRATA_MIPS_P8700_PAUSE_OPCODE 0
+#define ERRATA_MIPS_P8700_WFI 1
+#define ERRATA_MIPS_NUMBER 2
 #endif
 
 #endif /* ASM_ERRATA_LIST_VENDORS_H */
diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 4c3dd94d0f63844fecc32a7e2c1a184113ee49d9..ae4faed371c16ba33f31373561de03e89d35d04c 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -17,6 +17,7 @@
 #include <asm/alternative-macros.h>
 #include <asm/hwcap.h>
 #include <asm/usercfi.h>
+#include <asm/errata_list.h>
 
 #define arch_get_mmap_end(addr, len, flags)			\
 ({								\
@@ -176,7 +177,7 @@ extern unsigned long __get_wchan(struct task_struct *p);
 
 static inline void wait_for_interrupt(void)
 {
-	__asm__ __volatile__ ("wfi");
+	ALT_RISCV_WFI();
 }
 
 extern phys_addr_t dma32_phys_limit;
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index 9c99c5ad6fe8a32e24c8ce7e0badd63469d2c387..14935e8eec2639844c45bd37db29db74fee38a22 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -16,6 +16,8 @@
 #include <asm/scs.h>
 #include <asm/xip_fixup.h>
 #include <asm/usercfi.h>
+#include <asm/alternative.h>
+#include <asm/errata_list.h>
 #include "efi-header.S"
 
 __HEAD
@@ -196,7 +198,7 @@ secondary_start_sbi:
 	 *  - receive an early trap, before setup_trap_vector finished
 	 *  - fail in smp_callin(), as a successful one wouldn't return
 	 */
-	wfi
+	ALT_WFI
 	j .Lsecondary_park
 
 .align 2

---
base-commit: c369299895a591d96745d6492d4888259b004a9e
change-id: 20260415-p8700-wfi-9083b1d87d22

Best regards,
-- 
Aleksa Paunovic <aleksa.paunovic at htecgroup.com>




From brgl at kernel.org  Mon Jun  8 07:45:44 2026
From: brgl at kernel.org (Bartosz Golaszewski)
Date: Mon, 8 Jun 2026 07:45:44 -0700
Subject: [PATCH v3 18/21] pinctrl: starfive: Add StarFive JHB100 per2pok
 controller driver
In-Reply-To: <20260603055347.66845-19-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com> <20260603055347.66845-19-changhuang.liang@starfivetech.com>
Message-ID: <CAMRc=Md1z52A_JzMG=3Ce5nN-HMvwH0TO=t2jEqC3kdCQK8EwA@mail.gmail.com>

On Wed, 3 Jun 2026 07:53:44 +0200, Changhuang Liang
<changhuang.liang at starfivetech.com> said:
> Add pinctrl driver for StarFive JHB100 SoC Peripheral-2 Power OK
> (per2pok) pinctrl controller.
>
> Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
> ---
>  drivers/pinctrl/starfive/Kconfig              | 12 +++
>  drivers/pinctrl/starfive/Makefile             |  1 +
>  .../pinctrl-starfive-jhb100-per2pok.c         | 97 +++++++++++++++++++
>  3 files changed, 110 insertions(+)
>  create mode 100644 drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2pok.c
>
> diff --git a/drivers/pinctrl/starfive/Kconfig b/drivers/pinctrl/starfive/Kconfig
> index edc3b6d9c8d7..bf5915e0a5f2 100644
> --- a/drivers/pinctrl/starfive/Kconfig
> +++ b/drivers/pinctrl/starfive/Kconfig
> @@ -91,6 +91,18 @@ config PINCTRL_STARFIVE_JHB100_PER2
>  	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
>  	  and interrupts on input changes.
>
> +config PINCTRL_STARFIVE_JHB100_PER2POK
> +	tristate "StarFive JHB100 SoC Peripheral-2 Power OK pinctrl and GPIO driver"
> +	depends on ARCH_STARFIVE || COMPILE_TEST
> +	depends on OF

I don't see any real dependency on CONFIG_OF here, am I missing something? The
OF ID matching is available even with !CONFIG_OF.

Same elsewhere.

Bart


From asrinivasan at oss.tenstorrent.com  Mon Jun  8 08:07:25 2026
From: asrinivasan at oss.tenstorrent.com (Anirudh Srinivasan)
Date: Mon, 8 Jun 2026 10:07:25 -0500
Subject: [PATCH] irqchip/riscv-imsic: Fix IPI target CPU mapping for
 sparse hartid topology
In-Reply-To: <20260608115935.2194813-1-fanwenhui@masscore.cn>
References: <20260608115935.2194813-1-fanwenhui@masscore.cn>
Message-ID: <pbh34jxjqrwjdkavt43h3gaizdghjweq6jhcxs44knm76uaqwv@qqmmdelvb7ce>

On Mon, Jun 08, 2026 at 07:59:35PM +0800, Wenhui Fan wrote:
> When the system has sparse hartid topology (e.g., only hart0 and hart8
> are online), the current IMSIC driver incorrectly calculates the MSI
> MMIO offset for each CPU. This causes IPIs targeting hart8 to be
> misdirected to hart1.
> 
> The root cause is that in imsic_setup_state(), the MMIO offset is
> calculated using the parent interrupt index 'i' rather than the actual
> hartid:
>     reloff = i * BIT(global->guest_index_bits) * IMSIC_MMIO_PAGE_SZ;
> 
> This assumes a contiguous hartid space, which is not guaranteed in all
> systems. When only hart0 and hart8 are online, the driver receives
> nr_parent_irqs=2, with i=0 for hart0 and i=1 for hart8.
> 
> Using i=1 for hart8 results in using the wrong offset which is intended
> for hart1, and causes the MSI configured for hart8 to incorrectly access
> hart1's MSI page.
> 
> Fix this by using the actual hartid for offset calculation:
>     reloff = hartid * BIT(global->guest_index_bits) * IMSIC_MMIO_PAGE_SZ;

The IMSIC binding [1] says that multiple groups can be used if the IMSIC
files for different groups of harts aren't located contiguously in MMIO
space. I believe that this approach must be used here, rather than
patching the kernel like this. The same quirk exists with OpenSBI
(you'll need a patch similar to yours). So rather than patching both
linux and OpenSBI, you can try this solution below.

You'd have to change your IMSIC node in the DT from something like this

/* Assuming per HART IMSIC file size is 0x1000*/
interrupt-controller at 28000000 {
      compatible = "riscv,imsics";
      reg = <0x28000000 0x9000>;
};

to something like this

interrupt-controller at 28000000 {
      compatible = "riscv,imsics";
      reg = <0x28000000 0x1000>, <0x28008000 0x1000>;
};

and the existing implementation in the kernel (and opensbi) should work.


[1] https://elixir.bootlin.com/linux/v7.0/source/Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml#L28

> 
> Fixes: 21a8f8a0eb35 ("irqchip: Add RISC-V incoming MSI controller early driver")
> Signed-off-by: Wenhui Fan <fanwenhui at masscore.cn>
> ---
>  drivers/irqchip/irq-riscv-imsic-state.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
> index e3ed874d8..5f737ec36 100644
> --- a/drivers/irqchip/irq-riscv-imsic-state.c
> +++ b/drivers/irqchip/irq-riscv-imsic-state.c
> @@ -894,7 +894,7 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
>  
>  		/* Find MMIO location of MSI page */
>  		index = nr_mmios;
> -		reloff = i * BIT(global->guest_index_bits) *
> +		reloff = hartid * BIT(global->guest_index_bits) *
>  			 IMSIC_MMIO_PAGE_SZ;
>  		for (j = 0; nr_mmios; j++) {
>  			if (reloff < resource_size(&mmios[j])) {
> -- 
> 2.43.0
> 
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv


From aleksa.paunovic at htecgroup.com  Mon Jun  8 08:12:48 2026
From: aleksa.paunovic at htecgroup.com (Aleksa Paunovic)
Date: Mon, 8 Jun 2026 15:12:48 +0000
Subject: [PATCH] riscv: Add ERRATA_MIPS_P8700_WFI to replace WFI with
 mips.pause
In-Reply-To: <alpine.DEB.2.21.2605221220540.1450@angie.orcam.me.uk>
References: <alpine.DEB.2.21.2605221220540.1450@angie.orcam.me.uk>
Message-ID: <e964f45a-7f6a-4fb8-b9ba-b79dae6d687c@htecgroup.com>

Hi?Maciej,

On 5/22/26 13:22, Maciej W. Rozycki wrote:
> On Wed, 20 May 2026, Aleksa Paunovic wrote:
>
>>>> The MIPS P8700 has bugs with the WFI instruction.
>>> Has MIPS published an erratum for this?   If so, could you add a link to
>>> it in the patch description?  If not, could you please briefly describe
>>> the impact of the bug in the patch description, when WFI is used?
>> MIPS has not published an erratum for this. Briefly, a WFI instruction
>> after a mispredicted branch can result in erroneous address translation.
>  Shouldn't this be recorded next to actual code rather just the commit
> description?
>
I added the full description of the issue in v2.?

Best regards,
Aleksa

From seanwascoding at gmail.com  Mon Jun  8 08:52:52 2026
From: seanwascoding at gmail.com (Sean Chang)
Date: Mon,  8 Jun 2026 23:52:52 +0800
Subject: [PATCH v1] riscv: kvm: Use endian-specific __lelong for NACL shared memory
Message-ID: <20260608155252.4292-1-seanwascoding@gmail.com>

When compiling with sparse enabled (C=2), bitwise type warnings are
triggered in the RISC-V KVM implementation. This occurs because the
user-space data unboxing macro '__get_user_asm' performs implicit
casting on restricted types without forcing the compiler's compliance.

Additionally, raw 'unsigned long *' pointers are used to access the
SBI NACL shared memory, whereas the RISC-V SBI specification mandates
that these structures must follow little-endian byte ordering.

Fix these by:
1. Adding a '__force' cast to '__get_user_asm()' to safely suppress
   implicit cast warnings during user-space data fetching.
2. Introducing the '__lelong' type macro, which dynamically resolves to
   '__le32' or '__le64' depending on XLEN, and replacing 'unsigned long *'
   with '__lelong *' to enforce proper compile-time endianness checks.

Signed-off-by: Sean Chang <seanwascoding at gmail.com>
---
 arch/riscv/include/asm/kvm_nacl.h | 14 ++++++++------
 arch/riscv/include/asm/uaccess.h  |  2 +-
 arch/riscv/kvm/nacl.c             |  2 +-
 3 files changed, 10 insertions(+), 8 deletions(-)

diff --git a/arch/riscv/include/asm/kvm_nacl.h b/arch/riscv/include/asm/kvm_nacl.h
index 4124d5e06a0f..f45407bcaa26 100644
--- a/arch/riscv/include/asm/kvm_nacl.h
+++ b/arch/riscv/include/asm/kvm_nacl.h
@@ -60,9 +60,11 @@ int kvm_riscv_nacl_init(void);
 #ifdef CONFIG_32BIT
 #define lelong_to_cpu(__x)	le32_to_cpu(__x)
 #define cpu_to_lelong(__x)	cpu_to_le32(__x)
+#define __lelong                __le32
 #else
 #define lelong_to_cpu(__x)	le64_to_cpu(__x)
 #define cpu_to_lelong(__x)	cpu_to_le64(__x)
+#define __lelong                __le64
 #endif
 
 #define nacl_shmem()							\
@@ -70,7 +72,7 @@ int kvm_riscv_nacl_init(void);
 
 #define nacl_scratch_read_long(__shmem, __offset)			\
 ({									\
-	unsigned long *__p = (__shmem) +				\
+	__lelong *__p = (__shmem) +					\
 			     SBI_NACL_SHMEM_SCRATCH_OFFSET +		\
 			     (__offset);				\
 	lelong_to_cpu(*__p);						\
@@ -78,7 +80,7 @@ int kvm_riscv_nacl_init(void);
 
 #define nacl_scratch_write_long(__shmem, __offset, __val)		\
 do {									\
-	unsigned long *__p = (__shmem) +				\
+	__lelong *__p = (__shmem) +					\
 			     SBI_NACL_SHMEM_SCRATCH_OFFSET +		\
 			     (__offset);				\
 	*__p = cpu_to_lelong(__val);					\
@@ -87,7 +89,7 @@ do {									\
 #define nacl_scratch_write_longs(__shmem, __offset, __array, __count)	\
 do {									\
 	unsigned int __i;						\
-	unsigned long *__p = (__shmem) +				\
+	__lelong *__p = (__shmem) +					\
 			     SBI_NACL_SHMEM_SCRATCH_OFFSET +		\
 			     (__offset);				\
 	for (__i = 0; __i < (__count); __i++)				\
@@ -168,7 +170,7 @@ __kvm_riscv_nacl_hfence(__shmem,					\
 
 #define nacl_csr_read(__shmem, __csr)					\
 ({									\
-	unsigned long *__a = (__shmem) + SBI_NACL_SHMEM_CSR_OFFSET;	\
+	__lelong *__a = (__shmem) + SBI_NACL_SHMEM_CSR_OFFSET;		\
 	lelong_to_cpu(__a[SBI_NACL_SHMEM_CSR_INDEX(__csr)]);		\
 })
 
@@ -176,7 +178,7 @@ __kvm_riscv_nacl_hfence(__shmem,					\
 do {									\
 	void *__s = (__shmem);						\
 	unsigned int __i = SBI_NACL_SHMEM_CSR_INDEX(__csr);		\
-	unsigned long *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET;		\
+	__lelong *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET;		\
 	u8 *__b = (__s) + SBI_NACL_SHMEM_DBITMAP_OFFSET;		\
 	__a[__i] = cpu_to_lelong(__val);				\
 	__b[__i >> 3] |= 1U << (__i & 0x7);				\
@@ -186,7 +188,7 @@ do {									\
 ({									\
 	void *__s = (__shmem);						\
 	unsigned int __i = SBI_NACL_SHMEM_CSR_INDEX(__csr);		\
-	unsigned long *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET;		\
+	__lelong *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET;		\
 	u8 *__b = (__s) + SBI_NACL_SHMEM_DBITMAP_OFFSET;		\
 	unsigned long __r = lelong_to_cpu(__a[__i]);			\
 	__a[__i] = cpu_to_lelong(__val);				\
diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h
index 11c9886c3b70..5d4ec15584cf 100644
--- a/arch/riscv/include/asm/uaccess.h
+++ b/arch/riscv/include/asm/uaccess.h
@@ -112,7 +112,7 @@ do {								\
 		_ASM_EXTABLE_UACCESS_ERR(1b, %l2, %0)		\
 		: "=&r" (__tmp)					\
 		: "m" (*(ptr)) : : label);			\
-	(x) = (__typeof__(x))(unsigned long)__tmp;		\
+	(x) = (__force __typeof__(x))(unsigned long)__tmp;	\
 } while (0)
 #else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
 #define __get_user_asm(insn, x, ptr, label)			\
diff --git a/arch/riscv/kvm/nacl.c b/arch/riscv/kvm/nacl.c
index 08a95ad9ada2..6f9f8963e9dd 100644
--- a/arch/riscv/kvm/nacl.c
+++ b/arch/riscv/kvm/nacl.c
@@ -20,7 +20,7 @@ void __kvm_riscv_nacl_hfence(void *shmem,
 			     unsigned long page_count)
 {
 	int i, ent = -1, try_count = 5;
-	unsigned long *entp;
+	__lelong *entp;
 
 again:
 	for (i = 0; i < SBI_NACL_SHMEM_HFENCE_ENTRY_MAX; i++) {
-- 
2.43.0



From andrey.smirnov at siderolabs.com  Mon Jun  8 08:57:58 2026
From: andrey.smirnov at siderolabs.com (Andrey Smirnov)
Date: Mon,  8 Jun 2026 19:57:58 +0400
Subject: [PATCH] mm/page_table_check: do not track special (PFN-mapped) PTEs
Message-ID: <20260608155758.1220420-1-andrey.smirnov@siderolabs.com>

The vDSO data store ("[vvar]") special mapping is created as a VM_PFNMAP
mapping and its pages are installed into userspace with vmf_insert_pfn(),
which produces special PTEs (pte_special()). On x86 and arm64 (and riscv)
pte_user_accessible_page() only tests the PRESENT/USER bits and does not
exclude special PTEs, so page_table_check accounts these PFN mappings in
the per-page anon/file map counters even though they are not rmap-managed
pages (vm_normal_page() returns NULL for them).

Most of these data pages live in the kernel image and are never freed, so
the stray accounting is invisible. The time-namespace VVAR page is the
exception: it is a real alloc_page() page that is released with
__free_page() in free_time_ns() when the last task of a time namespace
exits. Across the map / unmap / vdso_join_timens() zap transitions the
special-PTE accounting is not balanced for this page, so a non-zero
file_map_count survives to the free path and trips:

  kernel BUG at mm/page_table_check.c:143!
  __page_table_check_zero+0xfb/0x130
  __free_frozen_pages+0x52f/0x650
  free_time_ns+0x85/0xc0
  free_nsproxy+0x7f/0x130
  do_exit+0x313/0xa60
  do_group_exit+0x77/0x90

This is reliably reproducible on x86_64 and arm64 under heavy container/CI
churn that rapidly creates and destroys time namespaces (CLONE_NEWTIME via
runc / docker-init / tini), and was independently reported by syzbot on
riscv. It only manifests when CONFIG_PAGE_TABLE_CHECK is active.

Special PTEs have no struct-page rmap semantics and must never have been
tracked by page table check. Skip them in both the set and clear paths so
the counters stay balanced (always zero) for PFN-mapped pages, regardless
of how the architecture defines pte_user_accessible_page(). pte_special()
is available generically (it is a no-op returning false on architectures
without ARCH_HAS_PTE_SPECIAL), so this is a single, arch-independent fix.

Note that the v7.0 generic vDSO datastore rework in commit 05988dba1179
("vdso/datastore: Allocate data pages dynamically") incidentally avoids
the problem by switching the mapping to VM_MIXEDMAP + vmf_insert_page()
with balanced struct-page accounting. This patch fixes the still-affected
VM_PFNMAP path used by 6.18.y and earlier, and additionally makes
page_table_check robust against any future PFN-mapped user pages.

Fixes: df4e817b7108 ("mm: page table check")
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
Cc: Andrei Vagin <avagin at gmail.com>
Cc: Andy Lutomirski <luto at kernel.org>
Cc: Vincenzo Frascino <vincenzo.frascino at arm.com>
Reported-by: syzbot+2b5fe617654be3d8848b at syzkaller.appspotmail.com
Closes: https://github.com/siderolabs/talos/issues/13496
Cc: stable at vger.kernel.org
Signed-off-by: Andrey Smirnov <andrey.smirnov at siderolabs.com>
---
 mm/page_table_check.c | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/mm/page_table_check.c b/mm/page_table_check.c
index 4eeca782b888..ee492d5389b9 100644
--- a/mm/page_table_check.c
+++ b/mm/page_table_check.c
@@ -150,9 +150,16 @@ void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
 	if (&init_mm == mm)
 		return;
 
-	if (pte_user_accessible_page(pte)) {
+	/*
+	 * PFN-mapped (special) PTEs - e.g. the vDSO/time-namespace "[vvar]"
+	 * mapping installed via vmf_insert_pfn() - are not rmap-managed and
+	 * must not be tracked here. Tracking them can leave a non-zero map
+	 * count on a struct page that is later freed (the time namespace VVAR
+	 * page in free_time_ns()), tripping the BUG_ON() in
+	 * __page_table_check_zero().
+	 */
+	if (pte_user_accessible_page(pte) && !pte_special(pte))
 		page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
-	}
 }
 EXPORT_SYMBOL(__page_table_check_pte_clear);
 
@@ -205,7 +212,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
 
 	for (i = 0; i < nr; i++)
 		__page_table_check_pte_clear(mm, ptep_get(ptep + i));
-	if (pte_user_accessible_page(pte))
+	if (pte_user_accessible_page(pte) && !pte_special(pte))
 		page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
 }
 EXPORT_SYMBOL(__page_table_check_ptes_set);
-- 
2.53.0



From akpm at linux-foundation.org  Mon Jun  8 09:10:00 2026
From: akpm at linux-foundation.org (Andrew Morton)
Date: Mon, 8 Jun 2026 09:10:00 -0700
Subject: [PATCH v16 00/10] arm64/riscv: Add support for crashkernel CMA
 reservation
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <20260608091000.d88d7f5cc1bc4fa17f5774fe@linux-foundation.org>

On Mon, 8 Jun 2026 15:34:49 +0800 Jinjie Ruan <ruanjinjie at huawei.com> wrote:

> The crash memory allocation, and the exclude of crashk_res, crashk_low_res
> and crashk_cma memory are almost identical across different architectures,
> This patch set handle them in crash core in a general way, which eliminate
> a lot of duplication code.
> 
> And add support for crashkernel CMA reservation for arm64 and riscv.

fyi, AI review might have found a bunch of issues in arch-specific
code, all of them pre-existing.

	https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie at huawei.com


From sunilvl at oss.qualcomm.com  Mon Jun  8 09:24:28 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Mon, 8 Jun 2026 21:54:28 +0530
Subject: [PATCH v2 1/6] ACPI: RISC-V: Fix riscv_acpi_irq_get_dep() loop termination
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-1-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-1-23ffa16b6ebb@kernel.org>
Message-ID: <CAB19ukFFwm3ehzkBFr+oXRjA7VK_4_=XHFSuqdEpbVqUz8Do4Q@mail.gmail.com>

Hi Lorenzo,

On Wed, Jun 3, 2026 at 1:51?PM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
>
> In riscv_acpi_add_irq_dep() the main loop condition would currently stop
> the loop if an interrupt descriptor contains an interrupt for which the
> respective GSI handle is NULL, which is not correct because subsequent
> interrupts in the interrupt descriptor might still have a GSI dependency
> that must not be skipped.
>
> Rework riscv_acpi_add_irq_dep() and the riscv_acpi_irq_get_dep() call chain
> to fix it - by not forcing the loop to stop in order to guarantee
> dependency detection for all the interrupt entries in the CRS descriptor.
>
> Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> Cc: "Rafael J. Wysocki" <rafael at kernel.org>
> Cc: Sunil V L <sunilvl at ventanamicro.com>
> ---
>  drivers/acpi/riscv/irq.c | 10 ++++++----
>  1 file changed, 6 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
> index 9b88d0993e88..cd83c3035cf6 100644
> --- a/drivers/acpi/riscv/irq.c
> +++ b/drivers/acpi/riscv/irq.c
> @@ -299,6 +299,7 @@ static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *c
>                         return AE_OK;
>
>                 ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
> +               ctx->rc = 0;
>                 return AE_CTRL_TERMINATE;
>         }
>
> @@ -314,10 +315,8 @@ static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_h
>
>         acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
>         *gsi_handle = ctx.handle;
> -       if (*gsi_handle)
> -               return 1;
>
> -       return 0;
> +       return ctx.rc;
>  }
>
>  static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
> @@ -381,8 +380,11 @@ static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
>         int i;
>
>         for (i = 0;
> -            riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
> +            !riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
>              i++) {
> +               if (!gsi_handle)
> +                       continue;
> +
>                 dep_devices.count = 1;
>                 dep_devices.handles = kzalloc_objs(*dep_devices.handles, 1);
>                 if (!dep_devices.handles) {
>
Do these fixes need the Fixes tag?

Otherwise, LGTM.
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>

Thanks!
Sunil


From sunilvl at oss.qualcomm.com  Mon Jun  8 09:30:32 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Mon, 8 Jun 2026 22:00:32 +0530
Subject: [PATCH v2 3/6] ACPI: RISC-V: Fix riscv_acpi_add_prt_dep() loop handling
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-3-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-3-23ffa16b6ebb@kernel.org>
Message-ID: <CAB19ukFw34et9YULib7i-xXPirrW-TVK96PH3KKR0Nb0iiwjNw@mail.gmail.com>

On Wed, Jun 3, 2026 at 2:18?PM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
>
> The loop in riscv_acpi_add_prt_dep() includes error conditions that are
> handled in a dubious - if not outright wrong - way, by continuining the
> loop (which skips and misses the entry pointer update to point to the next
> entry).
>
> Rewrite the loop as a for loop (that handles the continuation correctly)
> and wrap the condition and update statements using helper functions to make
> it cleaner.
>
> Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> Cc: "Rafael J. Wysocki" <rafael at kernel.org>
> Cc: Sunil V L <sunilvl at ventanamicro.com>
> ---
>  drivers/acpi/riscv/irq.c | 19 +++++++++++++++----
>  1 file changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
> index 75170151c614..0cdec5dd575e 100644
> --- a/drivers/acpi/riscv/irq.c
> +++ b/drivers/acpi/riscv/irq.c
> @@ -319,6 +319,20 @@ static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_h
>         return ctx.rc;
>  }
>
> +static bool acpi_prt_entry_valid(void *prt_entry)
> +{
> +       struct acpi_pci_routing_table *entry = prt_entry;
> +
> +       return entry && entry->length > 0;
> +}
> +
> +static void *acpi_prt_next_entry(void *prt_entry)
> +{
> +       struct acpi_pci_routing_table *entry = prt_entry;
> +
> +       return prt_entry + entry->length;
> +}
> +
>  static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
>  {
>         struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
> @@ -337,7 +351,7 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
>         }
>
>         entry = buffer.pointer;
> -       while (entry && (entry->length > 0)) {
> +       for (; acpi_prt_entry_valid(entry); entry = acpi_prt_next_entry(entry)) {
>                 if (entry->source[0]) {
>                         status = acpi_get_handle(handle, entry->source, &link_handle);
>                         if (ACPI_FAILURE(status))
> @@ -365,9 +379,6 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
>                         dep_devices.handles[0] = gsi_handle;
>                         count += acpi_scan_add_dep(handle, &dep_devices);
>                 }
> -
> -               entry = (struct acpi_pci_routing_table *)
> -                       ((unsigned long)entry + entry->length);
>         }
>
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From sunilvl at oss.qualcomm.com  Mon Jun  8 09:31:16 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Mon, 8 Jun 2026 22:01:16 +0530
Subject: [PATCH v2 2/6] ACPI: RISC-V: Check acpi_get_handle() status in riscv_acpi_add_prt_dep()
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-2-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-2-23ffa16b6ebb@kernel.org>
Message-ID: <CAB19ukFVPnWhgvb9icFU44L5qre8ViNTEHg_uvK5232PnCEE5g@mail.gmail.com>

On Wed, Jun 3, 2026 at 1:52?PM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
>
> In riscv_acpi_add_prt_dep(), the acpi_get_handle() call can fail which
> would leave link_handle uninitialized.
>
> Fix it by checking the acpi_get_handle() return status and skip the entry
> if it fails.
>
> Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> Cc: "Rafael J. Wysocki" <rafael at kernel.org>
> Cc: Sunil V L <sunilvl at ventanamicro.com>
> ---
>  drivers/acpi/riscv/irq.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
> index cd83c3035cf6..75170151c614 100644
> --- a/drivers/acpi/riscv/irq.c
> +++ b/drivers/acpi/riscv/irq.c
> @@ -339,7 +339,9 @@ static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
>         entry = buffer.pointer;
>         while (entry && (entry->length > 0)) {
>                 if (entry->source[0]) {
> -                       acpi_get_handle(handle, entry->source, &link_handle);
> +                       status = acpi_get_handle(handle, entry->source, &link_handle);
> +                       if (ACPI_FAILURE(status))
> +                               continue;
>                         dep_devices.count = 1;
>
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From sunilvl at oss.qualcomm.com  Mon Jun  8 09:38:15 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Mon, 8 Jun 2026 22:08:15 +0530
Subject: [PATCH v2 4/6] ACPI: irq: Move RISC-V interrupt controllers
 autodep to ACPI IRQ code
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-4-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-4-23ffa16b6ebb@kernel.org>
Message-ID: <CAB19ukH5hx_kfpfcRiuPFrUmvFxMk3B08RNjcaxx3C6fDBS0dw@mail.gmail.com>

On Wed, Jun 3, 2026 at 1:54?PM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
>
> RISC-V implements arch code to detect probe dependencies for devices and
> the interrupt controller the devices GSIs are routed to.
>
> The code itself is arch agnostic apart from an arch specific helper
> function required to retrieve the acpi_handle of the interrupt controller
> that manages the device GSI interrupt.
>
> In order to enable IRQ probe dependencies detection on other architectures,
> move RISC-V IRQ probe dependency detection code to generic ACPI IRQ code.
>
> Allow interrupt controller drivers to register an arch specific function to
> determine the acpi_handle for a specific GSI number to use the mechanism if
> needed by the respective interrupt controller drivers.
>
> Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> Cc: Huacai Chen <chenhuacai at kernel.org>
> Cc: Thomas Gleixner <tglx at kernel.org>
> Cc: Anup Patel <anup at brainfault.org>
> Cc: "Rafael J. Wysocki" <rafael at kernel.org>
> Cc: Sunil V L <sunilvl at ventanamicro.com>
> Cc: Marc Zyngier <maz at kernel.org>
> ---
>  arch/riscv/include/asm/acpi.h       |   1 +
>  drivers/acpi/irq.c                  | 172 +++++++++++++++++++++++++++++++++++-
>  drivers/acpi/riscv/irq.c            | 156 +-------------------------------
>  drivers/irqchip/irq-gic-v3.c        |   2 +-
>  drivers/irqchip/irq-gic-v5.c        |   2 +-
>  drivers/irqchip/irq-gic.c           |   2 +-
>  drivers/irqchip/irq-loongarch-cpu.c |   2 +-
>  drivers/irqchip/irq-riscv-intc.c    |   3 +-
>  include/linux/acpi.h                |   5 +-
>  9 files changed, 181 insertions(+), 164 deletions(-)
>
LGTM.

Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From linux at roeck-us.net  Mon Jun  8 10:03:48 2026
From: linux at roeck-us.net (Guenter Roeck)
Date: Mon, 8 Jun 2026 10:03:48 -0700
Subject: [PATCH v2] hwmon: add a driver for the temp/voltage sensor on
 PolarFire SoC
In-Reply-To: <20260603-ongoing-brunette-51e35be6d93e@spud>
References: <20260603-ongoing-brunette-51e35be6d93e@spud>
Message-ID: <fd92d7c9-9594-47b9-bd84-a6bd5ebae66d@roeck-us.net>

On 6/3/26 06:19, Conor Dooley wrote:
> From: Lars Randers <lranders at mail.dk>
> 
> Add a driver for the temperature and voltage sensors on PolarFire SoC.
> The temperature reports how hot the die is, and the voltages are the
> SoC's 1.05, 1.8 and 2.5 volt rails respectively.
> 
> The hardware supports alarms in theory, but there is an erratum that
> prevents clearing them once triggered, so no support is added for them.
> 
> The hardware measures voltage with 16 bits, of which 1 is a sign bit and
> the remainder holds the voltage as a fixed point integer value. It's
> improbable that the hardware will work if the voltages are negative, so
> the driver ignores the sign bits.
> 
> There's no dt support etc here because this is the child of a simple-mfd
> syscon.
> 
> Signed-off-by: Lars Randers <lranders at mail.dk>
> Co-developed-by: Conor Dooley <conor.dooley at microchip.com>
> Signed-off-by: Conor Dooley <conor.dooley at microchip.com>

Comments inline.

Thanks,
Guenter


> ---
> 
> v2:
> - Fix some minor things pointed out by Sashiko including inaccurate
>    comments, bounds checking of values read from sysfs and Kconfig
>    dependencies.
> - Make update_interval use milliseconds instead of microseconds
>    (I'll add update_interval_us support when that lands, there's a
>    proposed workaround for the erratum circulating internally, so it'll
>    probably come alongside alarm support).
> 
> CC: Guenter Roeck <linux at roeck-us.net>
> CC: Jonathan Corbet <corbet at lwn.net>
> CC: Shuah Khan <skhan at linuxfoundation.org>
> CC: Conor Dooley <conor.dooley at microchip.com>
> CC: Daire McNamara <daire.mcnamara at microchip.com>
> CC: linux-hwmon at vger.kernel.org
> CC: linux-doc at vger.kernel.org
> CC: linux-kernel at vger.kernel.org
> CC: linux-riscv at lists.infradead.org
> CC: Valentina.FernandezAlanis at microchip.com
> ---
>   Documentation/hwmon/index.rst    |   1 +
>   Documentation/hwmon/tvs-mpfs.rst |  53 +++++
>   MAINTAINERS                      |   1 +
>   drivers/hwmon/Kconfig            |  13 +
>   drivers/hwmon/Makefile           |   1 +
>   drivers/hwmon/tvs-mpfs.c         | 394 +++++++++++++++++++++++++++++++
>   6 files changed, 463 insertions(+)
>   create mode 100644 Documentation/hwmon/tvs-mpfs.rst
>   create mode 100644 drivers/hwmon/tvs-mpfs.c
> 
> diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
> index 8b655e5d6b68..84a5339e1d6f 100644
> --- a/Documentation/hwmon/index.rst
> +++ b/Documentation/hwmon/index.rst
> @@ -262,6 +262,7 @@ Hardware Monitoring Kernel Drivers
>      tps53679
>      tps546d24
>      tsc1641
> +   tvs-mpfs
>      twl4030-madc-hwmon
>      ucd9000
>      ucd9200
> diff --git a/Documentation/hwmon/tvs-mpfs.rst b/Documentation/hwmon/tvs-mpfs.rst
> new file mode 100644
> index 000000000000..ff445844d07c
> --- /dev/null
> +++ b/Documentation/hwmon/tvs-mpfs.rst
> @@ -0,0 +1,53 @@
> +.. SPDX-License-Identifier: GPL-2.0
> +
> +Kernel driver tvs-mpfs
> +======================
> +
> +Supported chips:
> +
> +  * PolarFire SoC
> +
> +Authors:
> +
> +   - Conor Dooley <conor.dooley at microchip.com>
> +   - Lars Randers <lranders at mail.dk>
> +
> +Description
> +-----------
> +
> +This driver implements support for the temperature and voltage sensors on
> +PolarFire SoC. The temperature reports how hot the die is, and the voltages are
> +the SoC's 1.05, 1.8 and 2.5 volt rails respectively.
> +
> +
> +Usage Notes
> +-----------
> +
> +update_interval has a permitted range of 0 to 8.
> +
> +

It might make sense to document what "0" means.

Temperatures are read in millidegrees Celsius, but the hardware measures in
> +degrees Kelvin, storing the result as 11.4 fixed point data, for a maximum
> +value of 2047.9375 degrees Kelvin.
> +
> +Voltages are read in millivolts. The hardware measures in millivolts, storing
> +the value as 12.3 fixed point data, for a maximum of 4095.875 millivolts.
> +The minimum value reportable by the driver is 0 volts, although the hardware
> +is capable of measuring negative values.
> +
> +Sysfs entries
> +-------------
> +
> +The following attributes are supported. update_interval is read-write, as are
> +the enables. All other attributes are read only.
> +
> +======================= ====================================================
> +temp1_label		Fixed name for channel.
> +temp1_input		Measured temperature for channel.
> +temp1_enable		Enable/disable for channel.
> +
> +in[0-2]_label		Fixed name for channel.
> +in[0-2]_input		Measured voltage for channel.
> +in[0-2]_enable		Enable/disable for channel.
> +
> +update_interval		The interval at which the chip will update readings.
> +======================= ====================================================
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 2fb1c75afd16..a492cf5ad0fc 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -22938,6 +22938,7 @@ F:	drivers/char/hw_random/mpfs-rng.c
>   F:	drivers/clk/microchip/clk-mpfs*.c
>   F:	drivers/firmware/microchip/mpfs-auto-update.c
>   F:	drivers/gpio/gpio-mpfs.c
> +F:	drivers/hwmon/tvs-mpfs.c
>   F:	drivers/i2c/busses/i2c-microchip-corei2c.c
>   F:	drivers/mailbox/mailbox-mpfs.c
>   F:	drivers/pci/controller/plda/pcie-microchip-host.c
> diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
> index 14e4cea48acc..2b9622b1db95 100644
> --- a/drivers/hwmon/Kconfig
> +++ b/drivers/hwmon/Kconfig
> @@ -930,6 +930,19 @@ config SENSORS_JC42
>   	  This driver can also be built as a module. If so, the module
>   	  will be called jc42.
>   
> +config SENSORS_POLARFIRE_SOC_TVS
> +	tristate "PolarFire SoC (MPFS) temperature and voltage sensor"
> +	depends on POLARFIRE_SOC_SYSCONS || COMPILE_TEST
> +	depends on MFD_SYSCON
> +	help
> +	  This driver adds support for the PolarFire SoC (MPFS) Temperature and
> +	  Voltage Sensor.
> +
> +	  To compile this driver as a module, choose M here. the
> +	  module will be called tvs-mpfs.
> +
> +	  If unsure, say N.
> +
>   config SENSORS_POWERZ
>   	tristate "ChargerLAB POWER-Z USB-C tester"
>   	depends on USB
> diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
> index 4788996aa137..b58d249e4cf4 100644
> --- a/drivers/hwmon/Makefile
> +++ b/drivers/hwmon/Makefile
> @@ -194,6 +194,7 @@ obj-$(CONFIG_SENSORS_NZXT_SMART2) += nzxt-smart2.o
>   obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
>   obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
>   obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
> +obj-$(CONFIG_SENSORS_POLARFIRE_SOC_TVS)  += tvs-mpfs.o
>   obj-$(CONFIG_SENSORS_POWERZ)	+= powerz.o
>   obj-$(CONFIG_SENSORS_POWR1220)  += powr1220.o
>   obj-$(CONFIG_SENSORS_PT5161L)	+= pt5161l.o
> diff --git a/drivers/hwmon/tvs-mpfs.c b/drivers/hwmon/tvs-mpfs.c
> new file mode 100644
> index 000000000000..f086f178b4ba
> --- /dev/null
> +++ b/drivers/hwmon/tvs-mpfs.c
> @@ -0,0 +1,394 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * Author: Lars Randers <lranders at mail.dk>
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/err.h>
> +#include <linux/freezer.h>
> +#include <linux/hwmon.h>
> +#include <linux/io.h>
> +#include <linux/kthread.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/of_address.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#define MPFS_TVS_CTRL 0x08
> +#define MPFS_TVS_OUTPUT0 0x24
> +#define MPFS_TVS_OUTPUT1 0x28
> +
> +#define MPFS_TVS_CTRL_TEMP_VALID	BIT(19)
> +#define MPFS_TVS_CTRL_V2P5_VALID	BIT(18)
> +#define MPFS_TVS_CTRL_V1P8_VALID	BIT(17)
> +#define MPFS_TVS_CTRL_V1P05_VALID	BIT(16)
> +
> +#define MPFS_TVS_CTRL_TEMP_ENABLE	BIT(3)
> +#define MPFS_TVS_CTRL_V2P5_ENABLE	BIT(2)
> +#define MPFS_TVS_CTRL_V1P8_ENABLE	BIT(1)
> +#define MPFS_TVS_CTRL_V1P05_ENABLE	BIT(0)
> +#define MPFS_TVS_CTRL_ENABLE_ALL	GENMASK(3, 0)
> +
> +/*
> + * For all of these the value in millivolts is stored in 16 bits, with an upper
> + * sign bit and a lower 3 bits of decimal. These masks discard the sign bit and
> + * decimal places, because if Linux is running these voltages cannot be negative
> + * and so avoid having to convert to two's complement.
> + */
> +#define MPFS_OUTPUT0_V1P8_MASK	GENMASK(30, 19)
> +#define MPFS_OUTPUT0_V1P05_MASK	GENMASK(14, 3)
> +#define MPFS_OUTPUT1_V2P5_MASK	GENMASK(14, 3)
> +
> +/*
> + * The register map claims that the temperature is stored in bits 31:16, but
> + * application note "AN4682: PolarFire FPGA Temperature and Voltage Sensor"
> + * says that 31 is reserved. Temperature is in kelvin, so what's probably a
> + * sign bit has no value anyway.
> + */
> +#define MPFS_OUTPUT1_TEMP_MASK GENMASK(30, 16)
> +
> +#define MPFS_TVS_INTERVAL_MASK GENMASK(15, 8)
> +#define MPFS_TVS_INTERVAL_OFFSET 8
> +/* The interval register is in increments of 32 us */
> +#define MPFS_TVS_INTERVAL_SCALE 32
> +
> +/* 273.1875 in 11.4 fixed-point notation */
> +#define MPFS_TVS_K_TO_C 0x1113
> +
> +enum mpfs_tvs_sensors {
> +	SENSOR_V1P05 = 0,
> +	SENSOR_V1P8,
> +	SENSOR_V2P5,
> +};
> +
> +static const char * const mpfs_tvs_voltage_labels[] = { "1P05", "1P8", "2P5" };
> +
> +struct mpfs_tvs {
> +	struct regmap *regmap;
> +};
> +
> +static int mpfs_tvs_voltage_read(struct mpfs_tvs *data, u32 attr,
> +				 int channel, long *val)
> +{
> +	u32 tmp, control;
> +
> +	if (attr != hwmon_in_input && attr != hwmon_in_enable)
> +		return -EOPNOTSUPP;
> +
> +	regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
> +
> +	switch (channel) {
> +	case SENSOR_V2P5:
> +		if (attr == hwmon_in_enable) {
> +			*val = FIELD_GET(MPFS_TVS_CTRL_V2P5_ENABLE, control);
> +			break;
> +		}
> +
> +		if (!(control & MPFS_TVS_CTRL_V2P5_VALID))
> +			return -EINVAL;
> +
> +		regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
> +		*val = FIELD_GET(MPFS_OUTPUT1_V2P5_MASK, tmp);
> +		break;
> +	case SENSOR_V1P8:
> +		if (attr == hwmon_in_enable) {
> +			*val = FIELD_GET(MPFS_TVS_CTRL_V1P8_ENABLE, control);
> +			break;
> +		}
> +
> +		if (!(control & MPFS_TVS_CTRL_V1P8_VALID))
> +			return -EINVAL;
> +
> +		regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp);
> +		*val = FIELD_GET(MPFS_OUTPUT0_V1P8_MASK, tmp);
> +		break;
> +	case SENSOR_V1P05:
> +		if (attr == hwmon_in_enable) {
> +			*val = FIELD_GET(MPFS_TVS_CTRL_V1P05_ENABLE, control);
> +			break;
> +		}
> +
> +		if (!(control & MPFS_TVS_CTRL_V1P05_VALID))
> +			return -EINVAL;
> +
> +		regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp);
> +		*val = FIELD_GET(MPFS_OUTPUT0_V1P05_MASK, tmp);
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return 0;
> +}
> +
> +static int mpfs_tvs_voltage_write(struct mpfs_tvs *data, u32 attr,
> +				  int channel, long val)
> +{
> +	u32 tmp;
> +
> +	if (attr != hwmon_in_enable)
> +		return -EOPNOTSUPP;
> +
> +	switch (channel) {
> +	case SENSOR_V2P5:
> +		if (val > 1 || val < 0)
> +			return -EINVAL;
> +

Range check should happen only once. The -EOPNOTSUPP
is theoretic (channel is always valid), so duplicating
the range check to handle that theoretic case does not add value.

> +		tmp = FIELD_PREP(MPFS_TVS_CTRL_V2P5_ENABLE, val);
> +		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
> +				   MPFS_TVS_CTRL_V2P5_ENABLE, tmp);
> +		break;
> +	case SENSOR_V1P8:
> +		if (val > 1 || val < 0)
> +			return -EINVAL;
> +
> +		tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P8_ENABLE, val);
> +		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
> +				   MPFS_TVS_CTRL_V1P8_ENABLE, tmp);
> +		break;
> +	case SENSOR_V1P05:
> +		if (val > 1 || val < 0)
> +			return -EINVAL;
> +
> +		tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P05_ENABLE, val);
> +		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
> +				   MPFS_TVS_CTRL_V1P05_ENABLE, tmp);
> +		break;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +
> +	return 0;
> +}
> +
> +static int mpfs_tvs_temp_read(struct mpfs_tvs *data, u32 attr, long *val)
> +{
> +	u32 tmp, control;
> +
> +	if (attr != hwmon_temp_input && attr != hwmon_temp_enable)
> +		return -EOPNOTSUPP;
> +
> +	regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
> +
> +	if (attr == hwmon_temp_enable) {
> +		*val = FIELD_GET(MPFS_TVS_CTRL_TEMP_ENABLE, control);
> +		return 0;
> +	}
> +
> +	if (!(control & MPFS_TVS_CTRL_TEMP_VALID))
> +		return -EINVAL;
> +
"Invalid argument" can not be correct for data read from the chip.
I don't know what this means. It should be either -ENODATA (no data available)
if this is transient or -EIO (I/O error) if it is a permanent problem.
The same applies to other validation checks.

> +	regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
> +	*val = FIELD_GET(MPFS_OUTPUT1_TEMP_MASK, tmp);
> +	*val -= MPFS_TVS_K_TO_C;
> +	*val = (1000 * *val) >> 4; /* fixed point (11.4) to millidegrees */
> +
> +	return 0;
> +}
> +
> +static int mpfs_tvs_temp_write(struct mpfs_tvs *data, u32 attr, long val)
> +{
> +	u32 tmp;
> +
> +	if (attr != hwmon_temp_enable)
> +		return -EOPNOTSUPP;
> +
> +	if (val > 1 || val < 0)
> +		return -EINVAL;
> +
> +	tmp = FIELD_PREP(MPFS_TVS_CTRL_TEMP_ENABLE, val);
> +	regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
> +			   MPFS_TVS_CTRL_TEMP_ENABLE, tmp);
> +
> +	return 0;
> +}
> +
> +static int mpfs_tvs_interval_read(struct mpfs_tvs *data, u32 attr, long *val)
> +{
> +	u32 tmp;
> +
> +	if (attr != hwmon_chip_update_interval)
> +		return -EOPNOTSUPP;
> +
> +	regmap_read(data->regmap, MPFS_TVS_CTRL, &tmp);
> +	*val = FIELD_GET(MPFS_TVS_INTERVAL_MASK, tmp);
> +	*val *= MPFS_TVS_INTERVAL_SCALE;
> +	*val /= 1000;
> +
> +	return 0;
> +}
> +
> +static int mpfs_tvs_interval_write(struct mpfs_tvs *data, u32 attr, long val)
> +{
> +	unsigned long temp = val;
> +
> +	if (attr != hwmon_chip_update_interval)
> +		return -EOPNOTSUPP;
> +
> +	temp *= 1000;

This is likely to result in overflow issues (for example if val == LONG_MAX).

> +	temp /= MPFS_TVS_INTERVAL_SCALE;
> +
> +	/*
> +	 * The value is 8 bits wide, but 255 is described as
> +	 * "255= Do single set of transfers when scoverride set"
> +	 * but there's no scoverride bit in the tvs register region.
> +	 * Ban using 255 since its behaviour is suspect.
> +	 */
> +	if (temp > 254)
> +		return -EINVAL;

Hardware monitoring drivers should use clamp() and not return -EINVAL
for ranges such as this. Since the valid range (in ms) is 0..8, I would
suggest to clamp val to (0, 8) before any calculations to also avoid
the overflow issue mentioned above. That makes me wonder: What does "0"
stand for ? 32 us or 0 us ? It does not make a difference here, but it
may be relevant when microsecond intervals are implemented.

> +
> +	temp <<= MPFS_TVS_INTERVAL_OFFSET;
> +	regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
> +			   MPFS_TVS_INTERVAL_MASK, temp);

If regmap never returns errors this needs to be documented in the driver.

> +
> +	return 0;
> +}
> +
> +static umode_t mpfs_tvs_is_visible(const void *data,
> +				   enum hwmon_sensor_types type,
> +				   u32 attr, int channel)
> +{
> +	if (type == hwmon_chip && attr == hwmon_chip_update_interval)
> +		return 0644;
> +
> +	if (type == hwmon_temp) {
> +		switch (attr) {
> +		case hwmon_temp_enable:
> +			return 0644;
> +		case hwmon_temp_input:
> +		case hwmon_temp_label:
> +			return 0444;
> +		default:
> +			return 0;
> +		}
> +	}
> +
> +	if (type == hwmon_in) {
> +		switch (attr) {
> +		case hwmon_in_enable:
> +			return 0644;
> +		case hwmon_in_input:
> +		case hwmon_in_label:
> +			return 0444;
> +		default:
> +			return 0;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
> +static int mpfs_tvs_read(struct device *dev, enum hwmon_sensor_types type,
> +			 u32 attr, int channel, long *val)
> +{
> +	struct mpfs_tvs *data = dev_get_drvdata(dev);
> +
> +	switch (type) {
> +	case hwmon_temp:
> +		return mpfs_tvs_temp_read(data, attr, val);
> +	case hwmon_in:
> +		return mpfs_tvs_voltage_read(data, attr, channel, val);
> +	case hwmon_chip:
> +		return mpfs_tvs_interval_read(data, attr, val);
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +static int mpfs_tvs_write(struct device *dev, enum hwmon_sensor_types type,
> +			  u32 attr, int channel, long val)
> +{
> +	struct mpfs_tvs *data = dev_get_drvdata(dev);
> +
> +	switch (type) {
> +	case hwmon_temp:
> +		return mpfs_tvs_temp_write(data, attr, val);
> +	case hwmon_in:
> +		return mpfs_tvs_voltage_write(data, attr, channel, val);
> +	case hwmon_chip:
> +		return mpfs_tvs_interval_write(data, attr, val);
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +static int mpfs_tvs_read_labels(struct device *dev,
> +				enum hwmon_sensor_types type,
> +				u32 attr, int channel,
> +				const char **str)
> +{
> +	switch (type) {
> +	case hwmon_temp:
> +		*str = "Die Temp";
> +		return 0;
> +	case hwmon_in:
> +		*str = mpfs_tvs_voltage_labels[channel];
> +		return 0;
> +	default:
> +		return -EOPNOTSUPP;
> +	}
> +}
> +
> +static const struct hwmon_ops mpfs_tvs_ops = {
> +	.is_visible = mpfs_tvs_is_visible,
> +	.read_string = mpfs_tvs_read_labels,
> +	.read = mpfs_tvs_read,
> +	.write = mpfs_tvs_write,
> +};
> +
> +static const struct hwmon_channel_info *mpfs_tvs_info[] = {
> +	HWMON_CHANNEL_INFO(chip,
> +			   HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
> +	HWMON_CHANNEL_INFO(temp,
> +			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_ENABLE),
> +	HWMON_CHANNEL_INFO(in,
> +			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE,
> +			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE,
> +			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE),
> +	NULL
> +};
> +
> +static const struct hwmon_chip_info mpfs_tvs_chip_info = {
> +	.ops = &mpfs_tvs_ops,
> +	.info = mpfs_tvs_info,
> +};
> +
> +static int mpfs_tvs_probe(struct platform_device *pdev)
> +{
> +	struct device *hwmon_dev;
> +	struct mpfs_tvs *data;
> +
> +	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->regmap = device_node_to_regmap(pdev->dev.parent->of_node);
> +	if (IS_ERR(data->regmap))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(data->regmap),
> +				     "Failed to find syscon regmap\n");
> +
> +	regmap_write(data->regmap, MPFS_TVS_CTRL, MPFS_TVS_CTRL_ENABLE_ALL);
> +
> +	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "mpfs_tvs",
> +							 data,
> +							 &mpfs_tvs_chip_info,
> +							 NULL);
> +	if (IS_ERR(hwmon_dev))
> +		return dev_err_probe(&pdev->dev, PTR_ERR(hwmon_dev),
> +				     "hwmon device registration failed.\n");
> +
> +	return 0;
> +}
> +
> +static struct platform_driver mpfs_tvs_driver = {
> +	.probe = mpfs_tvs_probe,
> +	.driver = {
> +		.name = "mpfs-tvs",
> +	},
> +};
> +module_platform_driver(mpfs_tvs_driver);
> +
> +MODULE_AUTHOR("Lars Randers <lranders at mail.dk>");
> +MODULE_DESCRIPTION("PolarFire SoC temperature & voltage sensor driver");
> +MODULE_LICENSE("GPL");



From conor at kernel.org  Mon Jun  8 10:10:08 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 8 Jun 2026 18:10:08 +0100
Subject: [PATCH v2 1/3] dt-bindings: arm: sunxi: Add NetCube Systems
 OpenNMC (dobermann)
In-Reply-To: <20260605191322.1920944-2-lukas.schmid@netcube.li>
References: <20260605191322.1920944-1-lukas.schmid@netcube.li>
 <20260605191322.1920944-2-lukas.schmid@netcube.li>
Message-ID: <20260608-efficient-unmasked-055a2b553525@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260608/d3873d16/attachment.sig>

From rafael at kernel.org  Mon Jun  8 10:18:15 2026
From: rafael at kernel.org (Rafael J. Wysocki)
Date: Mon, 8 Jun 2026 19:18:15 +0200
Subject: [PATCH v2 6/6] irqchip/gic-v5: Enable GICv5 IWB ACPI probe
 ordering detection
In-Reply-To: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-6-23ffa16b6ebb@kernel.org>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-6-23ffa16b6ebb@kernel.org>
Message-ID: <CAJZ5v0ibZKfzJwGyUb92-K1N9C_ab0QujpAKCrvMdyygquS1Vw@mail.gmail.com>

On Wed, Jun 3, 2026 at 10:21?AM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
>
> Register an ACPI hook in the ACPI interrupt management code for GICv5 to
> retrieve the ACPI interrupt controller handle (if any) of the controller
> handling a specific GSI, by updating the acpi_set_irq_model() call with
> the gic_v5_get_gsi_handle() function pointer parameter.
>
> gicv5_get_gsi_handle() allows ACPI core to detect the ACPI handle
> of the controller that manages a specific GSI interrupt.
>
> Update the IWB driver to clear device dependencies in ACPI core once the
> IWB driver has probed.
>
> Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> Cc: Thomas Gleixner <tglx at kernel.org>
> Cc: Marc Zyngier <maz at kernel.org>
> ---
>  drivers/irqchip/irq-gic-v5-iwb.c |  5 +++++
>  drivers/irqchip/irq-gic-v5.c     | 13 +++++++++++--
>  2 files changed, 16 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c
> index 9103feb70ce8..a02cb9537b15 100644
> --- a/drivers/irqchip/irq-gic-v5-iwb.c
> +++ b/drivers/irqchip/irq-gic-v5-iwb.c
> @@ -269,6 +269,11 @@ static int gicv5_iwb_device_probe(struct platform_device *pdev)
>         if (IS_ERR(iwb_node))
>                 return PTR_ERR(iwb_node);
>
> +#ifdef CONFIG_ACPI
> +       if (has_acpi_companion(&pdev->dev))
> +               acpi_dev_clear_dependencies(ACPI_COMPANION(&pdev->dev));
> +#endif

I would rather add a wrapper for this, along with an empty stub for
the !CONFIG_ACPI case.

> +
>         return 0;
>  }
>
> diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
> index 03cc2830b260..26cfaea1af41 100644
> --- a/drivers/irqchip/irq-gic-v5.c
> +++ b/drivers/irqchip/irq-gic-v5.c
> @@ -1217,11 +1217,19 @@ static struct fwnode_handle *gsi_domain_handle;
>  static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
>  {
>         if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
> -               return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> +               return iort_iwb_handle_fwnode(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));

Why is this change needed?

>
>         return gsi_domain_handle;
>  }
>
> +static acpi_handle gic_v5_get_gsi_handle(u32 gsi)
> +{
> +       if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
> +               return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> +
> +       return NULL;
> +}
> +
>  static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
>  {
>         struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
> @@ -1242,7 +1250,8 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
>         if (ret)
>                 goto out_irs;
>
> -       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id, NULL);
> +       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id,
> +                          gic_v5_get_gsi_handle);
>
>         return 0;
>
>
> --


From sunilvl at oss.qualcomm.com  Mon Jun  8 10:31:29 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Mon, 8 Jun 2026 23:01:29 +0530
Subject: [PATCH] acpi/riscv: use a dedicated insertion point in riscv_acpi_register_ext_intc()
In-Reply-To: <20260525074415.1533884-1-maoyixie.tju@gmail.com>
References: <20260525074415.1533884-1-maoyixie.tju@gmail.com>
Message-ID: <CAB19ukFFpsc2eOmkXo9UzSieF-PrMb_BqHw1gdH8_MvwHJTw+g@mail.gmail.com>

On Mon, May 25, 2026 at 1:14?PM Maoyi Xie <maoyixie.tju at gmail.com> wrote:
>
> riscv_acpi_register_ext_intc() inserts into ext_intc_list, which
> is sorted with the largest gsi_base first. It walks the list
> until it finds the first entry with a smaller gsi_base, then
> inserts the new entry before that entry. After the loop it also
> caps the predecessor's nr_irqs if that predecessor was registered
> as PENDING.
>
> The current code uses the loop cursor for both jobs:
>
>     list_for_each_entry(node, &ext_intc_list, list) {
>             if (node->gsi_base < ext_intc_element->gsi_base)
>                     break;
>     }
>
>     prev = list_prev_entry(node, list);
>     if (!list_entry_is_head(prev, &ext_intc_list, list)) {
>             ...
>     }
>
>     list_add_tail(&ext_intc_element->list, &node->list);
>
> If the loop falls through (no entry has a smaller gsi_base),
> node ends up past the end of the list. `&node->list` resolves
> to `&ext_intc_list` via container_of() offset cancellation. So
> list_prev_entry() lands on the last real entry, and
> list_add_tail() inserts at the tail. The code works today.
>
> It is fragile though. Any future change that reads another field
> of node will hit memory before the ext_intc_list global.
>
> Track the insertion point with a dedicated list_head pointer.
> Initialise pos to `&ext_intc_list`. Set it to `&node->list` on
> early break. Use pos->prev for the PENDING adjustment, and pos
> for list_add_tail(). The cursor is no longer touched after the
> loop. Behaviour is unchanged.
>
> Same shape as the Koschel cleanups from 2022 (e.g. 99d8ae4ec8a
> tracing, 2966a9918df clockevents, dc1acd5c946 dlm).
>
> Signed-off-by: Maoyi Xie <maoyixie.tju at gmail.com>
> ---
>  drivers/acpi/riscv/irq.c | 15 ++++++++++-----
>  1 file changed, 10 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
> index 9b88d0993e88..49582cf4f4e2 100644
> --- a/drivers/acpi/riscv/irq.c
> +++ b/drivers/acpi/riscv/irq.c
> @@ -134,7 +134,8 @@ struct fwnode_handle *riscv_acpi_get_gsi_domain_id(u32 gsi)
>  static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr_idcs,
>                                                u32 id, u32 type)
>  {
> -       struct riscv_ext_intc_list *ext_intc_element, *node, *prev;
> +       struct riscv_ext_intc_list *ext_intc_element, *node;
> +       struct list_head *pos = &ext_intc_list;
>
>         ext_intc_element = kzalloc_obj(*ext_intc_element);
>         if (!ext_intc_element)
> @@ -153,18 +154,22 @@ static int __init riscv_acpi_register_ext_intc(u32 gsi_base, u32 nr_irqs, u32 nr
>         ext_intc_element->nr_idcs = nr_idcs;
>         ext_intc_element->id = id;
>         list_for_each_entry(node, &ext_intc_list, list) {
> -               if (node->gsi_base < ext_intc_element->gsi_base)
> +               if (node->gsi_base < ext_intc_element->gsi_base) {
> +                       pos = &node->list;
>                         break;
> +               }
>         }
>
>         /* Adjust the previous node's GSI range if that has pending registration */
> -       prev = list_prev_entry(node, list);
> -       if (!list_entry_is_head(prev, &ext_intc_list, list)) {
> +       if (pos->prev != &ext_intc_list) {
> +               struct riscv_ext_intc_list *prev =
> +                       list_entry(pos->prev, struct riscv_ext_intc_list, list);
> +
>                 if (prev->flag & RISCV_ACPI_INTC_FLAG_PENDING)
>                         prev->nr_irqs = ext_intc_element->gsi_base - prev->gsi_base;
>         }
>
> -       list_add_tail(&ext_intc_element->list, &node->list);
> +       list_add_tail(&ext_intc_element->list, pos);
>         return 0;
>  }
>
LGTM.

Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From conor at kernel.org  Mon Jun  8 10:33:31 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 8 Jun 2026 18:33:31 +0100
Subject: [PATCH 1/2] dt-bindings: dmaengine: Add SpacemiT K1 PDMA request
 numbers
In-Reply-To: <20260607-b4-k1-pdma-req-macros-v1-1-5b2a3955007c@gmail.com>
References: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>
 <20260607-b4-k1-pdma-req-macros-v1-1-5b2a3955007c@gmail.com>
Message-ID: <20260608-dazzling-hacksaw-dbe84766ec76@spud>

On Sun, Jun 07, 2026 at 01:41:30PM -0400, Guodong Xu wrote:
> Add a dt-bindings header that gives symbolic names to the SpacemiT K1
> PDMA request lines of the non-secure peripherals. Device trees can use
> these K1_PDMA_* macros instead of magic numbers.
> 
> Point the spacemit,k1-pdma binding's #dma-cells description at the new
> header.
> 
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> ---
>  .../devicetree/bindings/dma/spacemit,k1-pdma.yaml  |  4 +-
>  include/dt-bindings/dma/spacemit,k1-pdma.h         | 56 ++++++++++++++++++++++
>  2 files changed, 59 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
> index ec06235baf5ca..0d4ac9849e27b 100644
> --- a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
> +++ b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
> @@ -35,7 +35,9 @@ properties:
>    '#dma-cells':
>      const: 1
>      description:
> -      The DMA request number for the peripheral device.
> +      The single cell is the DMA request number for the peripheral device.
> +      See <dt-bindings/dma/spacemit,k1-pdma.h> for the list of valid request
> +      numbers.
>  
>  required:
>    - compatible
> diff --git a/include/dt-bindings/dma/spacemit,k1-pdma.h b/include/dt-bindings/dma/spacemit,k1-pdma.h

Why does this need to be in a binding when there is no use of this in
the driver? May as well be a header, particularly if these are numbers
with a set meaning that are lifted from the TRM, rather than made up
numbers to make a driver work. The former seems likely, given you're
indexing from 3 not 0.

> new file mode 100644
> index 0000000000000..491976516550a
> --- /dev/null
> +++ b/include/dt-bindings/dma/spacemit,k1-pdma.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * This header provides DMA request number for non-secure peripherals of
> + * SpacemiT K1 PDMA.
> + *
> + * Copyright (c) 2026 Guodong Xu <docular.xu at gmail.com>
> + */
> +
> +#ifndef _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
> +#define _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
> +
> +#define K1_PDMA_UART0_TX	3
> +#define K1_PDMA_UART0_RX	4
> +#define K1_PDMA_UART2_TX	5
> +#define K1_PDMA_UART2_RX	6
> +#define K1_PDMA_UART3_TX	7
> +#define K1_PDMA_UART3_RX	8
> +#define K1_PDMA_UART4_TX	9
> +#define K1_PDMA_UART4_RX	10
> +#define K1_PDMA_I2C0_TX		11
> +#define K1_PDMA_I2C0_RX		12
> +#define K1_PDMA_I2C1_TX		13
> +#define K1_PDMA_I2C1_RX		14
> +#define K1_PDMA_I2C2_TX		15
> +#define K1_PDMA_I2C2_RX		16
> +#define K1_PDMA_I2C4_TX		17
> +#define K1_PDMA_I2C4_RX		18
> +#define K1_PDMA_SPI3_TX		19
> +#define K1_PDMA_SPI3_RX		20
> +#define K1_PDMA_I2S0_TX		21
> +#define K1_PDMA_I2S0_RX		22
> +#define K1_PDMA_I2S1_TX		23
> +#define K1_PDMA_I2S1_RX		24
> +#define K1_PDMA_UART5_TX	25
> +#define K1_PDMA_UART5_RX	26
> +#define K1_PDMA_UART6_TX	27
> +#define K1_PDMA_UART6_RX	28
> +#define K1_PDMA_UART7_TX	29
> +#define K1_PDMA_UART7_RX	30
> +#define K1_PDMA_UART8_TX	31
> +#define K1_PDMA_UART8_RX	32
> +#define K1_PDMA_UART9_TX	33
> +#define K1_PDMA_UART9_RX	34
> +#define K1_PDMA_I2C5_TX		35
> +#define K1_PDMA_I2C5_RX		36
> +#define K1_PDMA_I2C6_TX		37
> +#define K1_PDMA_I2C6_RX		38
> +#define K1_PDMA_I2C7_TX		39
> +#define K1_PDMA_I2C7_RX		40
> +#define K1_PDMA_I2C8_TX		41
> +#define K1_PDMA_I2C8_RX		42
> +#define K1_PDMA_CAN0_RX		43
> +#define K1_PDMA_QSPI_RX		44
> +#define K1_PDMA_QSPI_TX		45
> +
> +#endif /* _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_ */
> 
> -- 
> 2.43.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260608/f1f34e46/attachment.sig>

From sunilvl at oss.qualcomm.com  Mon Jun  8 10:35:17 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Mon, 8 Jun 2026 23:05:17 +0530
Subject: [PATCH] iommu/riscv: Add dependency between iommu and devices
In-Reply-To: <20260608142206426CGB5DlYd1xVlR8wrOawWH@zte.com.cn>
References: <CAB19ukEzQZktJcBAXi8X2Pwz+hO_FcR+iiaK9nsCAumP9BrHnw@mail.gmail.com>
 <20260608142206426CGB5DlYd1xVlR8wrOawWH@zte.com.cn>
Message-ID: <CAB19ukFMu1tW5QkCOY2e=DWbKrehEDv_iO5T7vEfKEGkbTFEEw@mail.gmail.com>

On Mon, Jun 8, 2026 at 11:52?AM <wang.yechao255 at zte.com.cn> wrote:
>
> > >
> > > From: Wang Yechao <wang.yechao255 at zte.com.cn>
> > >
> > > Commit 9156585280f1 ("ACPI: RIMT: Add dependency between iommu and
> > > devices") adds the dependency between iommu and devices on ACPI
> > > systems. On devicetree systems, the incorrect removal order also
> > > occurs.
> > >
> > Interesting. Why is it not handled by the fw_devlink infrastructure in DT?
> >
> > Thanks,
> > Sunil
>
> Thank you. I have noticed that commit e149573b2f84 ("of: property: Add device
> link support for "iommu-map"") adds support for "iommu-map" to the device link
> supplier bindings, so that probing of PCI devices can be deferred until after
> the IOMMU is available.
>
> The QEMU RISC-V virt machine currently lacks the "iommu-map" property for the
> PCIe bus when the iommu-pci device is used, which leads to this issue. Therefore,
> I believe the correct fix is to add the "iommu-map" property for PCIe in QEMU.
>
For PCI IOMMU, the dependency should be automatically taken care since iommu
should always be the first device in the hierarchy and scanned first.


From fustini at kernel.org  Mon Jun  8 11:11:26 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 8 Jun 2026 11:11:26 -0700
Subject: [PATCH v2] riscv: defconfig: thead: enable PCA953X GPIO driver
In-Reply-To: <20260608074104.2198409-1-m.szyprowski@samsung.com>
References: <CGME20260608074116eucas1p15c0f84c280d8645d778e42777bd238d1@eucas1p1.samsung.com>
 <20260608074104.2198409-1-m.szyprowski@samsung.com>
Message-ID: <aicFzt2i3_D4cebS@thelio>

On Mon, Jun 08, 2026 at 09:41:04AM +0200, Marek Szyprowski wrote:
> Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
> LicheePi4a board.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> ---
> v2:
> - copile GPIO_PCA953X as a module
> v1:
> https://lore.kernel.org/all/20260603082132.3200787-1-m.szyprowski at samsung.com/
> ---
>  arch/riscv/configs/defconfig | 2 ++
>  1 file changed, 2 insertions(+)

Reviewed-by: Drew Fustini <fustini at kernel.org>


From kernel at rembrandt.dev  Mon Jun  8 11:23:58 2026
From: kernel at rembrandt.dev (Andrew Rembrandt)
Date: Mon,  8 Jun 2026 20:23:58 +0200
Subject: [PATCH] riscv: dts: spacemit: k3-pico-itx: Fix non-functional ethernet TX timing
Message-ID: <20260608182358.170489-1-kernel@rembrandt.dev>

The "rgmii-id" PHY mode applies a symmetric 2ns internal delay in the
PHY. On the Pico-ITX board this leaves insufficient TX timing margin and
no ethernet traffic passes.

Add a 400ps MAC-side TX internal delay on top of the PHY's delay to
correct the TX clock/data skew. The value follows the vendor fork's
asymmetric tuning (tx-phase 73 x 33.3ps - 2000ps ID ~= 400ps); the
driver rounds tx-internal-delay-ps to the nearest supported step.

This builds on commit 3ea695eb111f ("dts: riscv: spacemit: k3: Fix I/O
power settings"), which fixed the GMAC0 1.8V/3.3V I/O switch

Tested on Pico-ITX hardware with iperf3: 60s TCP each direction and 60s
UDP, all at 1Gbps with no TX/RX errors on the interface.

Fixes: 74657a376960 ("riscv: dts: spacemit: Add ethernet device for K3")
Signed-off-by: Andrew Rembrandt <kernel at rembrandt.dev>
---
 arch/riscv/boot/dts/spacemit/k3-pico-itx.dts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts b/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
index b89c1521e664..59aecaa2d32a 100644
--- a/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
+++ b/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
@@ -186,6 +186,7 @@ &eth0 {
 	pinctrl-names = "default";
 	pinctrl-0 = <&gmac0_rgmii_0_cfg>, <&gmac0_phy_0_cfg>;
 	phy-mode = "rgmii-id";
+	tx-internal-delay-ps = <400>;
 	phy-handle = <&phy0>;
 	status = "okay";
 
-- 
2.54.0



From rppt at kernel.org  Mon Jun  8 12:00:22 2026
From: rppt at kernel.org (Mike Rapoport)
Date: Mon, 8 Jun 2026 22:00:22 +0300
Subject: [PATCH v16 00/10] arm64/riscv: Add support for crashkernel CMA
 reservation
In-Reply-To: <20260608091000.d88d7f5cc1bc4fa17f5774fe@linux-foundation.org>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608091000.d88d7f5cc1bc4fa17f5774fe@linux-foundation.org>
Message-ID: <aicRRrAmuCkTI68e@kernel.org>

On Mon, Jun 08, 2026 at 09:10:00AM -0700, Andrew Morton wrote:
> On Mon, 8 Jun 2026 15:34:49 +0800 Jinjie Ruan <ruanjinjie at huawei.com> wrote:
> 
> > The crash memory allocation, and the exclude of crashk_res, crashk_low_res
> > and crashk_cma memory are almost identical across different architectures,
> > This patch set handle them in crash core in a general way, which eliminate
> > a lot of duplication code.
> > 
> > And add support for crashkernel CMA reservation for arm64 and riscv.
> 
> fyi, AI review might have found a bunch of issues in arch-specific
> code, all of them pre-existing.

v15 grew to 23 patches because of them and Baoquan suggested to split the
fixes into a separate series.
 
> 	https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie at huawei.com

-- 
Sincerely yours,
Mike.


From martin at kaiser.cx  Mon Jun  8 13:18:27 2026
From: martin at kaiser.cx (Martin Kaiser)
Date: Mon,  8 Jun 2026 22:18:27 +0200
Subject: [PATCH] riscv: ftrace: sorttable: fix mcount sorting
Message-ID: <20260608201904.715374-1-martin@kaiser.cx>

Commit de04fca5d2f8 ("riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT")
enabled mcount sorting for risc-v. On my system, the sorting changes all
entries to address 0. The startup test reports that the mcount section is
properly sorted, but no traceable functions are registered at boot time.

[    0.000000] ftrace section at ffffffff8101bba0 sorted properly
[    0.000000] ftrace: allocating 0 entries in 128 pages
[    0.000000] ftrace: allocated 128 pages with 1 groups

The sorttable helper program does not take into account that the
-fpatchable-function-entry compiler flag reserves an additional 8 bytes
before each traceable function. (The size in bytes is the same for
RV32/64 or compressed/uncompressed instructions).

Define before_func = 8 to fix the mcount sorting for risc-v, share this
setting with arm64.

Fixes: de04fca5d2f8 ("riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT")
Signed-off-by: Martin Kaiser <martin at kaiser.cx>
---
 scripts/sorttable.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)

diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index e8ed11c680c6..da70f0938d04 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -895,13 +895,19 @@ static int do_file(char const *const fname, void *addr)
 #ifdef MCOUNT_SORT_ENABLED
 		sort_reloc = true;
 		rela_type = 0x403;
-		/* arm64 uses patchable function entry placing before function */
+#endif
+		/* fallthrough */
+	case EM_RISCV:
+#ifdef MCOUNT_SORT_ENABLED
+		/*
+		 * risc-v and arm64 use patchable function entry that stores
+		 * 8 bytes of nops before the function
+		 */
 		before_func = 8;
 #endif
 		/* fallthrough */
 	case EM_386:
 	case EM_LOONGARCH:
-	case EM_RISCV:
 	case EM_S390:
 	case EM_X86_64:
 		custom_sort = sort_relative_table_with_data;
-- 
2.43.7



From mhi at mailbox.org  Mon Jun  8 13:59:36 2026
From: mhi at mailbox.org (Maurice Hieronymus)
Date: Mon, 08 Jun 2026 22:59:36 +0200
Subject: [PATCH v2 0/2] rust: clk: Add ExclusiveClk and use it in
 pwm-th1520
In-Reply-To: <140FE1B3-73CA-45EA-B978-648A1A48B577@collabora.com>
References: <20260605-rate-exclusive-get-th1520-v2-0-695640bf7249@mailbox.org>
	 <140FE1B3-73CA-45EA-B978-648A1A48B577@collabora.com>
Message-ID: <e99b78d7aea835ab2960517e0c308b08538146ea.camel@mailbox.org>

On Mon, 2026-06-08 at 08:08 -0300, Daniel Almeida wrote:
> Hi Maurice,
> 
> There is some ongoing work to convert Clks to a type state pattern
> [0]
> 
> I wonder if you would be willing to rebase on top of that?
> I can push a new version if so.
Definitely! Just let me know when you pushed a new version. Thanks for
that.
> 
> It seems like we are mostly in agreement with that series, and only
> a few nits are missing.
> 
> ? Daniel
> 
> [0]:
> https://lore.kernel.org/rust-for-linux/20260107-clk-type-state-v3-0-77d3e3ee59c2 at collabora.com/


From akpm at linux-foundation.org  Mon Jun  8 14:22:58 2026
From: akpm at linux-foundation.org (Andrew Morton)
Date: Mon, 8 Jun 2026 14:22:58 -0700
Subject: [PATCH] mm/page_table_check: do not track special (PFN-mapped)
 PTEs
In-Reply-To: <20260608155758.1220420-1-andrey.smirnov@siderolabs.com>
References: <20260608155758.1220420-1-andrey.smirnov@siderolabs.com>
Message-ID: <20260608142258.5028187b1d245b46554eb2dc@linux-foundation.org>

On Mon,  8 Jun 2026 19:57:58 +0400 Andrey Smirnov <andrey.smirnov at siderolabs.com> wrote:

> The vDSO data store ("[vvar]") special mapping is created as a VM_PFNMAP
> mapping and its pages are installed into userspace with vmf_insert_pfn(),
> which produces special PTEs (pte_special()). On x86 and arm64 (and riscv)
> pte_user_accessible_page() only tests the PRESENT/USER bits and does not
> exclude special PTEs, so page_table_check accounts these PFN mappings in
> the per-page anon/file map counters even though they are not rmap-managed
> pages (vm_normal_page() returns NULL for them).
> 
> Most of these data pages live in the kernel image and are never freed, so
> the stray accounting is invisible. The time-namespace VVAR page is the
> exception: it is a real alloc_page() page that is released with
> __free_page() in free_time_ns() when the last task of a time namespace
> exits. Across the map / unmap / vdso_join_timens() zap transitions the
> special-PTE accounting is not balanced for this page, so a non-zero
> file_map_count survives to the free path and trips:
> 
>   kernel BUG at mm/page_table_check.c:143!
>   __page_table_check_zero+0xfb/0x130
>   __free_frozen_pages+0x52f/0x650
>   free_time_ns+0x85/0xc0
>   free_nsproxy+0x7f/0x130
>   do_exit+0x313/0xa60
>   do_group_exit+0x77/0x90
> 
> This is reliably reproducible on x86_64 and arm64 under heavy container/CI
> churn that rapidly creates and destroys time namespaces (CLONE_NEWTIME via
> runc / docker-init / tini), and was independently reported by syzbot on
> riscv. It only manifests when CONFIG_PAGE_TABLE_CHECK is active.
> 
> Special PTEs have no struct-page rmap semantics and must never have been
> tracked by page table check. Skip them in both the set and clear paths so
> the counters stay balanced (always zero) for PFN-mapped pages, regardless
> of how the architecture defines pte_user_accessible_page(). pte_special()
> is available generically (it is a no-op returning false on architectures
> without ARCH_HAS_PTE_SPECIAL), so this is a single, arch-independent fix.
> 
> Note that the v7.0 generic vDSO datastore rework in commit 05988dba1179
> ("vdso/datastore: Allocate data pages dynamically") incidentally avoids
> the problem by switching the mapping to VM_MIXEDMAP + vmf_insert_page()
> with balanced struct-page accounting. This patch fixes the still-affected
> VM_PFNMAP path used by 6.18.y and earlier, and additionally makes
> page_table_check robust against any future PFN-mapped user pages.

Thanks.

The patch isn't applicable to current -linus mainline.  I reworked it
as below, then deleted it.  It would be better if this rework came from
yourself (tested), please.  And a patch which applies will get checked
by Sashiko AI review.

--- a/mm/page_table_check.c~mm-page_table_check-do-not-track-special-pfn-mapped-ptes
+++ a/mm/page_table_check.c
@@ -151,7 +151,15 @@ void __page_table_check_pte_clear(struct
 	if (&init_mm == mm)
 		return;
 
-	if (pte_user_accessible_page(mm, addr, pte))
+	/*
+	 * PFN-mapped (special) PTEs - e.g. the vDSO/time-namespace "[vvar]"
+	 * mapping installed via vmf_insert_pfn() - are not rmap-managed and
+	 * must not be tracked here. Tracking them can leave a non-zero map
+	 * count on a struct page that is later freed (the time namespace VVAR
+	 * page in free_time_ns()), tripping the BUG_ON() in
+	 * __page_table_check_zero().
+	 */
+	if (pte_user_accessible_page(mm, addr, pte) && !pte_special(pte))
 		page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
 }
 EXPORT_SYMBOL(__page_table_check_pte_clear);
@@ -208,7 +216,7 @@ void __page_table_check_ptes_set(struct
 
 	for (i = 0; i < nr; i++)
 		__page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
-	if (pte_user_accessible_page(mm, addr, pte))
+	if (pte_user_accessible_page(mm, addr, pte) && !pte_special(pte))
 		page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
 }
 EXPORT_SYMBOL(__page_table_check_ptes_set);
_



From cp0613 at linux.alibaba.com  Mon Jun  8 18:30:08 2026
From: cp0613 at linux.alibaba.com (Chen Pei)
Date: Tue,  9 Jun 2026 09:30:08 +0800
Subject: [PATCH] riscv: ftrace: sorttable: fix mcount sorting
In-Reply-To: <20260608201904.715374-1-martin@kaiser.cx>
References: <20260608201904.715374-1-martin@kaiser.cx>
Message-ID: <20260609013008.6868-1-cp0613@linux.alibaba.com>

On Mon,  8 Jun 2026 22:18:27 +0200, martin at kaiser.cx wrote:

> The sorttable helper program does not take into account that the
> -fpatchable-function-entry compiler flag reserves an additional 8 bytes
> before each traceable function. (The size in bytes is the same for
> RV32/64 or compressed/uncompressed instructions).
> 
> Define before_func = 8 to fix the mcount sorting for risc-v, share this
> setting with arm64.
> 
> Fixes: de04fca5d2f8 ("riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT")

Hi Martin,

Thanks for the patch.

This has already been addressed by Wang Han here:
https://lore.kernel.org/linux-riscv/20260527123530.2593918-2-wanghan at linux.alibaba.com/

Thanks,
Pei


From ruanjinjie at huawei.com  Mon Jun  8 18:26:20 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Tue, 9 Jun 2026 09:26:20 +0800
Subject: [PATCH v2 1/5] arch: select HAVE_ARCH_BITREVERSE conditionally on
 BITREVERSE
In-Reply-To: <20260506175207.110893-2-ynorov@nvidia.com>
References: <20260506175207.110893-1-ynorov@nvidia.com>
 <20260506175207.110893-2-ynorov@nvidia.com>
Message-ID: <08bcdf6c-62e1-46d8-af83-4d5e74fff956@huawei.com>



On 5/7/2026 1:52 AM, Yury Norov wrote:
> Architectures may have bit reversal instructions, but if the API not
> needed, the corresponding option should not be selected because it may
> lead to generating the unneeded code.
> 
> Signed-off-by: Yury Norov <ynorov at nvidia.com>
> ---
>  arch/arm/Kconfig       | 2 +-
>  arch/arm64/Kconfig     | 2 +-
>  arch/loongarch/Kconfig | 2 +-
>  arch/mips/Kconfig      | 2 +-
>  lib/Kconfig            | 1 +
>  5 files changed, 5 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 71fc5dd4123f..0e963e54fe06 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -83,7 +83,7 @@ config ARM
>  	select HARDIRQS_SW_RESEND
>  	select HAS_IOPORT
>  	select HAVE_ARCH_AUDITSYSCALL if AEABI && !OABI_COMPAT
> -	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6
> +	select HAVE_ARCH_BITREVERSE if (CPU_32v7M || CPU_32v7) && !CPU_32v6 && BITREVERSE

I think there is a semantic confusion:

HAVE_ARCH_BITREVERSE indicates that the architecture itself has an
efficient bit?reverse implementation (e.g., the RBIT instruction on
ARMv7). It is a hardware capability declaration and should not depend on
a higher?level feature option like BITREVERSE.

>  	select HAVE_ARCH_JUMP_LABEL if !XIP_KERNEL && !CPU_ENDIAN_BE32 && MMU && (!PREEMPT_RT || !SMP)
>  	select HAVE_ARCH_KFENCE if MMU && !XIP_KERNEL
>  	select HAVE_ARCH_KGDB if !CPU_ENDIAN_BE32 && MMU
> diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
> index fe60738e5943..f5bb62c2ba9c 100644
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -150,7 +150,7 @@ config ARM64
>  	select HAVE_ACPI_APEI if (ACPI && EFI)
>  	select HAVE_ALIGNED_STRUCT_PAGE
>  	select HAVE_ARCH_AUDITSYSCALL
> -	select HAVE_ARCH_BITREVERSE
> +	select HAVE_ARCH_BITREVERSE if BITREVERSE

[..]

>  	bool
>  	default n
> +	depends on BITREVERSE
>  	help
>  	  This option enables the use of hardware bit-reversal instructions on
>  	  architectures which support such operations.



From ruanjinjie at huawei.com  Mon Jun  8 18:38:48 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Tue, 9 Jun 2026 09:38:48 +0800
Subject: [PATCH v2 4/5] arch/riscv: Add bitrev.h file to support rev8 and
 brev8
In-Reply-To: <20260506175207.110893-5-ynorov@nvidia.com>
References: <20260506175207.110893-1-ynorov@nvidia.com>
 <20260506175207.110893-5-ynorov@nvidia.com>
Message-ID: <2bd07ecf-9f7f-4c47-b5d8-0f17b72bc56d@huawei.com>



On 5/7/2026 1:52 AM, Yury Norov wrote:
> From: Jinjie Ruan <ruanjinjie at huawei.com>
> 
> The RISC-V Bit-manipulation Extension for Cryptography (Zbkb) provides
> the 'brev8' instruction, which reverses the bits within each byte.
> Combined with the 'rev8' instruction (from Zbb or Zbkb), which reverses
> the byte order of a register, we can efficiently implement 16-bit,
> 32-bit, and (on RV64) 64-bit bit reversal.
> 
> This is significantly faster than the default software table-lookup
> implementation in lib/bitrev.c, as it replaces memory accesses and
> multiple arithmetic operations with just two or three hardware
> instructions.
> 
> Select HAVE_ARCH_BITREVERSE as well as GENERIC_BITREVERSE,
> and provide <asm/bitrev.h> to utilize these instructions when
> the Zbkb extension is available at runtime via the alternatives
> mechanism.
> 
> [Yury: select the options conditionally on BITREVERSE]
> 
> Link: https://docs.riscv.org/reference/isa/unpriv/b-st-ext.html
> Suggested-by: David Laight <david.laight.linux at gmail.com>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> Signed-off-by: Yury Norov <ynorov at nvidia.com>
> ---
>  arch/riscv/Kconfig              |  2 ++
>  arch/riscv/include/asm/bitrev.h | 51 +++++++++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)
>  create mode 100644 arch/riscv/include/asm/bitrev.h
> 
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index d235396c4514..a708583f785d 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -104,6 +104,7 @@ config RISCV
>  	select FUNCTION_ALIGNMENT_8B if DYNAMIC_FTRACE_WITH_CALL_OPS
>  	select GENERIC_ARCH_TOPOLOGY
>  	select GENERIC_ATOMIC64 if !64BIT
> +	select GENERIC_BITREVERSE if HAVE_ARCH_BITREVERSE

Maybe 'select GENERIC_BITREVERSE if BITREVERSE' ?

>  	select GENERIC_CLOCKEVENTS_BROADCAST if SMP
>  	select GENERIC_CPU_DEVICES
>  	select GENERIC_CPU_VULNERABILITIES
> @@ -128,6 +129,7 @@ config RISCV
>  	select HAS_IOPORT if MMU
>  	select HAVE_ALIGNED_STRUCT_PAGE
>  	select HAVE_ARCH_AUDITSYSCALL
> +	select HAVE_ARCH_BITREVERSE if RISCV_ISA_ZBKB && BITREVERSE
>  	select HAVE_ARCH_HUGE_VMALLOC if HAVE_ARCH_HUGE_VMAP
>  	select HAVE_ARCH_HUGE_VMAP if MMU && 64BIT
>  	select HAVE_ARCH_JUMP_LABEL
> diff --git a/arch/riscv/include/asm/bitrev.h b/arch/riscv/include/asm/bitrev.h
> new file mode 100644
> index 000000000000..4b9b8d34cc3b
> --- /dev/null
> +++ b/arch/riscv/include/asm/bitrev.h
> @@ -0,0 +1,51 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef __ASM_BITREV_H
> +#define __ASM_BITREV_H
> +
> +#include <linux/types.h>
> +#include <asm/cpufeature-macros.h>
> +#include <asm/hwcap.h>
> +#include <asm-generic/bitops/__bitrev.h>
> +
> +static __always_inline __attribute_const__ u32 __arch_bitrev32(u32 x)
> +{
> +	unsigned long result;
> +
> +	if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZBKB))
> +		return generic___bitrev32(x);
> +
> +	asm volatile(
> +		".option push\n"
> +		".option arch,+zbkb\n"
> +		"rev8 %0, %1\n"
> +		"brev8 %0, %0\n"
> +		".option pop"
> +		: "=r" (result) : "r" ((long)x)
> +	);
> +
> +	return result >> (__riscv_xlen - 32);
> +}
> +
> +static __always_inline __attribute_const__ u16 __arch_bitrev16(u16 x)
> +{
> +	return __arch_bitrev32(x) >> 16;
> +}
> +
> +static __always_inline __attribute_const__ u8 __arch_bitrev8(u8 x)
> +{
> +	unsigned long result;
> +
> +	if (!riscv_has_extension_likely(RISCV_ISA_EXT_ZBKB))
> +		return generic___bitrev8(x);
> +
> +	asm volatile(
> +		".option push\n"
> +		".option arch,+zbkb\n"
> +		"brev8 %0, %1\n"
> +		".option pop"
> +		: "=r" (result) : "r" ((long)x)
> +	);
> +
> +	return result;
> +}
> +#endif



From ruanjinjie at huawei.com  Mon Jun  8 18:53:36 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Tue, 9 Jun 2026 09:53:36 +0800
Subject: [PATCH v2 2/5] lib/bitrev: Introduce GENERIC_BITREVERSE
In-Reply-To: <20260506175207.110893-3-ynorov@nvidia.com>
References: <20260506175207.110893-1-ynorov@nvidia.com>
 <20260506175207.110893-3-ynorov@nvidia.com>
Message-ID: <81d1ae23-8d18-4dff-a5c9-1824980b08ef@huawei.com>



On 5/7/2026 1:52 AM, Yury Norov wrote:
> The generic bit reversal implementation is controlled by
> !HAVE_ARCH_BITREVERSE. This makes it difficult for architectures to
> provide a hardware-accelerated implementation while being able to
> fall back to the generic version if needed.
> 
> This patch adds GENERIC_BITREVERSE, so bitreverse API is controlled by
> BITREVERSE, GENERIC_BITREVERSE and HAVE_ARCH_BITREVERSE options. The
> relationship between them is described as follows:
> 
>  - BITREVERSE is selected by user code; it's required to generate the API;
>  - Architectures may select HAVE_ARCH_BITREVERSE and provide an arch
>    implementation in arch/$(ARCH)/include/asm/bitrev.h.
>  - if HAVE_ARCH_BITREVERSE isn't set, BITREVERSE selects GENERIC_BITREVERSE;
>  - if GENERIC_BITREVERSE is set and HAVE_ARCH_BITREVERSE is not, the kernel
>    provides generic implementation only, and wires bitrevXX() to it.
>  - if HAVE_ARCH_BITREVERSE is set and GENERIC_BITREVERSE is not, the arch
>    code provides __arch_bitrevXX(), and it is wired to bitrevXX();
>  - if both GENERIC_BITREVERSE and HAVE_ARCH_BITREVERSE are selected, the kernel
>    generates generic___bitrev(), but wires bitrev() to the __arch_bitrev().
> 
> The last option allows architectures to use generic___bitrev() as a
> fallback option.
> 
> Drivers and core code should never select GENERIC_BITREVERSE or
> HAVE_ARCH_BITREVERSE explicitly.
> 
> Architectures that require generic bitreverse API as a fallback should
> explicitly enable GENERIC_BITREVERSE together with HAVE_ARCH_BITREVERSE.
> 
> Signed-off-by: Yury Norov <ynorov at nvidia.com>
> ---
>  lib/Kconfig  | 12 ++++++++++++
>  lib/Makefile |  2 +-
>  lib/bitrev.c |  3 ---
>  3 files changed, 13 insertions(+), 4 deletions(-)
> 
> diff --git a/lib/Kconfig b/lib/Kconfig
> index d8e7e89ae320..a33988adfaa3 100644
> --- a/lib/Kconfig
> +++ b/lib/Kconfig
> @@ -54,6 +54,7 @@ config PACKING_KUNIT_TEST
>  
>  config BITREVERSE
>  	tristate
> +	select GENERIC_BITREVERSE if !HAVE_ARCH_BITREVERSE
>  
>  config HAVE_ARCH_BITREVERSE
>  	bool
> @@ -63,6 +64,17 @@ config HAVE_ARCH_BITREVERSE
>  	  This option enables the use of hardware bit-reversal instructions on
>  	  architectures which support such operations.
>  
> +config GENERIC_BITREVERSE
> +	tristate
> +	depends on BITREVERSE
> +	help
> +	  Generic bit reversal implementation. Drivers should never enable
> +	  it explicitly. Instead, enable BITREVERSE.


The later riscv implementation force GENERIC_BITREVERSE even when
HAVE_ARCH_BITREVERSE=y but triggers a Kconfig unmet direct dependency
warning as below:

warning: (RISCV) selects GENERIC_BITREVERSE which has unmet direct
dependencies (BITREVERSE)

This happens because select ignores depends on clauses and can force a
tristate symbol to y even when its dependency BITREVERSE is only =m. The
warning is a symptom of an invalid dependency chain.

Link:
https://lore.kernel.org/all/20260506214943.1AAE8C2BCB0 at smtp.kernel.org/

> +
> +	  Architectures may want to select it as a fall-back option for
> +	  HAVE_ARCH_BITREVERSE, when the hardware-accelerated bit reverse
> +	  instruction set is optional, like RISC-V ZBKB extension.
> +
>  config ARCH_HAS_STRNCPY_FROM_USER
>  	bool
>  
> diff --git a/lib/Makefile b/lib/Makefile
> index f33a24bf1c19..23e07d19d01c 100644
> --- a/lib/Makefile
> +++ b/lib/Makefile
> @@ -145,7 +145,7 @@ obj-$(CONFIG_DEBUG_PREEMPT) += smp_processor_id.o
>  obj-$(CONFIG_LIST_HARDENED) += list_debug.o
>  obj-$(CONFIG_DEBUG_OBJECTS) += debugobjects.o
>  
> -obj-$(CONFIG_BITREVERSE) += bitrev.o
> +obj-$(CONFIG_GENERIC_BITREVERSE) += bitrev.o
>  obj-$(CONFIG_LINEAR_RANGES) += linear_ranges.o
>  obj-$(CONFIG_PACKING)	+= packing.o
>  obj-$(CONFIG_PACKING_KUNIT_TEST) += packing_test.o
> diff --git a/lib/bitrev.c b/lib/bitrev.c
> index 81b56e0a7f32..05088231f31f 100644
> --- a/lib/bitrev.c
> +++ b/lib/bitrev.c
> @@ -1,5 +1,4 @@
>  // SPDX-License-Identifier: GPL-2.0-only
> -#ifndef CONFIG_HAVE_ARCH_BITREVERSE
>  #include <linux/types.h>
>  #include <linux/module.h>
>  #include <linux/bitrev.h>
> @@ -43,5 +42,3 @@ const u8 byte_rev_table[256] = {
>  	0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
>  };
>  EXPORT_SYMBOL_GPL(byte_rev_table);
> -
> -#endif /* CONFIG_HAVE_ARCH_BITREVERSE */



From pasha.tatashin at soleen.com  Mon Jun  8 19:23:28 2026
From: pasha.tatashin at soleen.com (Pasha Tatashin)
Date: Tue, 9 Jun 2026 02:23:28 +0000
Subject: [PATCH] mm/page_table_check: do not track special (PFN-mapped)
 PTEs
In-Reply-To: <20260608142258.5028187b1d245b46554eb2dc@linux-foundation.org>
References: <20260608155758.1220420-1-andrey.smirnov@siderolabs.com>
 <20260608142258.5028187b1d245b46554eb2dc@linux-foundation.org>
Message-ID: <aid4yw9WRvZEm2BV@plex>

On 06-08 14:22, Andrew Morton wrote:
> On Mon,  8 Jun 2026 19:57:58 +0400 Andrey Smirnov <andrey.smirnov at siderolabs.com> wrote:
> 
> > The vDSO data store ("[vvar]") special mapping is created as a VM_PFNMAP
> > mapping and its pages are installed into userspace with vmf_insert_pfn(),
> > which produces special PTEs (pte_special()). On x86 and arm64 (and riscv)
> > pte_user_accessible_page() only tests the PRESENT/USER bits and does not
> > exclude special PTEs, so page_table_check accounts these PFN mappings in
> > the per-page anon/file map counters even though they are not rmap-managed
> > pages (vm_normal_page() returns NULL for them).
> > 
> > Most of these data pages live in the kernel image and are never freed, so
> > the stray accounting is invisible. The time-namespace VVAR page is the
> > exception: it is a real alloc_page() page that is released with
> > __free_page() in free_time_ns() when the last task of a time namespace
> > exits. Across the map / unmap / vdso_join_timens() zap transitions the
> > special-PTE accounting is not balanced for this page, so a non-zero
> > file_map_count survives to the free path and trips:
> > 
> >   kernel BUG at mm/page_table_check.c:143!
> >   __page_table_check_zero+0xfb/0x130
> >   __free_frozen_pages+0x52f/0x650
> >   free_time_ns+0x85/0xc0
> >   free_nsproxy+0x7f/0x130
> >   do_exit+0x313/0xa60
> >   do_group_exit+0x77/0x90
> > 
> > This is reliably reproducible on x86_64 and arm64 under heavy container/CI
> > churn that rapidly creates and destroys time namespaces (CLONE_NEWTIME via
> > runc / docker-init / tini), and was independently reported by syzbot on
> > riscv. It only manifests when CONFIG_PAGE_TABLE_CHECK is active.
> > 
> > Special PTEs have no struct-page rmap semantics and must never have been
> > tracked by page table check. Skip them in both the set and clear paths so
> > the counters stay balanced (always zero) for PFN-mapped pages, regardless
> > of how the architecture defines pte_user_accessible_page(). pte_special()
> > is available generically (it is a no-op returning false on architectures
> > without ARCH_HAS_PTE_SPECIAL), so this is a single, arch-independent fix.
> > 
> > Note that the v7.0 generic vDSO datastore rework in commit 05988dba1179
> > ("vdso/datastore: Allocate data pages dynamically") incidentally avoids
> > the problem by switching the mapping to VM_MIXEDMAP + vmf_insert_page()
> > with balanced struct-page accounting. This patch fixes the still-affected
> > VM_PFNMAP path used by 6.18.y and earlier, and additionally makes
> > page_table_check robust against any future PFN-mapped user pages.

Thank you for detailed explanation of the bug, and it makes sense to me.

> Thanks.
> 
> The patch isn't applicable to current -linus mainline.  I reworked it
> as below, then deleted it.  It would be better if this rework came from
> yourself (tested), please.  And a patch which applies will get checked
> by Sashiko AI review.

+1.

Pasha

> --- a/mm/page_table_check.c~mm-page_table_check-do-not-track-special-pfn-mapped-ptes
> +++ a/mm/page_table_check.c
> @@ -151,7 +151,15 @@ void __page_table_check_pte_clear(struct
>  	if (&init_mm == mm)
>  		return;
>  
> -	if (pte_user_accessible_page(mm, addr, pte))
> +	/*
> +	 * PFN-mapped (special) PTEs - e.g. the vDSO/time-namespace "[vvar]"
> +	 * mapping installed via vmf_insert_pfn() - are not rmap-managed and
> +	 * must not be tracked here. Tracking them can leave a non-zero map
> +	 * count on a struct page that is later freed (the time namespace VVAR
> +	 * page in free_time_ns()), tripping the BUG_ON() in
> +	 * __page_table_check_zero().
> +	 */
> +	if (pte_user_accessible_page(mm, addr, pte) && !pte_special(pte))
>  		page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
>  }
>  EXPORT_SYMBOL(__page_table_check_pte_clear);
> @@ -208,7 +216,7 @@ void __page_table_check_ptes_set(struct
>  
>  	for (i = 0; i < nr; i++)
>  		__page_table_check_pte_clear(mm, addr + PAGE_SIZE * i, ptep_get(ptep + i));
> -	if (pte_user_accessible_page(mm, addr, pte))
> +	if (pte_user_accessible_page(mm, addr, pte) && !pte_special(pte))
>  		page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
>  }
>  EXPORT_SYMBOL(__page_table_check_ptes_set);
> _
> 


From ryan_chen at aspeedtech.com  Mon Jun  8 19:47:17 2026
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Tue, 9 Jun 2026 10:47:17 +0800
Subject: [PATCH v9 0/4] Introduce ASPEED AST27xx BMC SoC
Message-ID: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>

This introduces initial support for the Aspeed AST27xx SoC and the AST2700
Evaluation Board (EVB) to the Linux kernel. The AST27xx is the 8th
generation Baseboard Management Controller (BMC) SoC from Aspeed,
featuring improved performance, enhanced security, and expanded I/O
capabilities compared to previous generations.

AST27xx SOC Family
 - https://www.aspeedtech.com/server_ast2700/
 - https://www.aspeedtech.com/server_ast2720/
 - https://www.aspeedtech.com/server_ast2750/

Bindings Dependencies:
 check with "make CHECK_DTBS=y W=1 arch/arm64/boot/dts/aspeed/ dtbs"

- scu/scu-ic/silicon-id: Documentation/devicetree/bindings/mfd/aspeed,ast2x00-scu.yaml
- intc: Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2700-interrupt.yaml
- scu-ic: Documentation/devicetree/bindings/interrupt-controller/aspeed,ast2500-scu-ic.yaml
- pinctrl soc0: Documentation/devicetree/bindings/pinctrl/aspeed,ast2700-soc0-pinctrl.yaml
- pinctrl soc1: Documentation/devicetree/bindings/pinctrl/aspeed,ast2700-soc1-pinctrl.yaml
- gpio: Documentation/devicetree/bindings/gpio/aspeed,ast2400-gpio.yaml
- sgpio: Documentation/devicetree/bindings/gpio/aspeed,sgpio.yaml
- fmc/spi: Documentation/devicetree/bindings/spi/aspeed,ast2600-fmc.yaml
- mdio: Documentation/devicetree/bindings/net/aspeed,ast2600-mdio.yaml
- sd/sdhci: Documentation/devicetree/bindings/mmc/aspeed,sdhci.yaml
- usb-vhub: Documentation/devicetree/bindings/usb/aspeed,usb-vhub.yaml
- ehci: Documentation/devicetree/bindings/usb/generic-ehci.yaml
- uhci: Documentation/devicetree/bindings/usb/usb-uhci.yaml
- wdt: Documentation/devicetree/bindings/watchdog/aspeed,ast2400-wdt.yaml
- mailbox: Documentation/devicetree/bindings/mailbox/aspeed,ast2700-mailbox.yaml
- adc: Documentation/devicetree/bindings/iio/adc/aspeed,ast2600-adc.yaml
- pwm-tach: Documentation/devicetree/bindings/hwmon/aspeed,g6-pwm-tach.yaml
- fsi: Documentation/devicetree/bindings/fsi/aspeed,ast2600-fsi-master.yaml

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
---
Changes in v9:
- use b4 send
- rebase on linux-next
- split aspeed-g7-common.dtsi to aspeed-g7-soc0/1.dtsi
- update all interrupt-extend by use aspeed,ast2700-intc0/1 parent
- MAINTAINERS: add arch/arm64/boot/dts/aspeed/ entry
- Kconfig.platforms: reword ARCH_ASPEED help text
- cover: complete bindings dependencies list and fix intc binding path
- Link to v8: https://lore.kernel.org/all/20251112101157.2149169-1-ryan_chen at aspeedtech.com/

Changes in v8:
- Kconfig.platforms
 - update commit message and help description.
- aspeed-g7-a35.dtsi,aspeed-g7-common.dtsi,ast2700-evb.dts
 - change license using a dual license of MIT + GPL2.0+
 - add company copyright.
- merge original v7 patch(3/5) and (4/5) to 1 v8patch(3/4)
 - that can do build test with make CHECK_DTBS=y W=1 arch/arm64/boot/dts/aspeed/ dtbs
- Link to v7: https://lore.kernel.org/all/20251107055629.4075519-1-ryan_chen at aspeedtech.com/

Changes in v7:
- remove aspeed,ast2x00-scu.yaml modify
- separate aspeed-g7.dtsi to aspeed-g7-a35.dtsi and aspeed-g7-common.dtsi
-move aliases to ast2700-evb.dts file
-Link to v6: https://lore.kernel.org/all/20251022070543.1169173-1-ryan_chen at aspeedtech.com/

Changes in v6:
- rebased on v6.18-rc1
- aspeed,ast2x00-scu.yaml
 - fixed dt-binding yaml issuse report.
-Linke to v5: https://lore.kernel.org/all/20250901031311.1247805-1-ryan_chen at aspeedtech.com/

Changes in v5:
- modify ast27XX 7th generation description to 8th generation.
- aspeed.yaml
 - modify missing blank line.
- Kconfig.platforms
 - modify ast27XX 7th generation to 8th generation.
-Link to v4: https://lore.kernel.org/all/20250821080214.513090-1-ryan_chen at aspeedtech.com/

Changes in v4:
- make CHECK_DTBS=y arch/arm64/boot/dts/aspeed/ fix.
- modify commit message remove itemlize.
- remove modify aspeed,ast2700-intc.yaml patch.
- aspeed.yaml
 - Add AST2700 board compatible.
- aspeed-g7.dtsi
 - modify all size-cells from 1 to 2.
 - add serial aliases, gpio, mdio, uart0 ~ 14.
 - add firmware for optee, reserved memory for atf and optee.
 - modify cpu at 0 to cpu0: cpu at 0.
 - fix intc-ic for yaml dependency.
- ast2700-evb.dts
 - update stdout-path = "serial12:115200n8";
-Link to v3: https://lore.kernel.org/all/20241212155237.848336-1-kevin_chen at aspeedtech.com/

Changes in v3:
- Split clk and reset driver to other commits, which are in series of
  "Add support for AST2700 clk driver".
- For BMC console by UART12, add uart12 using ASPEED INTC architecture.
aspeed,ast2700-intc.yaml
- Add minItems to 1 to fix the warning by "make dtbs_check W=1".
- Add intc1 into example.
Kconfig.platforms
  - Remove MACH_ASPEED_G7.
-Link to v2: https://lore.kernel.org/all/20240802090544.2741206-1-kevin_chen at aspeedtech.com/

Changes in v2:
-Link to v1: https://lore.kernel.org/all/20250612100933.3007673-1-ryan_chen at aspeedtech.com/

---
Ryan Chen (4):
      dt-bindings: arm: aspeed: Add AST2700 board compatible
      arm64: Kconfig: Add ASPEED SoC family Kconfig support
      arm64: dts: aspeed: Add initial AST27xx SoC device tree
      arm64: configs: Update defconfig for AST2700 platform support

 .../devicetree/bindings/arm/aspeed/aspeed.yaml     |    6 +
 MAINTAINERS                                        |    1 +
 arch/arm64/Kconfig.platforms                       |    6 +
 arch/arm64/boot/dts/Makefile                       |    1 +
 arch/arm64/boot/dts/aspeed/Makefile                |    4 +
 .../dts/aspeed/aspeed-evb-flash-layout-128.dtsi    |   32 +
 arch/arm64/boot/dts/aspeed/aspeed-g7-a35.dtsi      |  196 ++++
 .../boot/dts/aspeed/aspeed-g7-soc0-pinctrl.dtsi    |  225 ++++
 arch/arm64/boot/dts/aspeed/aspeed-g7-soc0.dtsi     |  230 ++++
 .../boot/dts/aspeed/aspeed-g7-soc1-pinctrl.dtsi    | 1113 ++++++++++++++++++++
 arch/arm64/boot/dts/aspeed/aspeed-g7-soc1.dtsi     |  557 ++++++++++
 arch/arm64/boot/dts/aspeed/ast2700-evb.dts         |   65 ++
 arch/arm64/configs/defconfig                       |    1 +
 13 files changed, 2437 insertions(+)
---
base-commit: 6e845bcb78c95af935094040bd4edc3c2b6dd784
change-id: 20260205-upstream_ast2700-6efec42ab228

Best regards,
-- 
Ryan Chen <ryan_chen at aspeedtech.com>



From ryan_chen at aspeedtech.com  Mon Jun  8 19:47:18 2026
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Tue, 9 Jun 2026 10:47:18 +0800
Subject: [PATCH v9 1/4] dt-bindings: arm: aspeed: Add AST2700 board
 compatible
In-Reply-To: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>
References: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>
Message-ID: <20260609-upstream_ast2700-v9-1-f631752f0cb1@aspeedtech.com>

Add device tree compatible string for AST2700 based boards
("aspeed,ast2700-evb" and "aspeed,ast2700") to the Aspeed SoC
board bindings. This allows proper schema validation and
enables support for AST2700 platforms.

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
index 9ba195b8f22d..dd7996960de3 100644
--- a/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
+++ b/Documentation/devicetree/bindings/arm/aspeed/aspeed.yaml
@@ -119,4 +119,10 @@ properties:
               - ufispace,ncplite-bmc
           - const: aspeed,ast2600
 
+      - description: AST2700 based boards
+        items:
+          - enum:
+              - aspeed,ast2700-evb
+          - const: aspeed,ast2700
+
 additionalProperties: true

-- 
2.34.1



From ryan_chen at aspeedtech.com  Mon Jun  8 19:47:19 2026
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Tue, 9 Jun 2026 10:47:19 +0800
Subject: [PATCH v9 2/4] arm64: Kconfig: Add ASPEED SoC family Kconfig
 support
In-Reply-To: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>
References: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>
Message-ID: <20260609-upstream_ast2700-v9-2-f631752f0cb1@aspeedtech.com>

Add support for ASPEED SoC family like ast27XX 8th
generation ASPEED BMCs.

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
---
 arch/arm64/Kconfig.platforms | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm64/Kconfig.platforms b/arch/arm64/Kconfig.platforms
index dc995a732117..d2acfac73003 100644
--- a/arch/arm64/Kconfig.platforms
+++ b/arch/arm64/Kconfig.platforms
@@ -48,6 +48,12 @@ config ARCH_ARTPEC
 	help
 	   This enables support for the ARMv8 based ARTPEC SoC Family.
 
+config ARCH_ASPEED
+	bool "Aspeed SoC family"
+	help
+	  This enables support for ASPEED's SoC family, such as the
+	  ast27XX 8th generation Baseboard Management Controller (BMC).
+
 config ARCH_AXIADO
 	bool "Axiado SoC Family"
 	select GPIOLIB

-- 
2.34.1



From ryan_chen at aspeedtech.com  Mon Jun  8 19:47:20 2026
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Tue, 9 Jun 2026 10:47:20 +0800
Subject: [PATCH v9 3/4] arm64: dts: aspeed: Add initial AST27xx SoC device
 tree
In-Reply-To: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>
References: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>
Message-ID: <20260609-upstream_ast2700-v9-3-f631752f0cb1@aspeedtech.com>

Add initial device tree support for the ASPEED AST27xx family, the
8th-generation Baseboard Management Controller (BMC) SoCs.

AST27xx SOC Family
 - https://www.aspeedtech.com/server_ast2700/
 - https://www.aspeedtech.com/server_ast2720/
 - https://www.aspeedtech.com/server_ast2750/

The AST27xx features a dual-SoC architecture consisting of two dies,
referred to as SoC0 and SoC1 - interconnected through an internal
proprietary bus. Both SoCs share the same address decoding scheme,
while each maintains independent clock and reset domains.

- SoC0 (CPU die): contains a quad-core Cortex-A35 cluster and two
  Cortex-M4 cores, along with high-speed peripherals.
- SoC1 (I/O die): includes the BootMCU (responsible for system
  boot) and its own clock/reset domains low-speed peripherals.

The device tree describes the SoC0 and SoC1 domains and their peripheral
layouts.

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
---
 MAINTAINERS                                        |    1 +
 arch/arm64/boot/dts/Makefile                       |    1 +
 arch/arm64/boot/dts/aspeed/Makefile                |    4 +
 .../dts/aspeed/aspeed-evb-flash-layout-128.dtsi    |   32 +
 arch/arm64/boot/dts/aspeed/aspeed-g7-a35.dtsi      |  196 ++++
 .../boot/dts/aspeed/aspeed-g7-soc0-pinctrl.dtsi    |  225 ++++
 arch/arm64/boot/dts/aspeed/aspeed-g7-soc0.dtsi     |  230 ++++
 .../boot/dts/aspeed/aspeed-g7-soc1-pinctrl.dtsi    | 1113 ++++++++++++++++++++
 arch/arm64/boot/dts/aspeed/aspeed-g7-soc1.dtsi     |  557 ++++++++++
 arch/arm64/boot/dts/aspeed/ast2700-evb.dts         |   65 ++
 10 files changed, 2424 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 20bd55913b2d..51d12804ad5a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2683,6 +2683,7 @@ T:	git git://git.kernel.org/pub/scm/linux/kernel/git/bmc/linux.git
 F:	Documentation/devicetree/bindings/arm/aspeed/
 F:	arch/arm/boot/dts/aspeed/
 F:	arch/arm/mach-aspeed/
+F:	arch/arm64/boot/dts/aspeed/
 N:	aspeed
 
 ARM/AXIADO ARCHITECTURE
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index 98ec8f1b76e4..fc726b215f12 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -9,6 +9,7 @@ subdir-y += amlogic
 subdir-y += apm
 subdir-y += apple
 subdir-y += arm
+subdir-y += aspeed
 subdir-y += axiado
 subdir-y += bitmain
 subdir-y += blaize
diff --git a/arch/arm64/boot/dts/aspeed/Makefile b/arch/arm64/boot/dts/aspeed/Makefile
new file mode 100644
index 000000000000..ffe7e15017cc
--- /dev/null
+++ b/arch/arm64/boot/dts/aspeed/Makefile
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+
+dtb-$(CONFIG_ARCH_ASPEED) += \
+	ast2700-evb.dtb
diff --git a/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi
new file mode 100644
index 000000000000..b54915f06efd
--- /dev/null
+++ b/arch/arm64/boot/dts/aspeed/aspeed-evb-flash-layout-128.dtsi
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+
+partitions {
+	compatible = "fixed-partitions";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+	u-boot at 0 {
+		reg = <0x0 0x400000>; // 4MB
+		label = "u-boot";
+	};
+
+	u-boot-env at 400000 {
+		reg = <0x400000 0x20000>; // 128KB
+		label = "u-boot-env";
+	};
+
+	kernel at 420000 {
+		reg = <0x420000 0x900000>; // 9MB
+		label = "kernel";
+	};
+
+	rofs at d20000 {
+		reg = <0xd20000 0x52E0000>; // 82.875MB
+		label = "rofs";
+	};
+
+	rwfs at 6000000 {
+		reg = <0x6000000 0x2000000>; // 32MB
+		label = "rwfs";
+	};
+};
diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-a35.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-g7-a35.dtsi
new file mode 100644
index 000000000000..ef283d95649a
--- /dev/null
+++ b/arch/arm64/boot/dts/aspeed/aspeed-g7-a35.dtsi
@@ -0,0 +1,196 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Device Tree Source for AST27xx SoC Family
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+	compatible = "aspeed,ast2700";
+	interrupt-parent = <&gic>;
+	#address-cells = <2>;
+	#size-cells = <2>;
+
+	cpus {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		cpu0: cpu at 0 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a35";
+			reg = <0x0 0x0>;
+			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2>;
+		};
+
+		cpu1: cpu at 1 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a35";
+			reg = <0x0 0x1>;
+			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2>;
+		};
+
+		cpu2: cpu at 2 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a35";
+			reg = <0x0 0x2>;
+			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2>;
+		};
+
+		cpu3: cpu at 3 {
+			device_type = "cpu";
+			compatible = "arm,cortex-a35";
+			reg = <0x0 0x3>;
+			enable-method = "psci";
+			i-cache-size = <0x8000>;
+			i-cache-line-size = <64>;
+			i-cache-sets = <256>;
+			d-cache-size = <0x8000>;
+			d-cache-line-size = <64>;
+			d-cache-sets = <128>;
+			next-level-cache = <&l2>;
+		};
+
+		l2: l2-cache0 {
+			compatible = "cache";
+			cache-level = <2>;
+			cache-unified;
+			cache-size = <0x80000>;
+			cache-line-size = <64>;
+			cache-sets = <1024>;
+		};
+	};
+
+	secondary {
+		#address-cells = <2>;
+		/* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/of/address.c?h=v6.16#n491 */
+		#size-cells = <0>;
+		/* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/drivers/of/address.c?h=v6.16#n430 */
+
+		ssp_nvic: interrupt-controller at 1,e000e100 {
+			compatible = "arm,v7m-nvic";
+			#interrupt-cells = <2>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <1 0xe000e100>;
+			arm,num-irq-priority-bits = <3>;
+			status = "disabled";
+		};
+	};
+
+	tertiary {
+		#address-cells = <2>;
+		#size-cells = <0>;
+
+		tsp_nvic: interrupt-controller at 2,e000e100 {
+			compatible = "arm,v7m-nvic";
+			#interrupt-cells = <2>;
+			#address-cells = <0>;
+			interrupt-controller;
+			reg = <2 0xe000e100>;
+			arm,num-irq-priority-bits = <3>;
+			status = "disabled";
+		};
+	};
+
+	bootmcu {
+		bootmcu_hlic: interrupt-controller {
+			compatible = "riscv,cpu-intc";
+			interrupt-controller;
+			#interrupt-cells = <1>;
+			status = "disabled";
+		};
+	};
+
+	firmware {
+		optee: optee {
+			compatible = "linaro,optee-tz";
+			method = "smc";
+		};
+
+		psci {
+			compatible = "arm,psci-1.0";
+			method = "smc";
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+
+		atf: trusted-firmware-a at 430000000 {
+			reg = <0x4 0x30000000 0x0 0x80000>;
+			no-map;
+		};
+
+		optee_core: optee-core at 430080000 {
+			reg = <0x4 0x30080000 0x0 0x1000000>;
+			no-map;
+		};
+	};
+
+	arm-pmu {
+		compatible = "arm,cortex-a35-pmu";
+		interrupts = <GIC_PPI 7 IRQ_TYPE_LEVEL_HIGH>;
+	};
+
+	timer {
+		compatible = "arm,armv8-timer";
+		interrupts = <GIC_PPI 13 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 14 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 11 IRQ_TYPE_LEVEL_LOW>,
+			     <GIC_PPI 10 IRQ_TYPE_LEVEL_LOW>;
+		arm,cpu-registers-not-fw-configured;
+		always-on;
+	};
+
+	gic: interrupt-controller at 12200000 {
+		compatible = "arm,gic-v3";
+		reg = <0 0x12200000 0 0x10000>, /* GICD */
+		      <0 0x12280000 0 0x80000>, /* GICR */
+		      <0 0x40440000 0 0x1000>;  /* GICC */
+		interrupts = <GIC_PPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		#interrupt-cells = <3>;
+		interrupt-controller;
+	};
+
+	soc0: bus at 10000000 {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges = <0x0 0x10000000 0x0 0x10000000 0x0 0x4000000>;
+	};
+
+	soc1: bus at 14000000 {
+		compatible = "simple-bus";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges = <0x0 0x14000000 0x0 0x14000000 0x2 0xec000000>;
+	};
+};
+
+#include "aspeed-g7-soc0.dtsi"
+#include "aspeed-g7-soc1.dtsi"
diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-soc0-pinctrl.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-g7-soc0-pinctrl.dtsi
new file mode 100644
index 000000000000..ed58ee41973b
--- /dev/null
+++ b/arch/arm64/boot/dts/aspeed/aspeed-g7-soc0-pinctrl.dtsi
@@ -0,0 +1,225 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+// Copyright 2025 ASPEED Corp.
+
+&pinctrl0 {
+	pinctrl_emmc_default: emmc-default-state {
+		function = "EMMC";
+		groups = "EMMCG1";
+	};
+	pinctrl_emmcg4_default: emmcg4-default-state {
+		function = "EMMC";
+		groups = "EMMCG4";
+	};
+	pinctrl_emmcg8_default: emmcg8-default-state {
+		function = "EMMC";
+		groups = "EMMCG8";
+	};
+	pinctrl_emmcwpn_default: emmcwpn-default-state {
+		function = "EMMC";
+		groups = "EMMCWPN";
+	};
+	pinctrl_emmccdn_default: emmccdn-default-state {
+		function = "EMMC";
+		groups = "EMMCCDN";
+	};
+	pinctrl_vb1_default: vb1-default-state {
+		function = "VB";
+		groups = "VB1";
+	};
+	pinctrl_vb0_default: vb0-default-state {
+		function = "VB";
+		groups = "VB0";
+	};
+	pinctrl_tsprstn_default: tsprstn-default-state {
+		function = "TSPRSTN";
+		groups = "TSPRSTN";
+	};
+	pinctrl_ufsclki_default: ufsclki-default-state {
+		function = "UFSCLKI";
+		groups = "UFSCLKI";
+	};
+	pinctrl_vgaddc_default: vgaddc-default-state {
+		function = "VGADDC";
+		groups = "VGADDC";
+	};
+	pinctrl_usb3axhd_default: usb3axhd-default-state {
+		function = "USB3AXHD";
+		groups = "USB3A";
+	};
+	pinctrl_usb3axhpd_default: usb3axhpd-default-state {
+		function = "USB3AXHPD";
+		groups = "USB3A";
+	};
+	pinctrl_usb3axh_default: usb3axh-default-state {
+		function = "USB3AXH";
+		groups = "USB3AAP";
+	};
+	pinctrl_usb3axhp_default: usb3axhp-default-state {
+		function = "USB3AXHP";
+		groups = "USB3AAP";
+	};
+	pinctrl_usb3axh2b_default: usb3axh2b-default-state {
+		function = "USB3AXH2B";
+		groups = "USB3ABP";
+	};
+	pinctrl_usb3axhp2b_default: usb3axhp2b-default-state {
+		function = "USB3AXHP2B";
+		groups = "USB3ABP";
+	};
+	pinctrl_usb2axhd1_default: usb2axhd1-default-state {
+		function = "USB2AXHD1";
+		groups = "USB2A";
+	};
+	pinctrl_usb2axhpd1_default: usb2axhpd1-default-state {
+		function = "USB2AXHPD1";
+		groups = "USB2A";
+	};
+	pinctrl_usb2ad1_default: usb2ad1-default-state {
+		function = "USB2AD1";
+		groups = "USB2ADAP";
+	};
+	pinctrl_usb2axh_default: usb2axh-default-state {
+		function = "USB2AXH";
+		groups = "USB2AAP";
+	};
+	pinctrl_usb2axhp_default: usb2axhp-default-state {
+		function = "USB2AXHP";
+		groups = "USB2AAP";
+	};
+	pinctrl_usb2axh2b_default: usb2axh2b-default-state {
+		function = "USB2AXH2B";
+		groups = "USB2ABP";
+	};
+	pinctrl_usb2axhp2b_default: usb2axhp2b-default-state {
+		function = "USB2AXHP2B";
+		groups = "USB2ABP";
+	};
+	pinctrl_usb2ahpd0_default: usb2ahpd0-default-state {
+		function = "USB2AHPD0";
+		groups = "USB2AH";
+	};
+	pinctrl_usb2ad0_default: usb2ad0-default-state {
+		function = "USB2AD0";
+		groups = "USB2AHAP";
+	};
+	pinctrl_usb2ah_default: usb2ah-default-state {
+		function = "USB2AH";
+		groups = "USB2AHAP";
+	};
+	pinctrl_usb2ahp_default: usb2ahp-default-state {
+		function = "USB2AHP";
+		groups = "USB2AHAP";
+	};
+	pinctrl_usb3bxhd_default: usb3bxhd-default-state {
+		function = "USB3BXHD";
+		groups = "USB3B";
+	};
+	pinctrl_usb3bxhpd_default: usb3bxhpd-default-state {
+		function = "USB3BXHPD";
+		groups = "USB3B";
+	};
+	pinctrl_usb3bxh_default: usb3bxh-default-state {
+		function = "USB3BXH";
+		groups = "USB3BBP";
+	};
+	pinctrl_usb3bxhp_default: usb3bxhp-default-state {
+		function = "USB3BXHP";
+		groups = "USB3BBP";
+	};
+	pinctrl_usb3bxh2a_default: usb3bxh2a-default-state {
+		function = "USB3BXH2A";
+		groups = "USB3BAP";
+	};
+	pinctrl_usb3bxhp2a_default: usb3bxhp2a-default-state {
+		function = "USB3BXHP2A";
+		groups = "USB3BAP";
+	};
+	pinctrl_usb2bxhd1_default: usb2bxhd1-default-state {
+		function = "USB2BXHD1";
+		groups = "USB2B";
+	};
+	pinctrl_usb2bxhpd1_default: usb2bxhpd1-default-state {
+		function = "USB2BXHPD1";
+		groups = "USB2B";
+	};
+	pinctrl_usb2bd1_default: usb2bd1-default-state {
+		function = "USB2BD1";
+		groups = "USB2BDBP";
+	};
+	pinctrl_usb2bxh_default: usb2bxh-default-state {
+		function = "USB2BXH";
+		groups = "USB2BBP";
+	};
+	pinctrl_usb2bxhp_default: usb2bxhp-default-state {
+		function = "USB2BXHP";
+		groups = "USB2BBP";
+	};
+	pinctrl_usb2bxh2a_default: usb2bxh2a-default-state {
+		function = "USB2BXH2A";
+		groups = "USB2BAP";
+	};
+	pinctrl_usb2bxhp2a_default: usb2bxhp2a-default-state {
+		function = "USB2BXHP2A";
+		groups = "USB2BAP";
+	};
+	pinctrl_usb2bhpd0_default: usb2bhpd0-default-state {
+		function = "USB2BHPD0";
+		groups = "USB2BH";
+	};
+	pinctrl_usb2bd0_default: usb2bd0-default-state {
+		function = "USB2BD0";
+		groups = "USB2BHBP";
+	};
+	pinctrl_usb2bh_default: usb2bh-default-state {
+		function = "USB2BH";
+		groups = "USB2BHBP";
+	};
+	pinctrl_usb2bhp_default: usb2bhp-default-state {
+		function = "USB2BHP";
+		groups = "USB2BHBP";
+	};
+	pinctrl_jtagm0_default: jtagm0-default-state {
+		function = "JTAGM0";
+		groups = "JTAG0";
+	};
+	pinctrl_jtag_psp_default: jtag-psp-default-state {
+		function = "JTAGPSP";
+		groups = "JTAG0";
+	};
+	pinctrl_jtag_ssp_default: jtag-ssp-default-state {
+		function = "JTAGSSP";
+		groups = "JTAG0";
+	};
+	pinctrl_jtag_tsp_default: jtag-tsp-default-state {
+		function = "JTAGTSP";
+		groups = "JTAG0";
+	};
+	pinctrl_jtag_ddr_default: jtag-ddr-default-state {
+		function = "JTAGDDR";
+		groups = "JTAG0";
+	};
+	pinctrl_jtag_usb3a_default: jtag-usb3a-default-state {
+		function = "JTAGUSB3A";
+		groups = "JTAG0";
+	};
+	pinctrl_jtag_usb3b_default: jtag-usb3b-default-state {
+		function = "JTAGUSB3B";
+		groups = "JTAG0";
+	};
+	pinctrl_jtag_pciea_default: jtag-pciea-default-state {
+		function = "JTAGPCIEA";
+		groups = "JTAG0";
+	};
+	pinctrl_jtag_pcieb_default: jtag-pcieb-default-state {
+		function = "JTAGPCIEB";
+		groups = "JTAG0";
+	};
+	pinctrl_pcierc0_perst_default: pcierc0-perst-default-state {
+		function = "PCIERC0PERST";
+		groups = "PCIERC0PERST";
+	};
+	pinctrl_pcierc1_perst_default: pcierc1-perst-default-state {
+		function = "PCIERC1PERST";
+		groups = "PCIERC1PERST";
+	};
+};
diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-soc0.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-g7-soc0.dtsi
new file mode 100644
index 000000000000..db42db2592e0
--- /dev/null
+++ b/arch/arm64/boot/dts/aspeed/aspeed-g7-soc0.dtsi
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Device Tree Source for AST27xx SoC Family Main Domain peripherals
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ */
+
+#include <dt-bindings/clock/aspeed,ast2700-scu.h>
+#include <dt-bindings/reset/aspeed,ast2700-scu.h>
+#include <dt-bindings/interrupt-controller/aspeed-scu-ic.h>
+
+&soc0 {
+	sram0: sram at 10000000 {
+		compatible = "mmio-sram";
+		reg = <0x0 0x10000000 0x0 0x20000>;
+		ranges = <0x0 0x0 0x10000000 0x20000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		soc0-sram at 0 {
+			reg = <0x0 0x20000>;
+			export;
+		};
+	};
+
+	vhuba1: usb-vhub at 12011000 {
+		compatible = "aspeed,ast2700-usb-vhub";
+		reg = <0x0 0x12011000 0x0 0x820>;
+		interrupts-extended = <&intc0 32>;
+		clocks = <&syscon0 SCU0_CLK_GATE_PORTAUSB2CLK>;
+		resets = <&syscon0 SCU0_RESET_PORTA_VHUB>;
+		aspeed,vhub-downstream-ports = <7>;
+		aspeed,vhub-generic-endpoints = <21>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2axhpd1_default>;
+		status = "disabled";
+	};
+
+	vhubb1: usb-vhub at 12021000 {
+		compatible = "aspeed,ast2700-usb-vhub";
+		reg = <0x0 0x12021000 0x0 0x820>;
+		interrupts-extended = <&intc0 36>;
+		clocks = <&syscon0 SCU0_CLK_GATE_PORTBUSB2CLK>;
+		resets = <&syscon0 SCU0_RESET_PORTB_VHUB>;
+		aspeed,vhub-downstream-ports = <7>;
+		aspeed,vhub-generic-endpoints = <21>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2bxhpd1_default>;
+		status = "disabled";
+	};
+
+	uhci0: usb at 12040000 {
+		compatible = "aspeed,ast2700-uhci", "generic-uhci";
+		reg = <0x0 0x12040000 0x0 0x100>;
+		interrupts-extended = <&intc0 10>;
+		#ports = <2>;
+		clocks = <&syscon0 SCU0_CLK_GATE_UHCICLK>;
+		resets = <&syscon0 SCU0_RESET_UHCI>;
+		status = "disabled";
+	};
+
+	vhuba0: usb-vhub at 12060000 {
+		compatible = "aspeed,ast2700-usb-vhub";
+		reg = <0x0 0x12060000 0x0 0x820>;
+		interrupts-extended = <&intc0 33>;
+		clocks = <&syscon0 SCU0_CLK_GATE_PORTAUSB2CLK>;
+		resets = <&syscon0 SCU0_RESET_PORTA_VHUB_EHCI>;
+		aspeed,vhub-downstream-ports = <7>;
+		aspeed,vhub-generic-endpoints = <21>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2ad0_default>;
+		status = "disabled";
+	};
+
+	ehci0: usb at 12061000 {
+		compatible = "aspeed,ast2700-ehci", "generic-ehci";
+		reg = <0x0 0x12061000 0x0 0x100>;
+		interrupts-extended = <&intc0 33>;
+		clocks = <&syscon0 SCU0_CLK_GATE_PORTAUSB2CLK>;
+		resets = <&syscon0 SCU0_RESET_PORTA_VHUB_EHCI>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2ah_default>;
+		status = "disabled";
+	};
+
+	vhubb0: usb-vhub at 12062000 {
+		compatible = "aspeed,ast2700-usb-vhub";
+		reg = <0x0 0x12062000 0x0 0x820>;
+		interrupts-extended = <&intc0 37>;
+		clocks = <&syscon0 SCU0_CLK_GATE_PORTBUSB2CLK>;
+		resets = <&syscon0 SCU0_RESET_PORTB_VHUB_EHCI>;
+		aspeed,vhub-downstream-ports = <7>;
+		aspeed,vhub-generic-endpoints = <21>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2bd0_default>;
+		status = "disabled";
+	};
+
+	ehci1: usb at 12063000 {
+		compatible = "aspeed,ast2700-ehci", "generic-ehci";
+		reg = <0x0 0x12063000 0x0 0x100>;
+		interrupts-extended = <&intc0 37>;
+		clocks = <&syscon0 SCU0_CLK_GATE_PORTBUSB2CLK>;
+		resets = <&syscon0 SCU0_RESET_PORTB_VHUB_EHCI>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2bh_default>;
+		status = "disabled";
+	};
+
+	emmc_controller: sdc at 12090000 {
+		compatible = "aspeed,ast2700-sd-controller", "aspeed,ast2600-sd-controller";
+		reg = <0 0x12090000 0 0x100>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0x0 0x12090000 0x10000>;
+		clocks = <&syscon0 SCU0_CLK_GATE_EMMCCLK>;
+		resets = <&syscon0 SCU0_RESET_EMMC>;
+		status = "disabled";
+
+		emmc: sdhci at 100 {
+			compatible = "aspeed,ast2700-sdhci", "aspeed,ast2600-sdhci";
+			reg = <0x100 0x100>;
+			sdhci,auto-cmd12;
+			interrupts-extended = <&intc0 15>;
+			clocks = <&syscon0 SCU0_CLK_GATE_EMMCCLK>;
+			status = "disabled";
+		};
+	};
+
+	intc0: interrupt-controller at 12100000 {
+		compatible = "aspeed,ast2700-intc0";
+		reg = <0x0 0x12100000 0x0 0x3c00>;
+		interrupt-controller;
+		interrupt-parent = <&gic>;
+		#interrupt-cells = <1>;
+		aspeed,interrupt-ranges =
+			<0 128 &gic GIC_SPI 0 IRQ_TYPE_LEVEL_HIGH>, /* linear range 1 to 1*/
+			<144 8 &gic GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>, /* sw int SSP */
+			<152 8 &gic GIC_SPI 152 IRQ_TYPE_LEVEL_HIGH>, /* sw int TSP */
+			<192 10 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>, /* M0-M9 intm */
+			<208 10 &gic GIC_SPI 208 IRQ_TYPE_LEVEL_HIGH>, /* M30-M39 intm */
+			<224 10 &gic GIC_SPI 224 IRQ_TYPE_LEVEL_HIGH>, /* M40-M49 intm */
+			<256 128 &ssp_nvic 0 0 >, /* linear to SSP */
+			<384 10 &ssp_nvic 160 0 >, /* cascaded to SSP via M10-M19 */
+			<400 8 &ssp_nvic 144 0 >, /* sw int PSP */
+			<408 8 &ssp_nvic 152 0 >, /* sw int TSP */
+			<426 128 &tsp_nvic 0 0 >, /* linear to TSP */
+			<554 10 &tsp_nvic 160 0 >, /* cascaded to TSP via M20-M29 */
+			<570 8 &tsp_nvic 144 0 >, /* sw int PSP */
+			<578 8 &tsp_nvic 152 0 >; /* sw int TSP */
+	};
+
+	syscon0: syscon at 12c02000 {
+		compatible = "aspeed,ast2700-scu0", "syscon", "simple-mfd";
+		reg = <0x0 0x12c02000 0x0 0x1000>;
+		ranges = <0x0 0x0 0x12c02000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+
+		silicon-id at 0 {
+			compatible = "aspeed,ast2700-silicon-id", "aspeed,silicon-id";
+			reg = <0x0 0x4>;
+		};
+
+		scu_ic0: interrupt-controller at 1d0 {
+			compatible = "aspeed,ast2700-scu-ic0";
+			reg = <0x1d0 0xc>;
+			interrupts-extended = <&intc0 97>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+		};
+
+		scu_ic1: interrupt-controller at 1e0 {
+			compatible = "aspeed,ast2700-scu-ic1";
+			reg = <0x1e0 0xc>;
+			interrupts-extended = <&intc0 98>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+		};
+
+		pinctrl0: pinctrl at 400 {
+			compatible = "aspeed,ast2700-soc0-pinctrl";
+			reg = <0x400 0x318>;
+		};
+	};
+
+	gpio0: gpio at 12c11000 {
+		#gpio-cells = <2>;
+		gpio-controller;
+		compatible = "aspeed,ast2700-gpio";
+		reg = <0x0 0x12c11000 0x0 0x1000>;
+		interrupts-extended = <&intc0 11>;
+		gpio-ranges = <&pinctrl0 0 0 12>;
+		ngpios = <12>;
+		clocks = <&syscon0 SCU0_CLK_APB>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	uart4: serial at 12c1a000 {
+		compatible = "ns16550a";
+		reg = <0x0 0x12c1a000 0x0 0x1000>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon0 SCU0_CLK_GATE_UART4CLK>;
+		interrupts-extended = <&intc0 8>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	mbox0: mbox at 12c1c200 {
+		compatible = "aspeed,ast2700-mailbox";
+		reg = <0x0 0x12c1c200 0x0 0x100>, <0x0 0x12c1c300 0x0 0x100>;
+		reg-names = "tx", "rx";
+		interrupts-extended = <&intc0 103>;
+		#mbox-cells = <1>;
+	};
+
+	mbox1: mbox at 12c1c600 {
+		compatible = "aspeed,ast2700-mailbox";
+		reg = <0x0 0x12c1c600 0x0 0x100>, <0x0 0x12c1c700 0x0 0x100>;
+		reg-names = "tx", "rx";
+		interrupts-extended = <&intc0 107>;
+		#mbox-cells = <1>;
+	};
+};
+
+#include "aspeed-g7-soc0-pinctrl.dtsi"
diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-soc1-pinctrl.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-g7-soc1-pinctrl.dtsi
new file mode 100644
index 000000000000..72d93323593d
--- /dev/null
+++ b/arch/arm64/boot/dts/aspeed/aspeed-g7-soc1-pinctrl.dtsi
@@ -0,0 +1,1113 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+// Copyright 2025 ASPEED Corp.
+
+&pinctrl1 {
+	pinctrl_sgpm0_default: sgpm0-default-state {
+		function = "SGPM0";
+		groups = "SGPM0";
+	};
+
+	pinctrl_dsgpm0_default: dsgpm0-default-state {
+		function = "SGPM0";
+		groups = "DSGPM0";
+	};
+
+	pinctrl_sgpm1_default: sgpm1-default-state {
+		function = "SGPM1";
+		groups = "SGPM1";
+	};
+
+	pinctrl_sgps_default: sgps-default-state {
+		function = "SGPS";
+		groups = "SGPS";
+	};
+
+	pinctrl_adc0_default: adc0-default-state {
+		function = "ADC0";
+		groups = "ADC0";
+	};
+
+	pinctrl_adc1_default: adc1-default-state {
+		function = "ADC1";
+		groups = "ADC1";
+	};
+
+	pinctrl_adc2_default: adc2-default-state {
+		function = "ADC2";
+		groups = "ADC2";
+	};
+
+	pinctrl_adc3_default: adc3-default-state {
+		function = "ADC3";
+		groups = "ADC3";
+	};
+
+	pinctrl_adc4_default: adc4-default-state {
+		function = "ADC4";
+		groups = "ADC4";
+	};
+
+	pinctrl_adc5_default: adc5-default-state {
+		function = "ADC5";
+		groups = "ADC5";
+	};
+
+	pinctrl_adc6_default: adc6-default-state {
+		function = "ADC6";
+		groups = "ADC6";
+	};
+
+	pinctrl_adc7_default: adc7-default-state {
+		function = "ADC7";
+		groups = "ADC7";
+	};
+
+	pinctrl_adc8_default: adc8-default-state {
+		function = "ADC8";
+		groups = "ADC8";
+	};
+
+	pinctrl_adc9_default: adc9-default-state {
+		function = "ADC9";
+		groups = "ADC9";
+	};
+
+	pinctrl_adc10_default: adc10-default-state {
+		function = "ADC10";
+		groups = "ADC10";
+	};
+
+	pinctrl_adc11_default: adc11-default-state {
+		function = "ADC11";
+		groups = "ADC11";
+	};
+
+	pinctrl_adc12_default: adc12-default-state {
+		function = "ADC12";
+		groups = "ADC12";
+	};
+
+	pinctrl_adc13_default: adc13-default-state {
+		function = "ADC13";
+		groups = "ADC13";
+	};
+
+	pinctrl_adc14_default: adc14-default-state {
+		function = "ADC14";
+		groups = "ADC14";
+	};
+
+	pinctrl_adc15_default: adc15-default-state {
+		function = "ADC15";
+		groups = "ADC15";
+	};
+
+	pinctrl_pwm0_default: pwm0-default-state {
+		function = "PWM0";
+		groups = "PWM0";
+	};
+
+	pinctrl_pwm1_default: pwm1-default-state {
+		function = "PWM1";
+		groups = "PWM1";
+	};
+
+	pinctrl_pwm2_default: pwm2-default-state {
+		function = "PWM2";
+		groups = "PWM2";
+	};
+
+	pinctrl_pwm3_default: pwm3-default-state {
+		function = "PWM3";
+		groups = "PWM3";
+	};
+
+	pinctrl_pwm4_default: pwm4-default-state {
+		function = "PWM4";
+		groups = "PWM4";
+	};
+
+	pinctrl_pwm5_default: pwm5-default-state {
+		function = "PWM5";
+		groups = "PWM5";
+	};
+
+	pinctrl_pwm6_default: pwm6-default-state {
+		function = "PWM6";
+		groups = "PWM6";
+	};
+
+	pinctrl_pwm7_default: pwm7-default-state {
+		function = "PWM7";
+		groups = "PWM7";
+	};
+
+	pinctrl_pwm8_default: pwm8-default-state {
+		function = "PWM8";
+		groups = "PWM8";
+	};
+
+	pinctrl_pwm9_default: pwm9-default-state {
+		function = "PWM9";
+		groups = "PWM9";
+	};
+
+	pinctrl_pwm10_default: pwm10-default-state {
+		function = "PWM10";
+		groups = "PWM10";
+	};
+
+	pinctrl_pwm11_default: pwm11-default-state {
+		function = "PWM11";
+		groups = "PWM11";
+	};
+
+	pinctrl_pwm12_default: pwm12-default-state {
+		function = "PWM12";
+		groups = "PWM12";
+	};
+
+	pinctrl_pwm13_default: pwm13-default-state {
+		function = "PWM13";
+		groups = "PWM13";
+	};
+
+	pinctrl_pwm14_default: pwm14-default-state {
+		function = "PWM14";
+		groups = "PWM14";
+	};
+
+	pinctrl_pwm15_default: pwm15-default-state {
+		function = "PWM15";
+		groups = "PWM15";
+	};
+
+	pinctrl_tach0_default: tach0-default-state {
+		function = "TACH0";
+		groups = "TACH0";
+	};
+
+	pinctrl_tach1_default: tach1-default-state {
+		function = "TACH1";
+		groups = "TACH1";
+	};
+
+	pinctrl_tach2_default: tach2-default-state {
+		function = "TACH2";
+		groups = "TACH2";
+	};
+
+	pinctrl_tach3_default: tach3-default-state {
+		function = "TACH3";
+		groups = "TACH3";
+	};
+
+	pinctrl_tach4_default: tach4-default-state {
+		function = "TACH4";
+		groups = "TACH4";
+	};
+
+	pinctrl_tach5_default: tach5-default-state {
+		function = "TACH5";
+		groups = "TACH5";
+	};
+
+	pinctrl_tach6_default: tach6-default-state {
+		function = "TACH6";
+		groups = "TACH6";
+	};
+
+	pinctrl_tach7_default: tach7-default-state {
+		function = "TACH7";
+		groups = "TACH7";
+	};
+
+	pinctrl_tach8_default: tach8-default-state {
+		function = "TACH8";
+		groups = "TACH8";
+	};
+
+	pinctrl_tach9_default: tach9-default-state {
+		function = "TACH9";
+		groups = "TACH9";
+	};
+
+	pinctrl_tach10_default: tach10-default-state {
+		function = "TACH10";
+		groups = "TACH10";
+	};
+
+	pinctrl_tach11_default: tach11-default-state {
+		function = "TACH11";
+		groups = "TACH11";
+	};
+
+	pinctrl_tach12_default: tach12-default-state {
+		function = "TACH12";
+		groups = "TACH12";
+	};
+
+	pinctrl_tach13_default: tach13-default-state {
+		function = "TACH13";
+		groups = "TACH13";
+	};
+
+	pinctrl_tach14_default: tach14-default-state {
+		function = "TACH14";
+		groups = "TACH14";
+	};
+
+	pinctrl_tach15_default: tach15-default-state {
+		function = "TACH15";
+		groups = "TACH15";
+	};
+
+	pinctrl_jtagm1_default: jtagm1-default-state {
+		function = "JTAGM1";
+		groups = "JTAGM1";
+	};
+
+	pinctrl_mdio0_default: mdio0-default-state {
+		function = "MDIO0";
+		groups = "MDIO0";
+	};
+
+	pinctrl_mdio1_default: mdio1-default-state {
+		function = "MDIO1";
+		groups = "MDIO1";
+	};
+
+	pinctrl_mdio2_default: mdio2-default-state {
+		function = "MDIO2";
+		groups = "MDIO2";
+	};
+
+	pinctrl_rgmii0_default: rgmii0-default-state {
+		function = "RGMII0";
+		groups = "RGMII0";
+	};
+
+	pinctrl_rgmii1_default: rgmii1-default-state {
+		function = "RGMII1";
+		groups = "RGMII1";
+	};
+
+	pinctrl_rmii0_default: rmii0-default-state {
+		function = "RMII0";
+		groups = "RMII0";
+	};
+
+	pinctrl_rmii0_rclko_default: rmii0-rclko-default-state {
+		function = "RMII0RCLKO";
+		groups = "RMII0RCLKO";
+	};
+
+	pinctrl_rmii1_default: rmii1-default-state {
+		function = "RMII1";
+		groups = "RMII1";
+	};
+
+	pinctrl_rmii1_rclko_default: rmii1-rclko-default-state {
+		function = "RMII1RCLKO";
+		groups = "RMII1RCLKO";
+	};
+
+	pinctrl_sgmii_default: sgmii-default-state {
+		function = "SGMII";
+		groups = "SGMII";
+	};
+
+	pinctrl_fwspi_quad_default: fwspi-quad-default-state {
+		function = "FWQSPI";
+		groups = "FWQSPI";
+	};
+
+	pinctrl_fsi0_default: fsi0-default-state {
+		function = "FSI0";
+		groups = "FSI0";
+	};
+
+	pinctrl_fsi1_default: fsi1-default-state {
+		function = "FSI1";
+		groups = "FSI1";
+	};
+
+	pinctrl_fsi2_default: fsi2-default-state {
+		function = "FSI2";
+		groups = "FSI2";
+	};
+
+	pinctrl_fsi3_default: fsi3-default-state {
+		function = "FSI3";
+		groups = "FSI3";
+	};
+
+	pinctrl_spi0_default: spi0-default-state {
+		function = "SPI0";
+		groups = "SPI0";
+	};
+
+	pinctrl_spi0_quad_default: spi0-quad-default-state {
+		function = "QSPI0";
+		groups = "QSPI0";
+	};
+
+	pinctrl_spi0_cs1_default: spi0-cs1-default-state {
+		function = "SPI0CS1";
+		groups = "SPI0CS1";
+	};
+
+	pinctrl_spi1_default: spi1-default-state {
+		function = "SPI1";
+		groups = "SPI1";
+	};
+
+	pinctrl_spi1_quad_default: spi1-quad-default-state {
+		function = "QSPI1";
+		groups = "QSPI1";
+	};
+
+	pinctrl_spi1_cs1_default: spi1-cs1-default-state {
+		function = "SPI1CS1";
+		groups = "SPI1CS1";
+	};
+
+	pinctrl_spi2_default: spi2-default-state {
+		function = "SPI2";
+		groups = "SPI2";
+	};
+
+	pinctrl_spi2_quad_default: spi2-quad-default-state {
+		function = "QSPI2";
+		groups = "QSPI2";
+	};
+
+	pinctrl_spi2_cs1_default: spi2-cs1-default-state {
+		function = "SPI2CS1";
+		groups = "SPI2CS1";
+	};
+
+	pinctrl_espi0_default: espi0-default-state {
+		function = "ESPI0";
+		groups = "ESPI0";
+	};
+
+	pinctrl_espi1_default: espi1-default-state {
+		function = "ESPI1";
+		groups = "ESPI1";
+	};
+
+	pinctrl_lpc0_default: lpc0-default-state {
+		function = "LPC0";
+		groups = "LPC0";
+	};
+
+	pinctrl_lpc1_default: lpc1-default-state {
+		function = "LPC1";
+		groups = "LPC1";
+	};
+
+	pinctrl_vpi_default: vpi-default-state {
+		function = "VPI";
+		groups = "VPI";
+	};
+
+	pinctrl_sd_default: sd-default-state {
+		function = "SD";
+		groups = "SD";
+	};
+
+	pinctrl_hvi3c0_default: hvi3c0-default-state {
+		function = "I3C0";
+		groups = "HVI3C0";
+	};
+
+	pinctrl_hvi3c1_default: hvi3c1-default-state {
+		function = "I3C1";
+		groups = "HVI3C1";
+	};
+
+	pinctrl_hvi3c2_default: hvi3c2-default-state {
+		function = "I3C2";
+		groups = "HVI3C2";
+	};
+
+	pinctrl_hvi3c3_default: hvi3c3-default-state {
+		function = "I3C3";
+		groups = "HVI3C3";
+	};
+
+	pinctrl_i3c4_default: i3c4-default-state {
+		function = "I3C4";
+		groups = "I3C4";
+	};
+
+	pinctrl_i3c5_default: i3c5-default-state {
+		function = "I3C5";
+		groups = "I3C5";
+	};
+
+	pinctrl_i3c6_default: i3c6-default-state {
+		function = "I3C6";
+		groups = "I3C6";
+	};
+
+	pinctrl_i3c7_default: i3c7-default-state {
+		function = "I3C7";
+		groups = "I3C7";
+	};
+
+	pinctrl_i3c8_default: i3c8-default-state {
+		function = "I3C8";
+		groups = "I3C8";
+	};
+
+	pinctrl_i3c9_default: i3c9-default-state {
+		function = "I3C9";
+		groups = "I3C9";
+	};
+
+	pinctrl_i3c10_default: i3c10-default-state {
+		function = "I3C10";
+		groups = "I3C10";
+	};
+
+	pinctrl_i3c11_default: i3c11-default-state {
+		function = "I3C11";
+		groups = "I3C11";
+	};
+
+	pinctrl_hvi3c12_default: hvi3c12-default-state {
+		function = "I3C12";
+		groups = "HVI3C12";
+	};
+
+	pinctrl_hvi3c13_default: hvi3c13-default-state {
+		function = "I3C13";
+		groups = "HVI3C13";
+	};
+
+	pinctrl_hvi3c14_default: hvi3c14-default-state {
+		function = "I3C14";
+		groups = "HVI3C14";
+	};
+
+	pinctrl_hvi3c15_default: hvi3c15-default-state {
+		function = "I3C15";
+		groups = "HVI3C15";
+	};
+
+	pinctrl_tach0_default: tach0-default-state {
+		function = "TACH0";
+		groups = "TACH0";
+	};
+
+	pinctrl_tach1_default: tach1-default-state {
+		function = "TACH1";
+		groups = "TACH1";
+	};
+
+	pinctrl_tach2_default: tach2-default-state {
+		function = "TACH2";
+		groups = "TACH2";
+	};
+
+	pinctrl_tach3_default: tach3-default-state {
+		function = "TACH3";
+		groups = "TACH3";
+	};
+
+	pinctrl_tach4_default: tach4-default-state {
+		function = "TACH4";
+		groups = "TACH4";
+	};
+
+	pinctrl_tach5_default: tach5-default-state {
+		function = "TACH5";
+		groups = "TACH5";
+	};
+
+	pinctrl_tach6_default: tach6-default-state {
+		function = "TACH6";
+		groups = "TACH6";
+	};
+
+	pinctrl_tach7_default: tach7-default-state {
+		function = "TACH7";
+		groups = "TACH7";
+	};
+
+	pinctrl_tach8_default: tach8-default-state {
+		function = "TACH8";
+		groups = "TACH8";
+	};
+
+	pinctrl_tach9_default: tach9-default-state {
+		function = "TACH9";
+		groups = "TACH9";
+	};
+
+	pinctrl_tach10_default: tach10-default-state {
+		function = "TACH10";
+		groups = "TACH10";
+	};
+
+	pinctrl_tach11_default: tach11-default-state {
+		function = "TACH11";
+		groups = "TACH11";
+	};
+
+	pinctrl_tach12_default: tach12-default-state {
+		function = "TACH12";
+		groups = "TACH12";
+	};
+
+	pinctrl_tach13_default: tach13-default-state {
+		function = "TACH13";
+		groups = "TACH13";
+	};
+
+	pinctrl_tach14_default: tach14-default-state {
+		function = "TACH14";
+		groups = "TACH14";
+	};
+
+	pinctrl_tach15_default: tach15-default-state {
+		function = "TACH15";
+		groups = "TACH15";
+	};
+
+	pinctrl_thru0_default: thru0-default-state {
+		function = "THRU0";
+		groups = "THRU0";
+	};
+
+	pinctrl_thru1_default: thru1-default-state {
+		function = "THRU1";
+		groups = "THRU1";
+	};
+
+	pinctrl_thru2_default: thru2-default-state {
+		function = "THRU2";
+		groups = "THRU2";
+	};
+
+	pinctrl_thru3_default: thru3-default-state {
+		function = "THRU3";
+		groups = "THRU3";
+	};
+
+	pinctrl_ncts5_default: ncts5-default-state {
+		function = "NCTS5";
+		groups = "NCTS5";
+	};
+
+	pinctrl_ndcd5_default: ndcd5-default-state {
+		function = "NDCD5";
+		groups = "NDCD5";
+	};
+
+	pinctrl_ndsr5_default: ndsr5-default-state {
+		function = "NDSR5";
+		groups = "NDSR5";
+	};
+
+	pinctrl_nri5_default: nri5-default-state {
+		function = "NRI5";
+		groups = "NRI5";
+	};
+
+	pinctrl_i2c0_default: i2c0-default-state {
+		function = "I2C0";
+		groups = "I2C0";
+	};
+
+	pinctrl_i2c1_default: i2c1-default-state {
+		function = "I2C1";
+		groups = "I2C1";
+	};
+
+	pinctrl_i2c2_default: i2c2-default-state {
+		function = "I2C2";
+		groups = "I2C2";
+	};
+
+	pinctrl_i2c3_default: i2c3-default-state {
+		function = "I2C3";
+		groups = "I2C3";
+	};
+
+	pinctrl_i2c4_default: i2c4-default-state {
+		function = "I2C4";
+		groups = "I2C4";
+	};
+
+	pinctrl_i2c5_default: i2c5-default-state {
+		function = "I2C5";
+		groups = "I2C5";
+	};
+
+	pinctrl_i2c6_default: i2c6-default-state {
+		function = "I2C6";
+		groups = "I2C6";
+	};
+
+	pinctrl_i2c7_default: i2c7-default-state {
+		function = "I2C7";
+		groups = "I2C7";
+	};
+
+	pinctrl_i2c8_default: i2c8-default-state {
+		function = "I2C8";
+		groups = "I2C8";
+	};
+
+	pinctrl_i2c9_default: i2c9-default-state {
+		function = "I2C9";
+		groups = "I2C9";
+	};
+
+	pinctrl_i2c10_default: i2c10-default-state {
+		function = "I2C10";
+		groups = "I2C10";
+	};
+
+	pinctrl_i2c11_default: i2c11-default-state {
+		function = "I2C11";
+		groups = "I2C11";
+	};
+
+	pinctrl_i2c12_default: i2c12-default-state {
+		function = "I2C12";
+		groups = "I2C12";
+	};
+
+	pinctrl_i2c13_default: i2c13-default-state {
+		function = "I2C13";
+		groups = "I2C13";
+	};
+
+	pinctrl_i2c14_default: i2c14-default-state {
+		function = "I2C14";
+		groups = "I2C14";
+	};
+
+	pinctrl_i2c15_default: i2c15-default-state {
+		function = "I2C15";
+		groups = "I2C15";
+	};
+
+	pinctrl_salt0_default: salt0-default-state {
+		function = "SALT0";
+		groups = "SALT0";
+	};
+
+	pinctrl_salt1_default: salt1-default-state {
+		function = "SALT1";
+		groups = "SALT1";
+	};
+
+	pinctrl_salt2_default: salt2-default-state {
+		function = "SALT2";
+		groups = "SALT2";
+	};
+
+	pinctrl_salt3_default: salt3-default-state {
+		function = "SALT3";
+		groups = "SALT3";
+	};
+
+	pinctrl_salt4_default: salt4-default-state {
+		function = "SALT4";
+		groups = "SALT4";
+	};
+
+	pinctrl_salt5_default: salt5-default-state {
+		function = "SALT5";
+		groups = "SALT5";
+	};
+
+	pinctrl_salt6_default: salt6-default-state {
+		function = "SALT6";
+		groups = "SALT6";
+	};
+
+	pinctrl_salt7_default: salt7-default-state {
+		function = "SALT7";
+		groups = "SALT7";
+	};
+
+	pinctrl_salt8_default: salt8-default-state {
+		function = "SALT8";
+		groups = "SALT8";
+	};
+
+	pinctrl_salt9_default: salt9-default-state {
+		function = "SALT9";
+		groups = "SALT9";
+	};
+
+	pinctrl_salt10_default: salt10-default-state {
+		function = "SALT10";
+		groups = "SALT10";
+	};
+
+	pinctrl_salt11_default: salt11-default-state {
+		function = "SALT11";
+		groups = "SALT11";
+	};
+
+	pinctrl_salt12_default: salt12-default-state {
+		function = "SALT12";
+		groups = "SALT12";
+	};
+
+	pinctrl_salt13_default: salt13-default-state {
+		function = "SALT13";
+		groups = "SALT13";
+	};
+
+	pinctrl_salt14_default: salt14-default-state {
+		function = "SALT14";
+		groups = "SALT14";
+	};
+
+	pinctrl_salt15_default: salt15-default-state {
+		function = "SALT15";
+		groups = "SALT15";
+	};
+
+	pinctrl_ltpipsi2c0_default: ltpipsi2c0-default-state {
+		function = "I2C0";
+		groups = "LTPI_PS_I2C0";
+	};
+
+	pinctrl_ltpipsi2c1_default: ltpipsi2c1-default-state {
+		function = "I2C1";
+		groups = "LTPI_PS_I2C1";
+	};
+
+	pinctrl_ltpipsi2c2_default: ltpipsi2c2-default-state {
+		function = "I2C2";
+		groups = "LTPI_PS_I2C2";
+	};
+
+	pinctrl_ltpipsi2c3_default: ltpipsi2c3-default-state {
+		function = "I2C3";
+		groups = "LTPI_PS_I2C3";
+	};
+
+	pinctrl_can_default: can-default-state {
+		function = "CANBUS";
+		groups = "CANBUS";
+	};
+
+	pinctrl_di2c0_default: di2c0-default-state {
+		function = "I2C0";
+		groups = "DI2C0";
+	};
+
+	pinctrl_di2c1_default: di2c1-default-state {
+		function = "I2C1";
+		groups = "DI2C1";
+	};
+
+	pinctrl_di2c2_default: di2c2-default-state {
+		function = "I2C2";
+		groups = "DI2C2";
+	};
+
+	pinctrl_di2c3_default: di2c3-default-state {
+		function = "I2C3";
+		groups = "DI2C3";
+	};
+	pinctrl_di2c8_default: di2c8-default-state {
+		function = "I2C8";
+		groups = "DI2C8";
+	};
+
+	pinctrl_di2c9_default: di2c9-default-state {
+		function = "I2C9";
+		groups = "DI2C9";
+	};
+
+	pinctrl_di2c10_default: di2c10-default-state {
+		function = "I2C10";
+		groups = "DI2C10";
+	};
+
+	pinctrl_di2c11_default: di2c11-default-state {
+		function = "I2C11";
+		groups = "DI2C11";
+	};
+
+	pinctrl_di2c12_default: di2c12-default-state {
+		function = "I2C12";
+		groups = "DI2C12";
+	};
+
+	pinctrl_di2c13_default: di2c13-default-state {
+		function = "I2C13";
+		groups = "DI2C13";
+	};
+
+	pinctrl_di2c14_default: di2c14-default-state {
+		function = "I2C14";
+		groups = "DI2C14";
+	};
+
+	pinctrl_di2c15_default: di2c15-default-state {
+		function = "I2C15";
+		groups = "DI2C15";
+	};
+
+	pinctrl_ncts0_default: ncts0-default-state {
+		function = "NCTS0";
+		groups = "NCTS0";
+	};
+
+	pinctrl_ndcd0_default: ndcd0-default-state {
+		function = "NDCD0";
+		groups = "NDCD0";
+	};
+
+	pinctrl_ndsr0_default: ndsr0-default-state {
+		function = "NDSR0";
+		groups = "NDSR0";
+	};
+
+	pinctrl_nri0_default: nri0-default-state {
+		function = "NRI0";
+		groups = "NRI0";
+	};
+
+	pinctrl_ndtr0_default: ndtr0-default-state {
+		function = "NDTR0";
+		groups = "NDTR0";
+	};
+
+	pinctrl_nrts0_default: nrts0-default-state {
+		function = "NRTS0";
+		groups = "NRTS0";
+	};
+
+	pinctrl_uart0_default: uart0-default-state {
+		function = "UART0";
+		groups = "UART0";
+	};
+
+	pinctrl_ncts1_default: ncts1-default-state {
+		function = "NCTS1";
+		groups = "NCTS1";
+	};
+
+	pinctrl_ndcd1_default: ndcd1-default-state {
+		function = "NDCD1";
+		groups = "NDCD1";
+	};
+
+	pinctrl_ndsr1_default: ndsr1-default-state {
+		function = "NDSR1";
+		groups = "NDSR1";
+	};
+
+	pinctrl_nri1_default: nri1-default-state {
+		function = "NRI1";
+		groups = "NRI1";
+	};
+
+	pinctrl_ndtr1_default: ndtr1-default-state {
+		function = "NDTR1";
+		groups = "NDTR1";
+	};
+
+	pinctrl_nrts1_default: nrts1-default-state {
+		function = "NRTS1";
+		groups = "NRTS1";
+	};
+
+	pinctrl_uart1_default: uart1-default-state {
+		function = "UART1";
+		groups = "UART1";
+	};
+
+	pinctrl_uart2_default: uart2-default-state {
+		function = "UART2";
+		groups = "UART2";
+	};
+
+	pinctrl_uart3_default: uart3-default-state {
+		function = "UART3";
+		groups = "UART3";
+	};
+
+	pinctrl_ncts5_default: ncts5-default-state {
+		function = "NCTS5";
+		groups = "NCTS5";
+	};
+
+	pinctrl_ndcd5_default: ndcd5-default-state {
+		function = "NDCD5";
+		groups = "NDCD5";
+	};
+
+	pinctrl_ndsr5_default: ndsr5-default-state {
+		function = "NDSR5";
+		groups = "NDSR5";
+	};
+
+	pinctrl_nri5_default: nri5-default-state {
+		function = "NRI5";
+		groups = "NRI5";
+	};
+
+	pinctrl_ndtr5_default: ndtr5-default-state {
+		function = "NDTR5";
+		groups = "NDTR5";
+	};
+
+	pinctrl_nrts5_default: nrts5-default-state {
+		function = "NRTS5";
+		groups = "NRTS5";
+	};
+
+	pinctrl_uart5_default: uart5-default-state {
+		function = "UART5";
+		groups = "UART5";
+	};
+
+	pinctrl_ncts6_default: ncts6-default-state {
+		function = "NCTS6";
+		groups = "NCTS6";
+	};
+
+	pinctrl_ndcd6_default: ndcd6-default-state {
+		function = "NDCD6";
+		groups = "NDCD6";
+	};
+
+	pinctrl_ndsr6_default: ndsr6-default-state {
+		function = "NDSR6";
+		groups = "NDSR6";
+	};
+
+	pinctrl_nri6_default: nri6-default-state {
+		function = "NRI6";
+		groups = "NRI6";
+	};
+
+	pinctrl_ndtr6_default: ndtr6-default-state {
+		function = "NDTR6";
+		groups = "NDTR6";
+	};
+
+	pinctrl_nrts6_default: nrts6-default-state {
+		function = "NRTS6";
+		groups = "NRTS6";
+	};
+
+	pinctrl_uart6_default: uart6-default-state {
+		function = "UART6";
+		groups = "UART6";
+	};
+
+	pinctrl_uart7_default: uart7-default-state {
+		function = "UART7";
+		groups = "UART7";
+	};
+
+	pinctrl_uart8_default: uart8-default-state {
+		function = "UART8";
+		groups = "UART8";
+	};
+
+	pinctrl_uart9_default: uart9-default-state {
+		function = "UART9";
+		groups = "UART9";
+	};
+
+	pinctrl_uart10_default: uart10-default-state {
+		function = "UART10";
+		groups = "UART10";
+	};
+
+	pinctrl_uart11_default: uart11-default-state {
+		function = "UART11";
+		groups = "UART11";
+	};
+
+	pinctrl_pcierc2_perst_default: pcierc2-perst-default-state {
+		function = "PCIERC";
+		groups = "PE2SGRSTN";
+	};
+
+	pinctrl_usb2cud_default: usb2cud-default-state {
+		function = "USB2C";
+		groups = "USB2CUD";
+	};
+
+	pinctrl_usb2cd_default: usb2cd-default-state {
+		function = "USB2C";
+		groups = "USB2CD";
+	};
+
+	pinctrl_usb2ch_default: usb2ch-default-state {
+		function = "USB2C";
+		groups = "USB2CH";
+	};
+
+	pinctrl_usb2cu_default: usb2cu-default-state {
+		function = "USB2C";
+		groups = "USB2CU";
+	};
+
+	pinctrl_usb2dd_default: usb2dd-default-state {
+		function = "USB2D";
+		groups = "USB2DD";
+	};
+
+	pinctrl_usb2dh_default: usb2dh-default-state {
+		function = "USB2D";
+		groups = "USB2DH";
+	};
+
+	pinctrl_wdtrst0n_default: wdtrst0n-default-state {
+		function = "WDTRST0N";
+		groups = "WDTRST0N";
+	};
+
+	pinctrl_wdtrst1n_default: wdtrst1n-default-state {
+		function = "WDTRST1N";
+		groups = "WDTRST1N";
+	};
+
+	pinctrl_wdtrst2n_default: wdtrst2n-default-state {
+		function = "WDTRST2N";
+		groups = "WDTRST2N";
+	};
+
+	pinctrl_wdtrst3n_default: wdtrst3n-default-state {
+		function = "WDTRST3N";
+		groups = "WDTRST3N";
+	};
+
+	pinctrl_wdtrst4n_default: wdtrst4n-default-state {
+		function = "WDTRST4N";
+		groups = "WDTRST4N";
+	};
+
+	pinctrl_wdtrst5n_default: wdtrst5n-default-state {
+		function = "WDTRST5N";
+		groups = "WDTRST5N";
+	};
+
+	pinctrl_wdtrst6n_default: wdtrst6n-default-state {
+		function = "WDTRST6N";
+		groups = "WDTRST6N";
+	};
+
+	pinctrl_wdtrst7n_default: wdtrst7n-default-state {
+		function = "WDTRST7N";
+		groups = "WDTRST7N";
+	};
+};
diff --git a/arch/arm64/boot/dts/aspeed/aspeed-g7-soc1.dtsi b/arch/arm64/boot/dts/aspeed/aspeed-g7-soc1.dtsi
new file mode 100644
index 000000000000..bc990f79e693
--- /dev/null
+++ b/arch/arm64/boot/dts/aspeed/aspeed-g7-soc1.dtsi
@@ -0,0 +1,557 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Device Tree Source for AST27xx SoC Family Main Domain peripherals
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ */
+
+#include <dt-bindings/clock/aspeed,ast2700-scu.h>
+#include <dt-bindings/reset/aspeed,ast2700-scu.h>
+#include <dt-bindings/interrupt-controller/aspeed-scu-ic.h>
+
+&soc1 {
+	fmc: spi at 14000000 {
+		reg = <0x0 0x14000000 0x0 0xc4>, <0x1 0x00000000 0x0 0x80000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "aspeed,ast2700-fmc";
+		status = "disabled";
+		clocks = <&syscon1 SCU1_CLK_AHB>;
+		interrupts-extended = <&intc1 121>;
+		num-cs = <3>;
+
+		flash at 0 {
+			reg = < 0 >;
+			compatible = "jedec,spi-nor";
+			spi-max-frequency = <50000000>;
+			spi-rx-bus-width = <2>;
+			status = "disabled";
+		};
+
+		flash at 1 {
+			reg = < 1 >;
+			compatible = "jedec,spi-nor";
+			spi-max-frequency = <50000000>;
+			spi-rx-bus-width = <2>;
+			status = "disabled";
+		};
+
+		flash at 2 {
+			reg = < 2 >;
+			compatible = "jedec,spi-nor";
+			spi-max-frequency = <50000000>;
+			spi-rx-bus-width = <2>;
+			status = "disabled";
+		};
+	};
+
+	spi0: spi at 14010000 {
+		reg = <0x0 0x14010000 0x0 0xc4>, <0x1 0x80000000 0x0 0x80000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "aspeed,ast2700-spi";
+		clocks = <&syscon1 SCU1_CLK_AHB>;
+		interrupts-extended = <&intc1 122>;
+		status = "disabled";
+		num-cs = <2>;
+
+		flash at 0 {
+			reg = < 0 >;
+			compatible = "jedec,spi-nor";
+			spi-max-frequency = <50000000>;
+			spi-rx-bus-width = <2>;
+			status = "disabled";
+		};
+
+		flash at 1 {
+			reg = < 1 >;
+			compatible = "jedec,spi-nor";
+			spi-max-frequency = <50000000>;
+			spi-rx-bus-width = <2>;
+			status = "disabled";
+		};
+	};
+
+	spi1: spi at 14020000 {
+		reg = <0x0 0x14020000 0x0 0xc4>, <0x2 0x00000000 0x0 0x80000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "aspeed,ast2700-spi";
+		clocks = <&syscon1 SCU1_CLK_AHB>;
+		interrupts-extended = <&intc1 123>;
+		status = "disabled";
+		num-cs = <2>;
+
+		flash at 0 {
+			reg = < 0 >;
+			compatible = "jedec,spi-nor";
+			spi-max-frequency = <50000000>;
+			spi-rx-bus-width = <2>;
+			status = "disabled";
+		};
+
+		flash at 1 {
+			reg = < 1 >;
+			compatible = "jedec,spi-nor";
+			spi-max-frequency = <50000000>;
+			spi-rx-bus-width = <2>;
+			status = "disabled";
+		};
+	};
+
+	spi2: spi at 14030000 {
+		reg = <0x0 0x14030000 0x0 0x1f0>, <0x2 0x80000000 0x0 0x80000000>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		compatible = "aspeed,ast2700-spi";
+		clocks = <&syscon1 SCU1_CLK_AHB>;
+		resets = <&syscon1 SCU1_RESET_SPI2>;
+		interrupts-extended = <&intc1 124>;
+		num-cs = <2>;
+		status = "disabled";
+	};
+
+	mdio0: mdio at 14040000 {
+		compatible = "aspeed,ast2700-mdio", "aspeed,ast2600-mdio";
+		reg = <0 0x14040000 0 0x8>;
+		resets = <&syscon1 SCU1_RESET_MII>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mdio0_default>;
+		status = "disabled";
+	};
+
+	mdio1: mdio at 14040008 {
+		compatible = "aspeed,ast2700-mdio", "aspeed,ast2600-mdio";
+		reg = <0 0x14040008 0 0x8>;
+		resets = <&syscon1 SCU1_RESET_MII>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mdio1_default>;
+		status = "disabled";
+	};
+
+	mdio2: mdio at 14040010 {
+		compatible = "aspeed,ast2700-mdio", "aspeed,ast2600-mdio";
+		reg = <0 0x14040010 0 0x8>;
+		resets = <&syscon1 SCU1_RESET_MII>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_mdio2_default>;
+		status = "disabled";
+	};
+
+	sdio_controller: sdc at 14080000 {
+		compatible = "aspeed,ast2700-sd-controller", "aspeed,ast2600-sd-controller";
+		reg = <0 0x14080000 0 0x100>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges = <0x0 0x0 0x14080000 0x10000>;
+		clocks = <&syscon1 SCU1_CLK_GATE_SDCLK>;
+		resets = <&syscon1 SCU1_RESET_SD>;
+		status = "disabled";
+
+		sdhci: sdhci at 100 {
+			compatible = "aspeed,ast2700-sdhci", "aspeed,ast2600-sdhci";
+			reg = <0x100 0x100>;
+			sdhci,auto-cmd12;
+			interrupts-extended = <&intc1 161>;
+			clocks = <&syscon1 SCU1_CLK_GATE_SDCLK>;
+			pinctrl-names = "default";
+			pinctrl-0 = <&pinctrl_sd_default>;
+			status = "disabled";
+		};
+	};
+
+	pwm_tach: pwm-tach-controller at 140c0000 {
+		compatible = "aspeed,ast2700-pwm-tach", "aspeed,ast2600-pwm-tach";
+		reg = <0x0 0x140c0000 0 0x100>;
+		clocks = <&syscon1 SCU1_CLK_AHB>;
+		resets = <&syscon1 SCU1_RESET_PWM>;
+		#pwm-cells = <3>;
+		status = "disabled";
+	};
+
+	uhci1: usb at 14110000 {
+		compatible = "aspeed,ast2700-uhci", "generic-uhci";
+		reg = <0x0 0x14110000 0x0 0x100>;
+		interrupts-extended = <&intc1 155>;
+		#ports = <2>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UHCICLK>;
+		resets = <&syscon1 SCU1_RESET_UHCI>;
+		status = "disabled";
+	};
+
+	vhubc: usb-vhub at 14120000 {
+		compatible = "aspeed,ast2700-usb-vhub";
+		reg = <0x0 0x14120000 0x0 0x820>;
+		interrupts-extended = <&intc1 156>;
+		clocks = <&syscon1 SCU1_CLK_GATE_PORTCUSB2CLK>;
+		resets = <&syscon1 SCU1_RESET_PORTC_VHUB_EHCI>;
+		aspeed,vhub-downstream-ports = <7>;
+		aspeed,vhub-generic-endpoints = <21>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2cd_default>;
+		status = "disabled";
+	};
+
+	ehci2: usb at 14121000 {
+		compatible = "aspeed,ast2700-ehci", "generic-ehci";
+		reg = <0x0 0x14121000 0x0 0x100>;
+		interrupts-extended = <&intc1 156>;
+		clocks = <&syscon1 SCU1_CLK_GATE_PORTCUSB2CLK>;
+		resets = <&syscon1 SCU1_RESET_PORTC_VHUB_EHCI>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2ch_default>;
+		status = "disabled";
+	};
+
+	vhubd: usb-vhub at 14122000 {
+		compatible = "aspeed,ast2700-usb-vhub";
+		reg = <0x0 0x14122000 0x0 0x820>;
+		interrupts-extended = <&intc1 157>;
+		clocks = <&syscon1 SCU1_CLK_GATE_PORTDUSB2CLK>;
+		resets = <&syscon1 SCU1_RESET_PORTD_VHUB_EHCI>;
+		aspeed,vhub-downstream-ports = <7>;
+		aspeed,vhub-generic-endpoints = <21>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2dd_default>;
+		status = "disabled";
+	};
+
+	ehci3: usb at 14123000 {
+		compatible = "aspeed,ast2700-ehci", "generic-ehci";
+		reg = <0x0 0x14123000 0x0 0x100>;
+		interrupts-extended = <&intc1 157>;
+		clocks = <&syscon1 SCU1_CLK_GATE_PORTDUSB2CLK>;
+		resets = <&syscon1 SCU1_RESET_PORTD_VHUB_EHCI>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_usb2dh_default>;
+		status = "disabled";
+	};
+
+	sram1: sram at 14b80000 {
+		compatible = "mmio-sram";
+		reg = <0x0 0x14b80000 0x0 0x40000>;
+		ranges = <0x0 0x0 0x14b80000 0x40000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		soc1-sram at 0 {
+			reg = <0x0 0x40000>;
+			export;
+		};
+	};
+
+	adc0: adc at 14c00000 {
+		compatible = "aspeed,ast2700-adc0";
+		reg = <0x0 0x14c00000 0 0x100>;
+		clocks = <&syscon1 SCU1_CLK_AHB>;
+		resets = <&syscon1 SCU1_RESET_ADC>;
+		interrupts-extended = <&intc1 80>;
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
+	adc1: adc at 14c00100 {
+		compatible = "aspeed,ast2700-adc1";
+		reg = <0x0 0x14c00100 0x0 0x100>;
+		clocks = <&syscon1 SCU1_CLK_AHB>;
+		resets = <&syscon1 SCU1_RESET_ADC>;
+		interrupts-extended = <&intc1 80>;
+		#io-channel-cells = <1>;
+		status = "disabled";
+	};
+
+	syscon1: syscon at 14c02000 {
+		compatible = "aspeed,ast2700-scu1", "syscon", "simple-mfd";
+		reg = <0x0 0x14c02000 0x0 0x1000>;
+		ranges = <0x0 0x0 0x14c02000 0x1000>;
+		#address-cells = <1>;
+		#size-cells = <1>;
+		#clock-cells = <1>;
+		#reset-cells = <1>;
+
+		scu_ic2: interrupt-controller at 100 {
+			compatible = "aspeed,ast2700-scu-ic2";
+			reg = <0x100 0x8>;
+			interrupts-extended = <&intc1 160>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+		};
+
+		scu_ic3: interrupt-controller at 108 {
+			compatible = "aspeed,ast2700-scu-ic3";
+			reg = <0x108 0x8>;
+			interrupts-extended = <&intc1 186>;
+			#interrupt-cells = <1>;
+			interrupt-controller;
+		};
+
+		pinctrl1: pinctrl at 400 {
+			compatible = "aspeed,ast2700-soc1-pinctrl";
+			reg = <0x400 0x2a0>;
+		};
+	};
+
+	gpio1: gpio at 14c0b000 {
+		#gpio-cells = <2>;
+		gpio-controller;
+		compatible = "aspeed,ast2700-gpio";
+		reg = <0x0 0x14c0b000 0x0 0x1000>;
+		interrupts-extended = <&intc1 82>;
+		gpio-ranges = <&pinctrl1 0 0 216>;
+		ngpios = <216>;
+		clocks = <&syscon1 SCU1_CLK_AHB>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+	};
+
+	sgpiom0: sgpiom at 14c0c000 {
+		#gpio-cells = <2>;
+		gpio-controller;
+		compatible = "aspeed,ast2700-sgpiom";
+		reg = <0x0 0x14c0c000 0x0 0x100>;
+		interrupts-extended = <&intc1 85>;
+		ngpios = <256>;
+		clocks = <&syscon1 SCU1_CLK_APB>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		bus-frequency = <12000000>;
+		status = "disabled";
+	};
+
+	sgpiom1: sgpiom at 14c0d000 {
+		#gpio-cells = <2>;
+		gpio-controller;
+		compatible = "aspeed,ast2700-sgpiom";
+		reg = <0x0 0x14c0d000 0x0 0x100>;
+		interrupts-extended = <&intc1 88>;
+		ngpios = <256>;
+		clocks = <&syscon1 SCU1_CLK_APB>;
+		interrupt-controller;
+		#interrupt-cells = <2>;
+		bus-frequency = <12000000>;
+		status = "disabled";
+	};
+
+	intc1: interrupt-controller at 14c18000 {
+		compatible = "aspeed,ast2700-intc1";
+		reg = <0 0x14c18000 0 0x400>;
+		interrupt-controller;
+		interrupt-parent = <&intc0>;
+		#interrupt-cells = <1>;
+		aspeed,interrupt-ranges =
+			<0 6 &intc0 480>,   /* M0  ~ M5  */
+			<10 6 &intc0 490>,   /* M10 ~ M15  */
+			<20 6 &intc0 500>,   /* M20 ~ M25  */
+			<30 6 &intc0 510>,   /* M30 ~ M35  */
+			<40 6 &intc0 520>,   /* M40 ~ M45  */
+			<50 1 &bootmcu_hlic 11>; /* only 1 pin to BootMCU */
+	};
+
+	uart0: serial at 14c33000 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33000 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART0CLK>;
+		interrupts-extended = <&intc1 135>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart1: serial at 14c33100 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33100 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART1CLK>;
+		interrupts-extended = <&intc1 136>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart2: serial at 14c33200 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33200 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART2CLK>;
+		interrupts-extended = <&intc1 137>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart3: serial at 14c33300 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33300 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART3CLK>;
+		interrupts-extended = <&intc1 138>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart5: serial at 14c33400 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33400 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART5CLK>;
+		interrupts-extended = <&intc1 139>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart6: serial at 14c33500 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33500 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART6CLK>;
+		interrupts-extended = <&intc1 140>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart7: serial at 14c33600 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33600 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART7CLK>;
+		interrupts-extended = <&intc1 141>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart8: serial at 14c33700 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33700 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART8CLK>;
+		interrupts-extended = <&intc1 142>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart9: serial at 14c33800 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33800 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART9CLK>;
+		interrupts-extended = <&intc1 143>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart10: serial at 14c33900 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33900 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART10CLK>;
+		interrupts-extended = <&intc1 144>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart11: serial at 14c33a00 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33a00 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART11CLK>;
+		interrupts-extended = <&intc1 145>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart12: serial at 14c33b00 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33b00 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_GATE_UART12CLK>;
+		interrupts-extended = <&intc1 146>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart13: serial at 14c33c00 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33c00 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_UART13>;
+		interrupts-extended = <&intc1 23>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	uart14: serial at 14c33d00 {
+		compatible = "ns16550a";
+		reg = <0x0 0x14c33d00 0x0 0x100>;
+		reg-shift = <2>;
+		reg-io-width = <4>;
+		clocks = <&syscon1 SCU1_CLK_UART14>;
+		interrupts-extended = <&intc1 55>;
+		no-loopback-test;
+		status = "disabled";
+	};
+
+	wdt0: watchdog at 14c37000 {
+		compatible = "aspeed,ast2700-wdt";
+		reg = <0x0 0x14c37000 0x0 0x80>;
+	};
+
+	wdt1: watchdog at 14c37080 {
+		compatible = "aspeed,ast2700-wdt";
+		reg = <0x0 0x14c37080 0x0 0x80>;
+	};
+
+	wdt2: watchdog at 14c37100 {
+		compatible = "aspeed,ast2700-wdt";
+		reg = <0x0 0x14c37100 0x0 0x80>;
+		status = "disabled";
+	};
+
+	wdt3: watchdog at 14c37180 {
+		compatible = "aspeed,ast2700-wdt";
+		reg = <0x0 0x14c37180 0x0 0x80>;
+		status = "disabled";
+	};
+
+	mbox2: mbox at 14c39200 {
+		compatible = "aspeed,ast2700-mailbox";
+		reg = <0x0 0x14c39200 0x0 0x100>, <0x0 0x14c39300 0x0 0x100>;
+		reg-names = "tx", "rx";
+		interrupts-extended = <&intc1 177>;
+		#mbox-cells = <1>;
+	};
+
+	fsim0: fsi at 21800000 {
+		compatible = "aspeed,ast2700-fsi-master";
+		reg = <0x0 0x21800000 0x0 0x94>;
+		interrupts-extended = <&intc1 166>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_fsi0_default>;
+		clocks = <&syscon1 SCU1_CLK_GATE_FSICLK>;
+		resets = <&syscon1 SCU1_RESET_FSI>;
+		status = "disabled";
+	};
+
+	fsim1: fsi at 23800000 {
+		compatible = "aspeed,ast2700-fsi-master";
+		reg = <0x0 0x23800000 0x0 0x94>;
+		interrupts-extended = <&intc1 167>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&pinctrl_fsi2_default>;
+		clocks = <&syscon1 SCU1_CLK_GATE_FSICLK>;
+		resets = <&syscon1 SCU1_RESET_FSI>;
+		status = "disabled";
+	};
+};
+
+#include "aspeed-g7-soc1-pinctrl.dtsi"
diff --git a/arch/arm64/boot/dts/aspeed/ast2700-evb.dts b/arch/arm64/boot/dts/aspeed/ast2700-evb.dts
new file mode 100644
index 000000000000..fe8f0b80fb2c
--- /dev/null
+++ b/arch/arm64/boot/dts/aspeed/ast2700-evb.dts
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-only OR MIT
+/*
+ * Device Tree Source AST2700 EVB
+ *
+ * Copyright (C) 2026 ASPEED Technology Inc.
+ */
+
+/dts-v1/;
+#include "aspeed-g7-a35.dtsi"
+
+/ {
+	model = "AST2700 EVB";
+	compatible = "aspeed,ast2700-evb", "aspeed,ast2700";
+
+	aliases {
+		serial0 = &uart12;	/* console port */
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	memory at 400000000 {
+		device_type = "memory";
+		reg = <0x4 0x00000000 0x0 0x40000000>;
+	};
+};
+
+&fmc {
+	status = "okay";
+	pinctrl-0 = <&pinctrl_fwspi_quad_default>;
+	pinctrl-names = "default";
+
+	flash at 0 {
+		status = "okay";
+		m25p,fast-read;
+		label = "bmc";
+		spi-max-frequency = <50000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+#include "aspeed-evb-flash-layout-128.dtsi"
+	};
+
+	flash at 1 {
+		status = "okay";
+		m25p,fast-read;
+		label = "fmc0:1";
+		spi-max-frequency = <50000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+	};
+
+	flash at 2 {
+		status = "disabled";
+		m25p,fast-read;
+		label = "fmc0:2";
+		spi-max-frequency = <50000000>;
+		spi-tx-bus-width = <4>;
+		spi-rx-bus-width = <4>;
+	};
+};
+
+&uart12 {
+	status = "okay";
+};

-- 
2.34.1



From ryan_chen at aspeedtech.com  Mon Jun  8 19:47:21 2026
From: ryan_chen at aspeedtech.com (Ryan Chen)
Date: Tue, 9 Jun 2026 10:47:21 +0800
Subject: [PATCH v9 4/4] arm64: configs: Update defconfig for AST2700
 platform support
In-Reply-To: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>
References: <20260609-upstream_ast2700-v9-0-f631752f0cb1@aspeedtech.com>
Message-ID: <20260609-upstream_ast2700-v9-4-f631752f0cb1@aspeedtech.com>

Enable options for ASPEED AST2700 SoC.

Signed-off-by: Ryan Chen <ryan_chen at aspeedtech.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at linaro.org>
---
 arch/arm64/configs/defconfig | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/configs/defconfig b/arch/arm64/configs/defconfig
index 909f3c188e75..4879939353f4 100644
--- a/arch/arm64/configs/defconfig
+++ b/arch/arm64/configs/defconfig
@@ -39,6 +39,7 @@ CONFIG_ARCH_SUNXI=y
 CONFIG_ARCH_ALPINE=y
 CONFIG_ARCH_APPLE=y
 CONFIG_ARCH_ARTPEC=y
+CONFIG_ARCH_ASPEED=y
 CONFIG_ARCH_AXIADO=y
 CONFIG_ARCH_BCM=y
 CONFIG_ARCH_BCM2835=y

-- 
2.34.1



From fustini at kernel.org  Mon Jun  8 20:26:04 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 8 Jun 2026 20:26:04 -0700
Subject: [PATCH 01/12] dt-bindings: clock: thead: add TH1520 MISC subsys
 clock controller
In-Reply-To: <20260507081710.4090814-2-zhengxingda@iscas.ac.cn>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
 <20260507081710.4090814-2-zhengxingda@iscas.ac.cn>
Message-ID: <aieHzC76oys5ejWT@thelio>

On Thu, May 07, 2026 at 04:16:59PM +0800, Icenowy Zheng wrote:
> TH1520 has a subsystem clock controller called MISC_SUBSYS in its
> manual, mainly controlling clocks for USB and MMC/SD in non-TEE
> environment.
> 
> Add device tree binding for it.
> 
> Signed-off-by: Icenowy Zheng <zhengxingda at iscas.ac.cn>
> ---
>  .../devicetree/bindings/clock/thead,th1520-clk-ap.yaml |  5 +++--
>  include/dt-bindings/clock/thead,th1520-clk-ap.h        | 10 ++++++++++
>  2 files changed, 13 insertions(+), 2 deletions(-)

Thanks for working on USB and sorry for the delay in reviewing this series.

Reviewed-by: Drew Fustini <fustini at kernel.org>



From fustini at kernel.org  Mon Jun  8 21:17:37 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 8 Jun 2026 21:17:37 -0700
Subject: [PATCH 00/12] Add TH1520 USB support
In-Reply-To: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
Message-ID: <aieT4WmWK9416M9E@thelio>

On Thu, May 07, 2026 at 04:16:58PM +0800, Icenowy Zheng wrote:
> This patchset adds support for T-Head TH1520's USB functionality, and
> enabled it on the Lichee Pi 4A board.
> 
> The first 3 patches add support for the MISC subsystem clock
> contrtoller, which contains some USB clocks.
> 
> The next 2 patches add support for the USB PHY of T-Head TH1520, which
> is a wrapped Synopsys USB3.0 FemtoPHY with a little integration quirk;
> the controller itself is a properly configured DWC3 controller with sane
> default register values set.
> 
> Then one patch adds the USB PHY and controller nodes to the TH1520 DTSI
> file.
> 
> The remaining half of this patchset dedicates to enablement of USB on
> TH1520, because of the onboard hub of that board -- its USB2 signals are
> behind a switch that needs to be toggled on, and Vbus supplies for both
> the hub itself and downstream ports are managed via I2C-expanded GPIOs
> (because the SoC does not have enough GPIO pins).

Hi, thanks for working on USB. I tried to apply it to next-20260601 and
several of the dts patches no longer apply cleanly. Could you rebase?

In the meantime, I'll apply to 7.1-rc7 for testing.

Thanks,
Drew


From uwu at icenowy.me  Mon Jun  8 22:10:41 2026
From: uwu at icenowy.me (Icenowy Zheng)
Date: Tue, 09 Jun 2026 13:10:41 +0800
Subject: [PATCH 00/12] Add TH1520 USB support
In-Reply-To: <aieT4WmWK9416M9E@thelio>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
	 <aieT4WmWK9416M9E@thelio>
Message-ID: <a8dc863b1692b4d327b4b9700dd56a4754120561.camel@icenowy.me>

? 2026-06-08?? 21:17 -0700?Drew Fustini???
> On Thu, May 07, 2026 at 04:16:58PM +0800, Icenowy Zheng wrote:
> > This patchset adds support for T-Head TH1520's USB functionality,
> > and
> > enabled it on the Lichee Pi 4A board.
> > 
> > The first 3 patches add support for the MISC subsystem clock
> > contrtoller, which contains some USB clocks.
> > 
> > The next 2 patches add support for the USB PHY of T-Head TH1520,
> > which
> > is a wrapped Synopsys USB3.0 FemtoPHY with a little integration
> > quirk;
> > the controller itself is a properly configured DWC3 controller with
> > sane
> > default register values set.
> > 
> > Then one patch adds the USB PHY and controller nodes to the TH1520
> > DTSI
> > file.
> > 
> > The remaining half of this patchset dedicates to enablement of USB
> > on
> > TH1520, because of the onboard hub of that board -- its USB2
> > signals are
> > behind a switch that needs to be toggled on, and Vbus supplies for
> > both
> > the hub itself and downstream ports are managed via I2C-expanded
> > GPIOs
> > (because the SoC does not have enough GPIO pins).
> 
> Hi, thanks for working on USB. I tried to apply it to next-20260601
> and
> several of the dts patches no longer apply cleanly. Could you rebase?

I think the reason is that one of the GPIO expansion chip is added to
the DT for enabling Wi-Fi.

I am not sure whether the next revision of this patchset will contain
all things, maybe I will split out at least the USB PHY part.

Thanks,
Icenowy

> 
> In the meantime, I'll apply to 7.1-rc7 for testing.
> 
> Thanks,
> Drew


From fustini at kernel.org  Mon Jun  8 22:14:59 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 8 Jun 2026 22:14:59 -0700
Subject: [PATCH 03/12] riscv: dts: thead: add device tree node for MISC
 clock controller
In-Reply-To: <20260507081710.4090814-4-zhengxingda@iscas.ac.cn>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
 <20260507081710.4090814-4-zhengxingda@iscas.ac.cn>
Message-ID: <aiehUzl-qZeZDjXP@thelio>

On Thu, May 07, 2026 at 04:17:01PM +0800, Icenowy Zheng wrote:
> The MISC_SUBSYS clock controller on TH1520 SoC is a clock controller
> mainly controlling USB-related clocks (which isn't utilized yet) and
> MMC/SD controllers' AHB bus clocks.
> 
> Add the device tree node for it along with the missing bus clock
> references for MMC/SD controllers.

Is there a functional reason to modify the mmc nodes in this series?

Thanks,
Drew


From dlan at kernel.org  Mon Jun  8 22:27:52 2026
From: dlan at kernel.org (Yixun Lan)
Date: Tue,  9 Jun 2026 05:27:52 +0000
Subject: [PATCH v2 0/4] riscv: spacemit: k3: some clock fixes related to PCIe
In-Reply-To: <20260511-06-pci-clk-fix-v2-0-c9a5e563bab3@kernel.org>
References: <20260511-06-pci-clk-fix-v2-0-c9a5e563bab3@kernel.org>
Message-ID: <178098282978.4045227.9791467212023885311.b4-ty@b4>


On Mon, 11 May 2026 02:59:08 +0000, Yixun Lan wrote:
> Here are some fixes for previous patch set in order to make PCIe work,
> Add PCIe DBI clock which was missing, Fix the parent clock, And correct
> the PCIe Clock CTRL register offset.

Applied, thanks!

[1/4] clk: spacemit: k3: Switch to pll2_d6 as parent for PCIe clock
      https://github.com/spacemit-com/linux/commit/d8a4cef90b1a4ae9196a5bfba683eb9a0c75acdc
[2/4] clk: spacemit: k3: Fix PCIe clock register offset
      https://github.com/spacemit-com/linux/commit/2f20c859a82a291483a8b3f01cbfbb1642782a14
[3/4] dt-bindings: soc: spacemit: k3: Add PCIe DBI clock IDs
      https://github.com/spacemit-com/linux/commit/7a2db70a3196717bfb01415b6dde1f90d4291ab1
[4/4] clk: spacemit: k3: Add PCIe DBI clock
      https://github.com/spacemit-com/linux/commit/a37c75d7b5bb7f3344b0e639b313ac5ace6244ff

Best regards,
-- 
Yixun Lan <dlan at kernel.org>


From dlan at kernel.org  Mon Jun  8 22:28:09 2026
From: dlan at kernel.org (Yixun Lan)
Date: Tue,  9 Jun 2026 05:28:09 +0000
Subject: [GIT PULL] clk: spacemit: Updates for v7.2
Message-ID: <20260609052422-KYC4837748@kernel.org>

From: Yixun Lan <dlan at gentoo.org>

Hi Stephen,

   Please pull SpacemiT's clock changes for v7.2
All clock changes are related to PCIe for K3 SoC.
   Hope this isn't too late..

Yixun Lan

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  https://github.com/spacemit-com/linux spacemit-clk-for-7.2-1

for you to fetch changes up to a37c75d7b5bb7f3344b0e639b313ac5ace6244ff:

  clk: spacemit: k3: Add PCIe DBI clock (2026-06-02 07:16:59 +0000)

----------------------------------------------------------------
RISC-V SpacemiT clock changes for 7.2

- Switch parent clock of PCIe
- Fix PCIe clock register offset
- Add PCIe DBI clock

----------------------------------------------------------------
Yixun Lan (4):
      clk: spacemit: k3: Switch to pll2_d6 as parent for PCIe clock
      clk: spacemit: k3: Fix PCIe clock register offset
      dt-bindings: soc: spacemit: k3: Add PCIe DBI clock IDs
      clk: spacemit: k3: Add PCIe DBI clock

 drivers/clk/spacemit/ccu-k3.c                  | 30 +++++++++++++++++---------
 include/dt-bindings/clock/spacemit,k3-clocks.h |  5 +++++
 include/soc/spacemit/k3-syscon.h               |  4 ++--
 3 files changed, 27 insertions(+), 12 deletions(-)


From uwu at icenowy.me  Mon Jun  8 22:35:11 2026
From: uwu at icenowy.me (Icenowy Zheng)
Date: Tue, 09 Jun 2026 13:35:11 +0800
Subject: [PATCH 03/12] riscv: dts: thead: add device tree node for MISC
 clock controller
In-Reply-To: <aiehUzl-qZeZDjXP@thelio>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
	 <20260507081710.4090814-4-zhengxingda@iscas.ac.cn>
	 <aiehUzl-qZeZDjXP@thelio>
Message-ID: <67790d90737c13127100510020262d6921810e34.camel@icenowy.me>

? 2026-06-08?? 22:14 -0700?Drew Fustini???
> On Thu, May 07, 2026 at 04:17:01PM +0800, Icenowy Zheng wrote:
> > The MISC_SUBSYS clock controller on TH1520 SoC is a clock
> > controller
> > mainly controlling USB-related clocks (which isn't utilized yet)
> > and
> > MMC/SD controllers' AHB bus clocks.
> > 
> > Add the device tree node for it along with the missing bus clock
> > references for MMC/SD controllers.
> 
> Is there a functional reason to modify the mmc nodes in this series?

When the clock isn't referenced, Linux will disable it unless
`clk_ignore_unused` parameter is passed.

Thanks,
Icenowy

> 
> Thanks,
> Drew


From inochiama at gmail.com  Mon Jun  8 22:37:56 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Tue, 9 Jun 2026 13:37:56 +0800
Subject: [PATCH] riscv: dts: spacemit: k3-pico-itx: Fix non-functional
 ethernet TX timing
In-Reply-To: <20260608182358.170489-1-kernel@rembrandt.dev>
References: <20260608182358.170489-1-kernel@rembrandt.dev>
Message-ID: <aiemGajqcQeY9avz@inochi.infowork>

On Mon, Jun 08, 2026 at 08:23:58PM +0200, Andrew Rembrandt wrote:
> The "rgmii-id" PHY mode applies a symmetric 2ns internal delay in the
> PHY. On the Pico-ITX board this leaves insufficient TX timing margin and
> no ethernet traffic passes.
> 
> Add a 400ps MAC-side TX internal delay on top of the PHY's delay to
> correct the TX clock/data skew. The value follows the vendor fork's
> asymmetric tuning (tx-phase 73 x 33.3ps - 2000ps ID ~= 400ps); the
> driver rounds tx-internal-delay-ps to the nearest supported step.
> 
> This builds on commit 3ea695eb111f ("dts: riscv: spacemit: k3: Fix I/O
> power settings"), which fixed the GMAC0 1.8V/3.3V I/O switch
> 
> Tested on Pico-ITX hardware with iperf3: 60s TCP each direction and 60s
> UDP, all at 1Gbps with no TX/RX errors on the interface.
> 
> Fixes: 74657a376960 ("riscv: dts: spacemit: Add ethernet device for K3")
> Signed-off-by: Andrew Rembrandt <kernel at rembrandt.dev>
> ---
>  arch/riscv/boot/dts/spacemit/k3-pico-itx.dts | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts b/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
> index b89c1521e664..59aecaa2d32a 100644
> --- a/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
> +++ b/arch/riscv/boot/dts/spacemit/k3-pico-itx.dts
> @@ -186,6 +186,7 @@ &eth0 {
>  	pinctrl-names = "default";
>  	pinctrl-0 = <&gmac0_rgmii_0_cfg>, <&gmac0_phy_0_cfg>;
>  	phy-mode = "rgmii-id";
> +	tx-internal-delay-ps = <400>;
>  	phy-handle = <&phy0>;
>  	status = "okay";
>  

You should set tx-internal-delay-ps of the phy instead of
the controller. This is a phy in "rgmii-id" mode.

Regards,
Inochi


From fustini at kernel.org  Mon Jun  8 23:00:21 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 8 Jun 2026 23:00:21 -0700
Subject: [PATCH 02/12] clk: thead: th1520-ap: add support for MISC subsys
 clocks
In-Reply-To: <20260507081710.4090814-3-zhengxingda@iscas.ac.cn>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
 <20260507081710.4090814-3-zhengxingda@iscas.ac.cn>
Message-ID: <aier9XppLeCkJydw@thelio>

On Thu, May 07, 2026 at 04:17:00PM +0800, Icenowy Zheng wrote:
> The TH1520 SoC contains a MISC_SUBSYS clock controller, which allows
> controlling of USB related clocks and MMC/SD controller AHB bus clocks.
> 
> Add support for this clock controller, in order to enable USB support.
> 
> Signed-off-by: Icenowy Zheng <zhengxingda at iscas.ac.cn>
> ---
>  drivers/clk/thead/clk-th1520-ap.c | 64 +++++++++++++++++++++++++++++++
>  1 file changed, 64 insertions(+)
> 
> diff --git a/drivers/clk/thead/clk-th1520-ap.c b/drivers/clk/thead/clk-th1520-ap.c
> index 3a6847f1c950f..24f785f0b329a 100644
> --- a/drivers/clk/thead/clk-th1520-ap.c
> +++ b/drivers/clk/thead/clk-th1520-ap.c
[...]
> @@ -1609,6 +1663,12 @@ static int th1520_clk_probe(struct platform_device *pdev)
>  			return ret;
>  	}
>  
> +	if (plat_data == &th1520_ap_platdata) {
> +		ret = devm_clk_hw_register(dev, &usb_suspend_div_clk.hw);
> +		if (ret)
> +			return ret;
> +	}

Should usb_suspend_div_clk.hw instead be registered under
'if (plat_data == &th1520_ap_platdata)'?

Thanks,
Drew


From atish.patra at linux.dev  Mon Jun  8 23:01:14 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:14 -0700
Subject: [PATCH v6 00/21] Add Counter delegation ISA extension support
Message-ID: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>

This series adds the counter delegation extension support. It is based on
very early PoC work done by Kevin Xue and mostly rewritten after that.
The counter delegation ISA extension(Smcdeleg/Ssccfg) actually depends
on multiple ISA extensions.

1. S[m|s]csrind : The indirect CSR extension[1] which defines additional
   5 ([M|S|VS]IREG2-[M|S|VS]IREG6) register to address size limitation of
   RISC-V CSR address space.
2. Smstateen: The stateen bit[60] controls the access to the registers
   indirectly via the above indirect registers.
3. Smcdeleg/Ssccfg: The counter delegation extensions[2]

The counter delegation extension allows Supervisor mode to program the
hpmevent and hpmcounters directly without needing the assistance from the
M-mode via SBI calls. This results in a faster perf profiling and very
few traps. This extension also introduces a scountinhibit CSR which allows
to stop/start any counter directly from the S-mode. As the counter
delegation extension potentially can have more than 100 CSRs, the specification
leverages the indirect CSR extension to save the precious CSR address range.

Due to the dependency of these extensions, the following extensions must be
enabled in qemu to use the counter delegation feature in S-mode.

"smstateen=true,sscofpmf=true,ssccfg=true,smcdeleg=true,smcsrind=true,sscsrind=true"
or Virt machine users can just "max" cpu instead.

When we access the counters directly in S-mode, we also need to solve the
following problems.

1. Event to counter mapping
2. Event encoding discovery

The RISC-V ISA doesn't define any standard either for event encoding or the
event to counter mapping rules. Until now, the SBI PMU implementation relies
on device tree binding[3] to discover the event to counter mapping in RISC-V
platform in the firmware. The SBI PMU specification[4] defines event encoding
for standard perf events as well. Thus, the kernel can query the appropriate
counter for an given event from the firmware.

However, the kernel doesn't need any firmware interaction for hardware
counters if counter delegation is available in the hardware. Thus, the driver
needs to discover the above mappings/encodings by itself without any assistance
from firmware.

Solution to Problem #1:
This patch series solves the above problem #1 by extending the perf tool in a
way so that event json file can specify the counter constraints of each event
and that can be passed to the driver to choose the best counter for a given
event.

This series introduces a RISC-V specific event field in "CounterIDMask" in
event_fields that describes a bitmask of counters supported for a specific eventi.
This is the similar approach for few other existing properties in the event_fields
which were used by single architecture as well. The counter constraint bitmap is
passed to the perf driver via newly introduced "counterid_mask" property set in "config2".

The platform vendor have these three ways to encode/use the platform specific
events.

1. Directly in driver with appropriate constraints (discouraged due to bloating
of the driver)
2. Encode in Json with with CounterIDMask field (preferred as it is contained
within platform specific json file)
3. Directly pass counterid_mask at while invoking perf 
cpu/event=<code>,counterid_mask=<mask>/

The last two patches show cases these use cases and not intended for merging.

Solution to problem #2:

The event encoding can come from the json or commandline as well.

The Qemu patches are available in upstream now.

The Linux kernel patches can be found here:
https://github.com/atishp04/linux/tree/b4/counter_delegation_v6

[1] https://github.com/riscv/riscv-indirect-csr-access
[2] https://github.com/riscv/riscv-smcdeleg-ssccfg
[3] https://www.kernel.org/doc/Documentation/devicetree/bindings/perf/riscv%2Cpmu.yaml
[4] https://github.com/riscv-non-isa/riscv-sbi-doc/blob/master/src/ext-pmu.adoc

To: Paul Walmsley <pjw at kernel.org>
To: Rob Herring <robh at kernel.org>
To: Krzysztof Kozlowski <krzk+dt at kernel.org>
To: Will Deacon <will at kernel.org>
To: Mark Rutland <mark.rutland at arm.com>
To: Atish Patra <atish.patra at linux.dev>
To: Anup Patel <anup at brainfault.org>
To: Arnaldo Carvalho de Melo <acme at kernel.org>
To: Namhyung Kim <namhyung at kernel.org>
To: Jiri Olsa <jolsa at kernel.org>
To: Ian Rogers <irogers at google.com>
To: James Clark <james.clark at linaro.org>
Cc: linux-riscv at lists.infradead.org
Cc: linux-kernel at vger.kernel.org
Cc: Conor Dooley <conor at kernel.org>
Cc: devicetree at vger.kernel.org
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-perf-users at vger.kernel.org

Signed-off-by: Atish Patra <atishp at meta.com>

Changes in v6:
- Reverted the file name changes as suggested by Will. Now pmu-sbi.c will continue
  to support both counter delegation and SBI PMU with different function prefixes.
- No longer depends up old upstream patch for reusing the Counter property to
  encode event to counter mapping property. It directly uses additional field in
  json event fields similar to other architectures.
- Added few test patches (not intended for upstreaming) to show case different
  possibilities of providing mapping/event encodings.
- Fixed review comments and miscellenous minor typos/fixes on v5
- Rebased on top of v7.1-rc6

Changes in v5:
- Fixed dt_binding_check errors.
- Added the ISA extension dependancy for counter delegation extensions.
- Replaced the boolean variables with static key conditional check required at boot time.
- Miscellaneous minor code restructuring.
- Link to v4: https://lore.kernel.org/r/20250205-counter_delegation-v4-0-835cfa88e3b1 at rivosinc.com

Changes in v4:
- Added ISA dependencies as per dt schema instead of description.
- Fixed few compilation issues due to patch reordering in v3.
- Link to v3: https://lore.kernel.org/r/20250127-counter_delegation-v3-0-64894d7e16d5 at rivosinc.com

Changes in v3:
- Fixed the dtb binding check failures.
- Inlcuded the fix reported by Rajnesh Kanwal for guest counter overflow.
- Rearranged the overflow handling more efficiently for better modularity.
- Link to v2: https://lore.kernel.org/r/20250114-counter_delegation-v2-0-8ba74cdb851b at rivosinc.com

Changes in v2:
- Dropped architecture specific overrides for event encoding.
- Dropped hwprobe bits.
- Added a vendor specific event encoding table to support vendor specific event
  encoding and counter mapping.
- Fixed few bugs and cleanup.
- Link to v1: https://lore.kernel.org/r/20240217005738.3744121-1-atishp at rivosinc.com

---
Atish Patra (18):
      RISC-V: Add Sxcsrind ISA extension definition and parsing
      dt-bindings: riscv: add Sxcsrind ISA extension description
      RISC-V: Define indirect CSR access helpers
      RISC-V: Add Smcntrpmf extension parsing
      dt-bindings: riscv: add Smcntrpmf ISA extension description
      RISC-V: Add Ssccfg/Smcdeleg ISA extension definition and parsing
      dt-bindings: riscv: add Counter delegation ISA extensions description
      RISC-V: perf: Restructure the SBI PMU code
      RISC-V: perf: Modify the counter discovery mechanism
      RISC-V: perf: Add a mechanism to defined legacy event encoding
      RISC-V: perf: Implement supervisor counter delegation support
      RISC-V: perf: Use config2/vendor table for event to counter mapping
      RISC-V: perf: Add legacy event encodings via sysfs
      RISC-V: perf: Add Qemu virt machine events
      tools/perf: Support event code for arch standard events
      tools/perf: Add RISC-V CounterIDMask event field
      TEST(do-not-upstream): fake qemu-virt PMU events for cdeleg counter-mask testing
      TEST(do-not-upstream): fake qemu vendor JSON + mapfile entry for CounterIDMask path

Charlie Jenkins (1):
      RISC-V: perf: Skip PMU SBI extension when not implemented

Kaiwen Xue (2):
      RISC-V: Add Sxcsrind ISA extension CSR definitions
      RISC-V: Add Sscfg extension CSR definition

 .../devicetree/bindings/riscv/extensions.yaml      |   67 ++
 arch/riscv/include/asm/csr.h                       |   57 ++
 arch/riscv/include/asm/csr_ind.h                   |   44 +
 arch/riscv/include/asm/hwcap.h                     |    7 +
 arch/riscv/include/asm/vendorid_list.h             |    4 +
 arch/riscv/kernel/cpufeature.c                     |   27 +
 drivers/perf/Kconfig                               |   14 +-
 drivers/perf/riscv_pmu_sbi.c                       | 1044 ++++++++++++++++----
 include/linux/perf/riscv_pmu.h                     |   18 +
 .../perf/pmu-events/arch/riscv/arch-standard.json  |   10 +
 tools/perf/pmu-events/arch/riscv/mapfile.csv       |    1 +
 .../pmu-events/arch/riscv/qemu/virt/events.json    |   26 +
 tools/perf/pmu-events/jevents.py                   |    7 +-
 13 files changed, 1124 insertions(+), 202 deletions(-)
---
base-commit: ba3e43a9e601636f5edb54e259a74f96ca3b8fd8
change-id: 20240715-counter_delegation-628a32f8c9cc

Best regards,
-- 
Atish Patra <atishp at meta.com>



From atish.patra at linux.dev  Mon Jun  8 23:01:15 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:15 -0700
Subject: [PATCH v6 01/21] RISC-V: Add Sxcsrind ISA extension CSR
 definitions
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-1-285b72ed65a9@meta.com>

From: Kaiwen Xue <kaiwenx at rivosinc.com>

This adds definitions of new CSRs and bits defined in Sxcsrind ISA
extension. These CSR enables indirect accesses mechanism to access
any CSRs in M-, S-, and VS-mode. The range of the select values
and ireg will be define by the ISA extension using Sxcsrind extension.

Signed-off-by: Kaiwen Xue <kaiwenx at rivosinc.com>
Reviewed-by: Cl?ment L?ger <cleger at rivosinc.com>
Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 arch/riscv/include/asm/csr.h | 30 ++++++++++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 31b8988f4488..b4551a6cf7cb 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -347,6 +347,12 @@
 /* Supervisor-Level Window to Indirectly Accessed Registers (AIA) */
 #define CSR_SISELECT		0x150
 #define CSR_SIREG		0x151
+/* Supervisor-Level Window to Indirectly Accessed Registers (Sxcsrind) */
+#define CSR_SIREG2		0x152
+#define CSR_SIREG3		0x153
+#define CSR_SIREG4		0x155
+#define CSR_SIREG5		0x156
+#define CSR_SIREG6		0x157
 
 /* Supervisor-Level Interrupts (AIA) */
 #define CSR_STOPEI		0x15c
@@ -394,6 +400,14 @@
 /* VS-Level Window to Indirectly Accessed Registers (H-extension with AIA) */
 #define CSR_VSISELECT		0x250
 #define CSR_VSIREG		0x251
+/*
+ * VS-Level Window to Indirectly Accessed Registers (H-extension with Sxcsrind)
+ */
+#define CSR_VSIREG2		0x252
+#define CSR_VSIREG3		0x253
+#define CSR_VSIREG4		0x255
+#define CSR_VSIREG5		0x256
+#define CSR_VSIREG6		0x257
 
 /* VS-Level Interrupts (H-extension with AIA) */
 #define CSR_VSTOPEI		0x25c
@@ -436,6 +450,12 @@
 /* Machine-Level Window to Indirectly Accessed Registers (AIA) */
 #define CSR_MISELECT		0x350
 #define CSR_MIREG		0x351
+/* Machine-Level Window to Indirectly Accessed Registers (Sxcsrind) */
+#define CSR_MIREG2		0x352
+#define CSR_MIREG3		0x353
+#define CSR_MIREG4		0x355
+#define CSR_MIREG5		0x356
+#define CSR_MIREG6		0x357
 
 /* Machine-Level Interrupts (AIA) */
 #define CSR_MTOPEI		0x35c
@@ -498,6 +518,11 @@
 # define CSR_IEH		CSR_MIEH
 # define CSR_ISELECT	CSR_MISELECT
 # define CSR_IREG	CSR_MIREG
+# define CSR_IREG2	CSR_MIREG2
+# define CSR_IREG3	CSR_MIREG3
+# define CSR_IREG4	CSR_MIREG4
+# define CSR_IREG5	CSR_MIREG5
+# define CSR_IREG6	CSR_MIREG6
 # define CSR_IPH		CSR_MIPH
 # define CSR_TOPEI	CSR_MTOPEI
 # define CSR_TOPI	CSR_MTOPI
@@ -523,6 +548,11 @@
 # define CSR_IEH		CSR_SIEH
 # define CSR_ISELECT	CSR_SISELECT
 # define CSR_IREG	CSR_SIREG
+# define CSR_IREG2	CSR_SIREG2
+# define CSR_IREG3	CSR_SIREG3
+# define CSR_IREG4	CSR_SIREG4
+# define CSR_IREG5	CSR_SIREG5
+# define CSR_IREG6	CSR_SIREG6
 # define CSR_IPH		CSR_SIPH
 # define CSR_TOPEI	CSR_STOPEI
 # define CSR_TOPI	CSR_STOPI

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:16 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:16 -0700
Subject: [PATCH v6 02/21] RISC-V: Add Sxcsrind ISA extension definition and
 parsing
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-2-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

The S[m|s]csrind extension extends the indirect CSR access mechanism
defined in Smaia/Ssaia extensions.

This patch just enables the definition and parsing.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 arch/riscv/include/asm/hwcap.h | 4 ++++
 arch/riscv/kernel/cpufeature.c | 2 ++
 2 files changed, 6 insertions(+)

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 7ef8e5f55c8d..d4a7b90e2d78 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -112,6 +112,8 @@
 #define RISCV_ISA_EXT_ZCLSD		103
 #define RISCV_ISA_EXT_ZICFILP		104
 #define RISCV_ISA_EXT_ZICFISS		105
+#define RISCV_ISA_EXT_SSCSRIND		106
+#define RISCV_ISA_EXT_SMCSRIND		107
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
@@ -121,9 +123,11 @@
 #ifdef CONFIG_RISCV_M_MODE
 #define RISCV_ISA_EXT_SxAIA		RISCV_ISA_EXT_SMAIA
 #define RISCV_ISA_EXT_SUPM		RISCV_ISA_EXT_SMNPM
+#define RISCV_ISA_EXT_SxCSRIND		RISCV_ISA_EXT_SMCSRIND
 #else
 #define RISCV_ISA_EXT_SxAIA		RISCV_ISA_EXT_SSAIA
 #define RISCV_ISA_EXT_SUPM		RISCV_ISA_EXT_SSNPM
+#define RISCV_ISA_EXT_SxCSRIND		RISCV_ISA_EXT_SSCSRIND
 #endif
 
 #endif /* _ASM_RISCV_HWCAP_H */
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index f46aa5602d74..3fa0a563fb21 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -576,11 +576,13 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_BUNDLE_VALIDATE(zvksg, riscv_zvksg_bundled_exts, riscv_ext_vector_crypto_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zvkt, RISCV_ISA_EXT_ZVKT, riscv_ext_vector_crypto_validate),
 	__RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
+	__RISCV_ISA_EXT_DATA(smcsrind, RISCV_ISA_EXT_SMCSRIND),
 	__RISCV_ISA_EXT_DATA(smmpm, RISCV_ISA_EXT_SMMPM),
 	__RISCV_ISA_EXT_SUPERSET(smnpm, RISCV_ISA_EXT_SMNPM, riscv_xlinuxenvcfg_exts),
 	__RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
 	__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
 	__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
+	__RISCV_ISA_EXT_DATA(sscsrind, RISCV_ISA_EXT_SSCSRIND),
 	__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
 	__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
 	__RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:17 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:17 -0700
Subject: [PATCH v6 03/21] dt-bindings: riscv: add Sxcsrind ISA extension
 description
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-3-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

Add the S[m|s]csrind ISA extension description.

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 Documentation/devicetree/bindings/riscv/extensions.yaml | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb21..4be557dc215d 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -181,6 +181,14 @@ properties:
             changes to interrupts as frozen at commit ccbddab ("Merge pull
             request #42 from riscv/jhauser-2023-RC4") of riscv-aia.
 
+        - const: smcsrind
+          description: |
+            The standard Smcsrind supervisor-level extension extends the
+            indirect CSR access mechanism defined by the Smaia extension. This
+            extension allows other ISA extension to use indirect CSR access
+            mechanism in M-mode as ratified in the 20240326 version of the
+            privileged ISA specification.
+
         - const: smmpm
           description: |
             The standard Smmpm extension for M-mode pointer masking as
@@ -199,6 +207,14 @@ properties:
             added by other RISC-V extensions in H/S/VS/U/VU modes and as
             ratified at commit a28bfae (Ratified (#7)) of riscv-state-enable.
 
+        - const: sscsrind
+          description: |
+            The standard Sscsrind supervisor-level extension extends the
+            indirect CSR access mechanism defined by the Ssaia extension. This
+            extension allows other ISA extension to use indirect CSR access
+            mechanism in S-mode as ratified in the 20240326 version of the
+            privileged ISA specification.
+
         - const: ssaia
           description: |
             The standard Ssaia supervisor-level extension for the advanced

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:18 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:18 -0700
Subject: [PATCH v6 04/21] RISC-V: Define indirect CSR access helpers
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-4-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

The indriect CSR requires multiple instructions to read/write CSR.
Add a few helper functions for ease of usage.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 arch/riscv/include/asm/csr_ind.h | 44 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/arch/riscv/include/asm/csr_ind.h b/arch/riscv/include/asm/csr_ind.h
new file mode 100644
index 000000000000..6fd7d44dc640
--- /dev/null
+++ b/arch/riscv/include/asm/csr_ind.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2024 Rivos Inc.
+ */
+
+#ifndef _ASM_RISCV_CSR_IND_H
+#define _ASM_RISCV_CSR_IND_H
+
+#include <linux/irqflags.h>
+
+#include <asm/csr.h>
+
+#define csr_ind_read(iregcsr, iselbase, iseloff) ({		\
+	unsigned long __value = 0;				\
+	unsigned long __flags;					\
+	local_irq_save(__flags);				\
+	csr_write(CSR_ISELECT, (iselbase) + (iseloff));		\
+	__value = csr_read(iregcsr);				\
+	local_irq_restore(__flags);				\
+	__value;						\
+})
+
+#define csr_ind_write(iregcsr, iselbase, iseloff, value) ({	\
+	unsigned long __flags;					\
+	local_irq_save(__flags);				\
+	csr_write(CSR_ISELECT, (iselbase) + (iseloff));		\
+	csr_write(iregcsr, (value));				\
+	local_irq_restore(__flags);				\
+})
+
+#define csr_ind_warl(iregcsr, iselbase, iseloff, warl_val) ({	\
+	unsigned long __old_val = 0, __value = 0;		\
+	unsigned long __flags;					\
+	local_irq_save(__flags);				\
+	csr_write(CSR_ISELECT, (iselbase) + (iseloff));		\
+	__old_val = csr_read(iregcsr);				\
+	csr_write(iregcsr, (warl_val));				\
+	__value = csr_read(iregcsr);				\
+	csr_write(iregcsr, __old_val);				\
+	local_irq_restore(__flags);				\
+	__value;						\
+})
+
+#endif

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:19 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:19 -0700
Subject: [PATCH v6 05/21] RISC-V: Add Smcntrpmf extension parsing
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-5-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

Smcntrpmf extension allows M-mode to enable privilege mode filtering
for cycle/instret counters. However, the cyclecfg/instretcfg CSRs are
only available only in Ssccfg only Smcntrpmf is present.

That's why, kernel needs to detect presence of Smcntrpmf extension and
enable privilege mode filtering for cycle/instret counters.

Reviewed-by: Cl?ment L?ger <cleger at rivosinc.com>
Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 arch/riscv/include/asm/hwcap.h | 1 +
 arch/riscv/kernel/cpufeature.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index d4a7b90e2d78..51ad55b9677a 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -114,6 +114,7 @@
 #define RISCV_ISA_EXT_ZICFISS		105
 #define RISCV_ISA_EXT_SSCSRIND		106
 #define RISCV_ISA_EXT_SMCSRIND		107
+#define RISCV_ISA_EXT_SMCNTRPMF		108
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 3fa0a563fb21..1452521d740a 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -576,6 +576,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_BUNDLE_VALIDATE(zvksg, riscv_zvksg_bundled_exts, riscv_ext_vector_crypto_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zvkt, RISCV_ISA_EXT_ZVKT, riscv_ext_vector_crypto_validate),
 	__RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
+	__RISCV_ISA_EXT_DATA(smcntrpmf, RISCV_ISA_EXT_SMCNTRPMF),
 	__RISCV_ISA_EXT_DATA(smcsrind, RISCV_ISA_EXT_SMCSRIND),
 	__RISCV_ISA_EXT_DATA(smmpm, RISCV_ISA_EXT_SMMPM),
 	__RISCV_ISA_EXT_SUPERSET(smnpm, RISCV_ISA_EXT_SMNPM, riscv_xlinuxenvcfg_exts),

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:20 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:20 -0700
Subject: [PATCH v6 06/21] dt-bindings: riscv: add Smcntrpmf ISA extension
 description
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-6-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

Add the description for Smcntrpmf ISA extension

Acked-by: Rob Herring (Arm) <robh at kernel.org>
Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 Documentation/devicetree/bindings/riscv/extensions.yaml | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 4be557dc215d..ece3edccee42 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -189,6 +189,12 @@ properties:
             mechanism in M-mode as ratified in the 20240326 version of the
             privileged ISA specification.
 
+        - const: smcntrpmf
+          description: |
+            The standard Smcntrpmf supervisor-level extension for the machine mode
+            to enable privilege mode filtering for cycle and instret counters as
+            ratified in the 20240326 version of the privileged ISA specification.
+
         - const: smmpm
           description: |
             The standard Smmpm extension for M-mode pointer masking as

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:21 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:21 -0700
Subject: [PATCH v6 07/21] RISC-V: Add Sscfg extension CSR definition
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-7-285b72ed65a9@meta.com>

From: Kaiwen Xue <kaiwenx at rivosinc.com>

This adds the scountinhibit CSR definition and S-mode accessible hpmevent
bits defined by smcdeleg/ssccfg. scountinhibit allows S-mode to start/stop
counters directly from S-mode without invoking SBI calls to M-mode. It is
also used to figure out the counters delegated to S-mode by the M-mode as
well.

Signed-off-by: Kaiwen Xue <kaiwenx at rivosinc.com>
Reviewed-by: Cl?ment L?ger <cleger at rivosinc.com>
---
 arch/riscv/include/asm/csr.h | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index b4551a6cf7cb..26cb78dee2fd 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -241,6 +241,31 @@
 #define SMSTATEEN0_HSENVCFG		(_ULL(1) << SMSTATEEN0_HSENVCFG_SHIFT)
 #define SMSTATEEN0_SSTATEEN0_SHIFT	63
 #define SMSTATEEN0_SSTATEEN0		(_ULL(1) << SMSTATEEN0_SSTATEEN0_SHIFT)
+/* HPMEVENT bits. These are accessible in S-mode via Smcdeleg/Ssccfg */
+#ifdef CONFIG_64BIT
+#define HPMEVENT_OF			(BIT_ULL(63))
+#define HPMEVENT_MINH			(BIT_ULL(62))
+#define HPMEVENT_SINH			(BIT_ULL(61))
+#define HPMEVENT_UINH			(BIT_ULL(60))
+#define HPMEVENT_VSINH			(BIT_ULL(59))
+#define HPMEVENT_VUINH			(BIT_ULL(58))
+#else
+#define HPMEVENTH_OF			(BIT_ULL(31))
+#define HPMEVENTH_MINH			(BIT_ULL(30))
+#define HPMEVENTH_SINH			(BIT_ULL(29))
+#define HPMEVENTH_UINH			(BIT_ULL(28))
+#define HPMEVENTH_VSINH			(BIT_ULL(27))
+#define HPMEVENTH_VUINH			(BIT_ULL(26))
+
+#define HPMEVENT_OF			(HPMEVENTH_OF << 32)
+#define HPMEVENT_MINH			(HPMEVENTH_MINH << 32)
+#define HPMEVENT_SINH			(HPMEVENTH_SINH << 32)
+#define HPMEVENT_UINH			(HPMEVENTH_UINH << 32)
+#define HPMEVENT_VSINH			(HPMEVENTH_VSINH << 32)
+#define HPMEVENT_VUINH			(HPMEVENTH_VUINH << 32)
+#endif
+
+#define SISELECT_SSCCFG_BASE		0x40
 
 /* mseccfg bits */
 #define MSECCFG_PMM			ENVCFG_PMM
@@ -322,6 +347,7 @@
 #define CSR_SCOUNTEREN		0x106
 #define CSR_SENVCFG		0x10a
 #define CSR_SSTATEEN0		0x10c
+#define CSR_SCOUNTINHIBIT	0x120
 #define CSR_SSCRATCH		0x140
 #define CSR_SEPC		0x141
 #define CSR_SCAUSE		0x142

-- 
2.53.0-Meta



From uwu at icenowy.me  Mon Jun  8 23:01:43 2026
From: uwu at icenowy.me (Icenowy Zheng)
Date: Tue, 09 Jun 2026 14:01:43 +0800
Subject: [PATCH 02/12] clk: thead: th1520-ap: add support for MISC
 subsys clocks
In-Reply-To: <aier9XppLeCkJydw@thelio>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
	 <20260507081710.4090814-3-zhengxingda@iscas.ac.cn>
	 <aier9XppLeCkJydw@thelio>
Message-ID: <93b867c1b7f5526cc25cb04f838432cd752f5981.camel@icenowy.me>

? 2026-06-08?? 23:00 -0700?Drew Fustini???
> On Thu, May 07, 2026 at 04:17:00PM +0800, Icenowy Zheng wrote:
> > The TH1520 SoC contains a MISC_SUBSYS clock controller, which
> > allows
> > controlling of USB related clocks and MMC/SD controller AHB bus
> > clocks.
> > 
> > Add support for this clock controller, in order to enable USB
> > support.
> > 
> > Signed-off-by: Icenowy Zheng <zhengxingda at iscas.ac.cn>
> > ---
> > ?drivers/clk/thead/clk-th1520-ap.c | 64
> > +++++++++++++++++++++++++++++++
> > ?1 file changed, 64 insertions(+)
> > 
> > diff --git a/drivers/clk/thead/clk-th1520-ap.c
> > b/drivers/clk/thead/clk-th1520-ap.c
> > index 3a6847f1c950f..24f785f0b329a 100644
> > --- a/drivers/clk/thead/clk-th1520-ap.c
> > +++ b/drivers/clk/thead/clk-th1520-ap.c
> [...]
> > @@ -1609,6 +1663,12 @@ static int th1520_clk_probe(struct
> > platform_device *pdev)
> > ?			return ret;
> > ?	}
> > ?
> > +	if (plat_data == &th1520_ap_platdata) {
> > +		ret = devm_clk_hw_register(dev,
> > &usb_suspend_div_clk.hw);
> > +		if (ret)
> > +			return ret;
> > +	}
> 
> Should usb_suspend_div_clk.hw instead be registered under
> 'if (plat_data == &th1520_ap_platdata)'?

Do you mean misc_platdata?

Yes, this is an copy-n-paste error that deserves a fix.

Thanks,
Icenowy

> 
> Thanks,
> Drew


From atish.patra at linux.dev  Mon Jun  8 23:01:22 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:22 -0700
Subject: [PATCH v6 08/21] RISC-V: Add Ssccfg/Smcdeleg ISA extension
 definition and parsing
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-8-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

Smcdeleg extension allows the M-mode to delegate selected counters
to S-mode so that it can access those counters and correpsonding
hpmevent CSRs without M-mode.

Ssccfg (?Ss? for Privileged architecture and Supervisor-level
extension, ?ccfg? for Counter Configuration) provides access to
delegated counters and new supervisor-level state.

This patch just enables these definitions and enable parsing.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 arch/riscv/include/asm/hwcap.h |  2 ++
 arch/riscv/kernel/cpufeature.c | 24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 51ad55b9677a..089353b250b0 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -115,6 +115,8 @@
 #define RISCV_ISA_EXT_SSCSRIND		106
 #define RISCV_ISA_EXT_SMCSRIND		107
 #define RISCV_ISA_EXT_SMCNTRPMF		108
+#define RISCV_ISA_EXT_SSCCFG		109
+#define RISCV_ISA_EXT_SMCDELEG		110
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 1452521d740a..1fe647e03515 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -330,6 +330,27 @@ static const unsigned int riscv_a_exts[] = {
 	RISCV_ISA_EXT_ZKNE,	\
 	RISCV_ISA_EXT_ZKNH
 
+static int riscv_ext_smcdeleg_validate(const struct riscv_isa_ext_data *data,
+				       const unsigned long *isa_bitmap)
+{
+	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SSCSRIND) &&
+	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZIHPM) &&
+	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZICNTR))
+		return 0;
+
+	return -EPROBE_DEFER;
+}
+
+static int riscv_ext_ssccfg_validate(const struct riscv_isa_ext_data *data,
+				     const unsigned long *isa_bitmap)
+{
+	if (!riscv_ext_smcdeleg_validate(data, isa_bitmap) &&
+	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SMCDELEG))
+		return 0;
+
+	return -EPROBE_DEFER;
+}
+
 static const unsigned int riscv_zk_bundled_exts[] = {
 	RISCV_ISA_EXT_ZKN,
 	RISCV_ISA_EXT_ZKR,
@@ -576,12 +597,15 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_BUNDLE_VALIDATE(zvksg, riscv_zvksg_bundled_exts, riscv_ext_vector_crypto_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zvkt, RISCV_ISA_EXT_ZVKT, riscv_ext_vector_crypto_validate),
 	__RISCV_ISA_EXT_DATA(smaia, RISCV_ISA_EXT_SMAIA),
+	__RISCV_ISA_EXT_DATA_VALIDATE(smcdeleg, RISCV_ISA_EXT_SMCDELEG,
+				      riscv_ext_smcdeleg_validate),
 	__RISCV_ISA_EXT_DATA(smcntrpmf, RISCV_ISA_EXT_SMCNTRPMF),
 	__RISCV_ISA_EXT_DATA(smcsrind, RISCV_ISA_EXT_SMCSRIND),
 	__RISCV_ISA_EXT_DATA(smmpm, RISCV_ISA_EXT_SMMPM),
 	__RISCV_ISA_EXT_SUPERSET(smnpm, RISCV_ISA_EXT_SMNPM, riscv_xlinuxenvcfg_exts),
 	__RISCV_ISA_EXT_DATA(smstateen, RISCV_ISA_EXT_SMSTATEEN),
 	__RISCV_ISA_EXT_DATA(ssaia, RISCV_ISA_EXT_SSAIA),
+	__RISCV_ISA_EXT_DATA_VALIDATE(ssccfg, RISCV_ISA_EXT_SSCCFG, riscv_ext_ssccfg_validate),
 	__RISCV_ISA_EXT_DATA(sscofpmf, RISCV_ISA_EXT_SSCOFPMF),
 	__RISCV_ISA_EXT_DATA(sscsrind, RISCV_ISA_EXT_SSCSRIND),
 	__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:26 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:26 -0700
Subject: [PATCH v6 12/21] RISC-V: perf: Add a mechanism to defined legacy
 event encoding
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-12-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

RISC-V ISA doesn't define any standard event encodings or specify
any event to counter mapping. Thus, event encoding information
and corresponding counter mapping fot those events needs to be
provided in the driver for each vendor.

Add a framework to support that. The individual platform events
will be added later.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 drivers/perf/riscv_pmu_sbi.c   | 54 +++++++++++++++++++++++++++++++++++++++++-
 include/linux/perf/riscv_pmu.h | 13 ++++++++++
 2 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 57ab15beab3e..46a25979e95e 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -379,6 +379,56 @@ static int pmu_sbi_check_event_info(void)
 	return result;
 }
 
+/*
+ * Vendor specific PMU events.
+ */
+struct riscv_pmu_event {
+	u64 event_id;
+	u32 counter_mask;
+};
+
+struct riscv_vendor_pmu_events {
+	unsigned long vendorid;
+	unsigned long archid;
+	unsigned long implid;
+	const struct riscv_pmu_event *hw_event_map;
+	const struct riscv_pmu_event (*cache_event_map)[PERF_COUNT_HW_CACHE_OP_MAX]
+						       [PERF_COUNT_HW_CACHE_RESULT_MAX];
+};
+
+#define RISCV_VENDOR_PMU_EVENTS(_vendorid, _archid, _implid, _hw_event_map, _cache_event_map) \
+	{ .vendorid = _vendorid, .archid = _archid, .implid = _implid, \
+	  .hw_event_map = _hw_event_map, .cache_event_map = _cache_event_map },
+
+static struct riscv_vendor_pmu_events pmu_vendor_events_table[] = {
+};
+
+static const struct riscv_pmu_event *current_pmu_hw_event_map;
+static const struct riscv_pmu_event (*current_pmu_cache_event_map)[PERF_COUNT_HW_CACHE_OP_MAX]
+							   [PERF_COUNT_HW_CACHE_RESULT_MAX];
+
+static void rvpmu_vendor_register_events(void)
+{
+	int cpu = raw_smp_processor_id();
+	unsigned long vendor_id = riscv_cached_mvendorid(cpu);
+	unsigned long impl_id = riscv_cached_mimpid(cpu);
+	unsigned long arch_id = riscv_cached_marchid(cpu);
+
+	for (int i = 0; i < ARRAY_SIZE(pmu_vendor_events_table); i++) {
+		if (pmu_vendor_events_table[i].vendorid == vendor_id &&
+		    pmu_vendor_events_table[i].implid == impl_id &&
+		    pmu_vendor_events_table[i].archid == arch_id) {
+			current_pmu_hw_event_map = pmu_vendor_events_table[i].hw_event_map;
+			current_pmu_cache_event_map = pmu_vendor_events_table[i].cache_event_map;
+			break;
+		}
+	}
+
+	if (!current_pmu_hw_event_map || !current_pmu_cache_event_map) {
+		pr_info("No default PMU events found\n");
+	}
+}
+
 static void rvpmu_sbi_check_event(struct sbi_pmu_event_data *edata)
 {
 	struct sbiret ret;
@@ -1643,8 +1693,10 @@ static int __init rvpmu_devinit(void)
 	 */
 	if (riscv_isa_extension_available(NULL, SSCCFG) &&
 	    riscv_isa_extension_available(NULL, SMCDELEG) &&
-	    riscv_isa_extension_available(NULL, SSCSRIND))
+	    riscv_isa_extension_available(NULL, SSCSRIND)) {
 		static_branch_enable(&riscv_pmu_cdeleg_available);
+		rvpmu_vendor_register_events();
+	}
 
 	if (!(riscv_pmu_sbi_available_boot() || riscv_pmu_cdeleg_available_boot()))
 		return 0;
diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
index f82a28040594..6c75106989b6 100644
--- a/include/linux/perf/riscv_pmu.h
+++ b/include/linux/perf/riscv_pmu.h
@@ -28,6 +28,19 @@
 
 #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1
 
+#define HW_OP_UNSUPPORTED		0xFFFF
+#define CACHE_OP_UNSUPPORTED		0xFFFF
+
+#define PERF_MAP_ALL_UNSUPPORTED					\
+	[0 ... PERF_COUNT_HW_MAX - 1] = {HW_OP_UNSUPPORTED, 0x0}
+
+#define PERF_CACHE_MAP_ALL_UNSUPPORTED					\
+[0 ... C(MAX) - 1] = {							\
+	[0 ... C(OP_MAX) - 1] = {					\
+		[0 ... C(RESULT_MAX) - 1] = {CACHE_OP_UNSUPPORTED, 0x0}	\
+	},								\
+}
+
 struct cpu_hw_events {
 	/* currently enabled events */
 	int			n_events;

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:23 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:23 -0700
Subject: [PATCH v6 09/21] dt-bindings: riscv: add Counter delegation ISA
 extensions description
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-9-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

Add description for the Smcdeleg/Ssccfg extension.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../devicetree/bindings/riscv/extensions.yaml      | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index ece3edccee42..2845e8e2999a 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -181,6 +181,13 @@ properties:
             changes to interrupts as frozen at commit ccbddab ("Merge pull
             request #42 from riscv/jhauser-2023-RC4") of riscv-aia.
 
+        - const: smcdeleg
+          description: |
+            The standard Smcdeleg supervisor-level extension for the machine mode
+            to delegate the hpmcounters to supervisor mode so that they are
+            directly accessible in the supervisor mode as ratified in the
+            20240213 version of the privileged ISA specification.
+
         - const: smcsrind
           description: |
             The standard Smcsrind supervisor-level extension extends the
@@ -228,6 +235,14 @@ properties:
             behavioural changes to interrupts as frozen at commit ccbddab
             ("Merge pull request #42 from riscv/jhauser-2023-RC4") of riscv-aia.
 
+        - const: ssccfg
+          description: |
+            The standard Ssccfg supervisor-level extension for configuring
+            the delegated hpmcounters to be accessible directly in supervisor
+            mode as ratified in the 20240213 version of the privileged ISA
+            specification. This extension depends on Sscsrind, Smcdeleg, Sscofpmf,
+            Smcntrpmf, Zihpm, Zicntr extensions.
+
         - const: ssccptr
           description: |
             The standard Ssccptr extension for main memory (cacheability and
@@ -1135,6 +1150,36 @@ properties:
             allOf:
               - const: zilsd
               - const: zca
+      # Smcdeleg depends on Sscsrind, Zihpm, Zicntr
+      - if:
+          contains:
+            const: smcdeleg
+        then:
+          allOf:
+            - contains:
+                const: sscsrind
+            - contains:
+                const: zihpm
+            - contains:
+                const: zicntr
+      # Ssccfg depends on Smcdeleg, Sscsrind, Zihpm, Zicntr, Sscofpmf, Smcntrpmf
+      - if:
+          contains:
+            const: ssccfg
+        then:
+          allOf:
+            - contains:
+                const: smcdeleg
+            - contains:
+                const: sscsrind
+            - contains:
+                const: sscofpmf
+            - contains:
+                const: smcntrpmf
+            - contains:
+                const: zihpm
+            - contains:
+                const: zicntr
 
 allOf:
   # Zcf extension does not exist on rv64

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:24 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:24 -0700
Subject: [PATCH v6 10/21] RISC-V: perf: Restructure the SBI PMU code
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-10-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

With Ssccfg/Smcdeleg, supervisor mode can program and access the hpmcounters
and events directly, without the SBI PMU extension. The SBI PMU extension is
still required for firmware counters. Restructure the existing SBI PMU code so
the hpmcounter/event helpers can be shared between the SBI and the counter
delegation paths that follow.

The driver, file, module and Kconfig names are intentionally kept unchanged to
avoid backport churn and userspace breakage (module listings, udev rules,
cmdline options).

No functional change intended.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 drivers/perf/Kconfig         |  14 ++-
 drivers/perf/riscv_pmu_sbi.c | 238 +++++++++++++++++++++++++------------------
 2 files changed, 150 insertions(+), 102 deletions(-)

diff --git a/drivers/perf/Kconfig b/drivers/perf/Kconfig
index ab90932fc2d0..3245bb2969e1 100644
--- a/drivers/perf/Kconfig
+++ b/drivers/perf/Kconfig
@@ -97,13 +97,17 @@ config RISCV_PMU_LEGACY
 
 config RISCV_PMU_SBI
 	depends on RISCV_PMU && RISCV_SBI
-	bool "RISC-V PMU based on SBI PMU extension"
+	bool "RISC-V PMU based on SBI PMU extension and/or counter delegation"
 	default y
 	help
-	  Say y if you want to use the CPU performance monitor
-	  using SBI PMU extension on RISC-V based systems. This option provides
-	  full perf feature support i.e. counter overflow, privilege mode
-	  filtering, counter configuration.
+	  Say y if you want to use the CPU performance monitor on RISC-V based
+	  systems. This single driver supports both hardware counter access
+	  mechanisms: it uses the counter delegation (Smcdeleg/Ssccfg) ISA
+	  extension to program and read the hpmcounters directly in supervisor
+	  mode when available, and uses the SBI PMU extension for firmware
+	  counters and when counter delegation is not present. This option
+	  provides full perf feature support i.e. counter overflow, privilege
+	  mode filtering, counter configuration.
 
 config STARFIVE_STARLINK_PMU
 	depends on ARCH_STARFIVE || COMPILE_TEST
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 385af5e6e6d0..7f21c16003f0 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -88,6 +88,8 @@ static const struct attribute_group *riscv_pmu_attr_groups[] = {
 static int sysctl_perf_user_access __read_mostly = SYSCTL_USER_ACCESS;
 
 /*
+ * This structure is SBI specific but counter delegation also require counter
+ * width, csr mapping. Reuse it for now.
  * RISC-V doesn't have heterogeneous harts yet. This need to be part of
  * per_cpu in case of harts with different pmu counters
  */
@@ -100,7 +102,7 @@ static unsigned int riscv_pmu_irq;
 /* Cache the available counters in a bitmask */
 static unsigned long cmask;
 
-static int pmu_event_find_cache(u64 config);
+static int sbi_pmu_event_find_cache(u64 config);
 struct sbi_pmu_event_data {
 	union {
 		union {
@@ -121,7 +123,7 @@ struct sbi_pmu_event_data {
 	};
 };
 
-static struct sbi_pmu_event_data pmu_hw_event_map[] = {
+static struct sbi_pmu_event_data pmu_hw_event_sbi_map[] = {
 	[PERF_COUNT_HW_CPU_CYCLES]		= {.hw_gen_event = {
 							SBI_PMU_HW_CPU_CYCLES,
 							SBI_PMU_EVENT_TYPE_HW, 0}},
@@ -155,7 +157,7 @@ static struct sbi_pmu_event_data pmu_hw_event_map[] = {
 };
 
 #define C(x) PERF_COUNT_HW_CACHE_##x
-static struct sbi_pmu_event_data pmu_cache_event_map[PERF_COUNT_HW_CACHE_MAX]
+static struct sbi_pmu_event_data pmu_cache_event_sbi_map[PERF_COUNT_HW_CACHE_MAX]
 [PERF_COUNT_HW_CACHE_OP_MAX]
 [PERF_COUNT_HW_CACHE_RESULT_MAX] = {
 	[C(L1D)] = {
@@ -302,7 +304,7 @@ static struct sbi_pmu_event_data pmu_cache_event_map[PERF_COUNT_HW_CACHE_MAX]
 
 static int pmu_sbi_check_event_info(void)
 {
-	int num_events = ARRAY_SIZE(pmu_hw_event_map) + PERF_COUNT_HW_CACHE_MAX *
+	int num_events = ARRAY_SIZE(pmu_hw_event_sbi_map) + PERF_COUNT_HW_CACHE_MAX *
 			 PERF_COUNT_HW_CACHE_OP_MAX * PERF_COUNT_HW_CACHE_RESULT_MAX;
 	struct riscv_pmu_event_info *event_info_shmem;
 	phys_addr_t base_addr;
@@ -313,14 +315,14 @@ static int pmu_sbi_check_event_info(void)
 	if (!event_info_shmem)
 		return -ENOMEM;
 
-	for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++)
-		event_info_shmem[count++].event_idx = pmu_hw_event_map[i].event_idx;
+	for (i = 0; i < ARRAY_SIZE(pmu_hw_event_sbi_map); i++)
+		event_info_shmem[count++].event_idx = pmu_hw_event_sbi_map[i].event_idx;
 
-	for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) {
-		for (j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) {
-			for (k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++)
+	for (i = 0; i < ARRAY_SIZE(pmu_cache_event_sbi_map); i++) {
+		for (j = 0; j < ARRAY_SIZE(pmu_cache_event_sbi_map[i]); j++) {
+			for (k = 0; k < ARRAY_SIZE(pmu_cache_event_sbi_map[i][j]); k++)
 				event_info_shmem[count++].event_idx =
-							pmu_cache_event_map[i][j][k].event_idx;
+							pmu_cache_event_sbi_map[i][j][k].event_idx;
 		}
 	}
 
@@ -336,19 +338,19 @@ static int pmu_sbi_check_event_info(void)
 		goto free_mem;
 	}
 
-	for (i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++) {
+	for (i = 0; i < ARRAY_SIZE(pmu_hw_event_sbi_map); i++) {
 		if (!(event_info_shmem[i].output & RISCV_PMU_EVENT_INFO_OUTPUT_MASK))
-			pmu_hw_event_map[i].event_idx = -ENOENT;
+			pmu_hw_event_sbi_map[i].event_idx = -ENOENT;
 	}
 
-	count = ARRAY_SIZE(pmu_hw_event_map);
+	count = ARRAY_SIZE(pmu_hw_event_sbi_map);
 
-	for (i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++) {
-		for (j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++) {
-			for (k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++) {
+	for (i = 0; i < ARRAY_SIZE(pmu_cache_event_sbi_map); i++) {
+		for (j = 0; j < ARRAY_SIZE(pmu_cache_event_sbi_map[i]); j++) {
+			for (k = 0; k < ARRAY_SIZE(pmu_cache_event_sbi_map[i][j]); k++) {
 				if (!(event_info_shmem[count].output &
 				      RISCV_PMU_EVENT_INFO_OUTPUT_MASK))
-					pmu_cache_event_map[i][j][k].event_idx = -ENOENT;
+					pmu_cache_event_sbi_map[i][j][k].event_idx = -ENOENT;
 				count++;
 			}
 		}
@@ -360,7 +362,7 @@ static int pmu_sbi_check_event_info(void)
 	return result;
 }
 
-static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata)
+static void rvpmu_sbi_check_event(struct sbi_pmu_event_data *edata)
 {
 	struct sbiret ret;
 
@@ -375,7 +377,7 @@ static void pmu_sbi_check_event(struct sbi_pmu_event_data *edata)
 	}
 }
 
-static void pmu_sbi_check_std_events(struct work_struct *work)
+static void rvpmu_sbi_check_std_events(struct work_struct *work)
 {
 	int ret;
 
@@ -386,23 +388,23 @@ static void pmu_sbi_check_std_events(struct work_struct *work)
 		return;
 	}
 
-	for (int i = 0; i < ARRAY_SIZE(pmu_hw_event_map); i++)
-		pmu_sbi_check_event(&pmu_hw_event_map[i]);
+	for (int i = 0; i < ARRAY_SIZE(pmu_hw_event_sbi_map); i++)
+		rvpmu_sbi_check_event(&pmu_hw_event_sbi_map[i]);
 
-	for (int i = 0; i < ARRAY_SIZE(pmu_cache_event_map); i++)
-		for (int j = 0; j < ARRAY_SIZE(pmu_cache_event_map[i]); j++)
-			for (int k = 0; k < ARRAY_SIZE(pmu_cache_event_map[i][j]); k++)
-				pmu_sbi_check_event(&pmu_cache_event_map[i][j][k]);
+	for (int i = 0; i < ARRAY_SIZE(pmu_cache_event_sbi_map); i++)
+		for (int j = 0; j < ARRAY_SIZE(pmu_cache_event_sbi_map[i]); j++)
+			for (int k = 0; k < ARRAY_SIZE(pmu_cache_event_sbi_map[i][j]); k++)
+				rvpmu_sbi_check_event(&pmu_cache_event_sbi_map[i][j][k]);
 }
 
-static DECLARE_WORK(check_std_events_work, pmu_sbi_check_std_events);
+static DECLARE_WORK(check_std_events_work, rvpmu_sbi_check_std_events);
 
-static int pmu_sbi_ctr_get_width(int idx)
+static int rvpmu_ctr_get_width(int idx)
 {
 	return pmu_ctr_list[idx].width;
 }
 
-static bool pmu_sbi_ctr_is_fw(int cidx)
+static bool rvpmu_ctr_is_fw(int cidx)
 {
 	union sbi_pmu_ctr_info *info;
 
@@ -421,10 +423,10 @@ int riscv_pmu_get_event_info(u32 type, u64 config, u64 *econfig)
 	case PERF_TYPE_HARDWARE:
 		if (config >= PERF_COUNT_HW_MAX)
 			return -EINVAL;
-		ret = pmu_hw_event_map[config].event_idx;
+		ret = pmu_hw_event_sbi_map[config].event_idx;
 		break;
 	case PERF_TYPE_HW_CACHE:
-		ret = pmu_event_find_cache(config);
+		ret = sbi_pmu_event_find_cache(config);
 		break;
 	case PERF_TYPE_RAW:
 		/*
@@ -509,12 +511,12 @@ int riscv_pmu_get_hpm_info(u32 *hw_ctr_width, u32 *num_hw_ctr)
 }
 EXPORT_SYMBOL_GPL(riscv_pmu_get_hpm_info);
 
-static uint8_t pmu_sbi_csr_index(struct perf_event *event)
+static uint8_t rvpmu_csr_index(struct perf_event *event)
 {
 	return pmu_ctr_list[event->hw.idx].csr - CSR_CYCLE;
 }
 
-static unsigned long pmu_sbi_get_filter_flags(struct perf_event *event)
+static unsigned long rvpmu_sbi_get_filter_flags(struct perf_event *event)
 {
 	unsigned long cflags = 0;
 	bool guest_events = false;
@@ -535,7 +537,7 @@ static unsigned long pmu_sbi_get_filter_flags(struct perf_event *event)
 	return cflags;
 }
 
-static int pmu_sbi_ctr_get_idx(struct perf_event *event)
+static int rvpmu_sbi_ctr_get_idx(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
 	struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
@@ -545,7 +547,7 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event)
 	uint64_t cbase = 0, cmask = rvpmu->cmask;
 	unsigned long cflags = 0;
 
-	cflags = pmu_sbi_get_filter_flags(event);
+	cflags = rvpmu_sbi_get_filter_flags(event);
 
 	/*
 	 * In legacy mode, we have to force the fixed counters for those events
@@ -582,7 +584,7 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event)
 		return -ENOENT;
 
 	/* Additional sanity check for the counter id */
-	if (pmu_sbi_ctr_is_fw(idx)) {
+	if (rvpmu_ctr_is_fw(idx)) {
 		if (!test_and_set_bit(idx, cpuc->used_fw_ctrs))
 			return idx;
 	} else {
@@ -593,7 +595,7 @@ static int pmu_sbi_ctr_get_idx(struct perf_event *event)
 	return -ENOENT;
 }
 
-static void pmu_sbi_ctr_clear_idx(struct perf_event *event)
+static void rvpmu_ctr_clear_idx(struct perf_event *event)
 {
 
 	struct hw_perf_event *hwc = &event->hw;
@@ -601,13 +603,13 @@ static void pmu_sbi_ctr_clear_idx(struct perf_event *event)
 	struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
 	int idx = hwc->idx;
 
-	if (pmu_sbi_ctr_is_fw(idx))
+	if (rvpmu_ctr_is_fw(idx))
 		clear_bit(idx, cpuc->used_fw_ctrs);
 	else
 		clear_bit(idx, cpuc->used_hw_ctrs);
 }
 
-static int pmu_event_find_cache(u64 config)
+static int sbi_pmu_event_find_cache(u64 config)
 {
 	unsigned int cache_type, cache_op, cache_result, ret;
 
@@ -623,7 +625,7 @@ static int pmu_event_find_cache(u64 config)
 	if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
 		return -EINVAL;
 
-	ret = pmu_cache_event_map[cache_type][cache_op][cache_result].event_idx;
+	ret = pmu_cache_event_sbi_map[cache_type][cache_op][cache_result].event_idx;
 
 	return ret;
 }
@@ -639,7 +641,7 @@ static bool pmu_sbi_is_fw_event(struct perf_event *event)
 		return false;
 }
 
-static int pmu_sbi_event_map(struct perf_event *event, u64 *econfig)
+static int rvpmu_sbi_event_map(struct perf_event *event, u64 *econfig)
 {
 	u32 type = event->attr.type;
 	u64 config = event->attr.config;
@@ -736,7 +738,7 @@ static int pmu_sbi_snapshot_setup(struct riscv_pmu *pmu, int cpu)
 	return 0;
 }
 
-static u64 pmu_sbi_ctr_read(struct perf_event *event)
+static u64 rvpmu_sbi_ctr_read(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
 	int idx = hwc->idx;
@@ -778,25 +780,25 @@ static u64 pmu_sbi_ctr_read(struct perf_event *event)
 	return val;
 }
 
-static void pmu_sbi_set_scounteren(void *arg)
+static void rvpmu_set_scounteren(void *arg)
 {
 	struct perf_event *event = (struct perf_event *)arg;
 
 	if (event->hw.idx != -1)
 		csr_write(CSR_SCOUNTEREN,
-			  csr_read(CSR_SCOUNTEREN) | BIT(pmu_sbi_csr_index(event)));
+			  csr_read(CSR_SCOUNTEREN) | BIT(rvpmu_csr_index(event)));
 }
 
-static void pmu_sbi_reset_scounteren(void *arg)
+static void rvpmu_reset_scounteren(void *arg)
 {
 	struct perf_event *event = (struct perf_event *)arg;
 
 	if (event->hw.idx != -1)
 		csr_write(CSR_SCOUNTEREN,
-			  csr_read(CSR_SCOUNTEREN) & ~BIT(pmu_sbi_csr_index(event)));
+			  csr_read(CSR_SCOUNTEREN) & ~BIT(rvpmu_csr_index(event)));
 }
 
-static void pmu_sbi_ctr_start(struct perf_event *event, u64 ival)
+static void rvpmu_sbi_ctr_start(struct perf_event *event, u64 ival)
 {
 	struct sbiret ret;
 	struct hw_perf_event *hwc = &event->hw;
@@ -816,10 +818,10 @@ static void pmu_sbi_ctr_start(struct perf_event *event, u64 ival)
 
 	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
 	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
-		pmu_sbi_set_scounteren((void *)event);
+		rvpmu_set_scounteren((void *)event);
 }
 
-static void pmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
+static void rvpmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
 {
 	struct sbiret ret;
 	struct hw_perf_event *hwc = &event->hw;
@@ -829,7 +831,7 @@ static void pmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
 
 	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
 	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
-		pmu_sbi_reset_scounteren((void *)event);
+		rvpmu_reset_scounteren((void *)event);
 
 	if (sbi_pmu_snapshot_available())
 		flag |= SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT;
@@ -855,7 +857,7 @@ static void pmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
 	}
 }
 
-static int pmu_sbi_find_num_ctrs(void)
+static int rvpmu_sbi_find_num_ctrs(void)
 {
 	struct sbiret ret;
 
@@ -866,7 +868,7 @@ static int pmu_sbi_find_num_ctrs(void)
 		return sbi_err_map_linux_errno(ret.error);
 }
 
-static int pmu_sbi_get_ctrinfo(int nctr, unsigned long *mask)
+static int rvpmu_sbi_get_ctrinfo(int nctr, unsigned long *mask)
 {
 	struct sbiret ret;
 	int i, num_hw_ctr = 0, num_fw_ctr = 0;
@@ -897,7 +899,7 @@ static int pmu_sbi_get_ctrinfo(int nctr, unsigned long *mask)
 	return 0;
 }
 
-static inline void pmu_sbi_stop_all(struct riscv_pmu *pmu)
+static inline void rvpmu_sbi_stop_all(struct riscv_pmu *pmu)
 {
 	/*
 	 * No need to check the error because we are disabling all the counters
@@ -907,7 +909,7 @@ static inline void pmu_sbi_stop_all(struct riscv_pmu *pmu)
 		  0, pmu->cmask, SBI_PMU_STOP_FLAG_RESET, 0, 0, 0);
 }
 
-static inline void pmu_sbi_stop_hw_ctrs(struct riscv_pmu *pmu)
+static inline void rvpmu_sbi_stop_hw_ctrs(struct riscv_pmu *pmu)
 {
 	struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
 	struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
@@ -951,8 +953,8 @@ static inline void pmu_sbi_stop_hw_ctrs(struct riscv_pmu *pmu)
  * while the overflowed counters need to be started with updated initialization
  * value.
  */
-static inline void pmu_sbi_start_ovf_ctrs_sbi(struct cpu_hw_events *cpu_hw_evt,
-					      u64 ctr_ovf_mask)
+static inline void rvpmu_sbi_start_ovf_ctrs_sbi(struct cpu_hw_events *cpu_hw_evt,
+						u64 ctr_ovf_mask)
 {
 	int idx = 0, i;
 	struct perf_event *event;
@@ -992,8 +994,8 @@ static inline void pmu_sbi_start_ovf_ctrs_sbi(struct cpu_hw_events *cpu_hw_evt,
 	}
 }
 
-static inline void pmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_evt,
-						   u64 ctr_ovf_mask)
+static inline void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_evt,
+						     u64 ctr_ovf_mask)
 {
 	int i, idx = 0;
 	struct perf_event *event;
@@ -1027,18 +1029,18 @@ static inline void pmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_
 	}
 }
 
-static void pmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
-					u64 ctr_ovf_mask)
+static void rvpmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
+					  u64 ctr_ovf_mask)
 {
 	struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
 
 	if (sbi_pmu_snapshot_available())
-		pmu_sbi_start_ovf_ctrs_snapshot(cpu_hw_evt, ctr_ovf_mask);
+		rvpmu_sbi_start_ovf_ctrs_snapshot(cpu_hw_evt, ctr_ovf_mask);
 	else
-		pmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
+		rvpmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
 }
 
-static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
+static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
 {
 	struct perf_sample_data data;
 	struct pt_regs *regs;
@@ -1070,7 +1072,7 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
 	}
 
 	pmu = to_riscv_pmu(event->pmu);
-	pmu_sbi_stop_hw_ctrs(pmu);
+	rvpmu_sbi_stop_hw_ctrs(pmu);
 
 	/* Overflow status register should only be read after counter are stopped */
 	if (sbi_pmu_snapshot_available())
@@ -1139,13 +1141,55 @@ static irqreturn_t pmu_sbi_ovf_handler(int irq, void *dev)
 		hw_evt->state = 0;
 	}
 
-	pmu_sbi_start_overflow_mask(pmu, overflowed_ctrs);
+	rvpmu_sbi_start_overflow_mask(pmu, overflowed_ctrs);
 	perf_sample_event_took(sched_clock() - start_clock);
 
 	return IRQ_HANDLED;
 }
 
-static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
+static void rvpmu_ctr_start(struct perf_event *event, u64 ival)
+{
+	rvpmu_sbi_ctr_start(event, ival);
+	/* TODO: Counter delegation implementation */
+}
+
+static void rvpmu_ctr_stop(struct perf_event *event, unsigned long flag)
+{
+	rvpmu_sbi_ctr_stop(event, flag);
+	/* TODO: Counter delegation implementation */
+}
+
+static int rvpmu_find_num_ctrs(void)
+{
+	return rvpmu_sbi_find_num_ctrs();
+	/* TODO: Counter delegation implementation */
+}
+
+static int rvpmu_get_ctrinfo(int nctr, unsigned long *mask)
+{
+	return rvpmu_sbi_get_ctrinfo(nctr, mask);
+	/* TODO: Counter delegation implementation */
+}
+
+static int rvpmu_event_map(struct perf_event *event, u64 *econfig)
+{
+	return rvpmu_sbi_event_map(event, econfig);
+	/* TODO: Counter delegation implementation */
+}
+
+static int rvpmu_ctr_get_idx(struct perf_event *event)
+{
+	return rvpmu_sbi_ctr_get_idx(event);
+	/* TODO: Counter delegation implementation */
+}
+
+static u64 rvpmu_ctr_read(struct perf_event *event)
+{
+	return rvpmu_sbi_ctr_read(event);
+	/* TODO: Counter delegation implementation */
+}
+
+static int rvpmu_starting_cpu(unsigned int cpu, struct hlist_node *node)
 {
 	struct riscv_pmu *pmu = hlist_entry_safe(node, struct riscv_pmu, node);
 	struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
@@ -1160,7 +1204,7 @@ static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
 		csr_write(CSR_SCOUNTEREN, 0x2);
 
 	/* Stop all the counters so that they can be enabled from perf */
-	pmu_sbi_stop_all(pmu);
+	rvpmu_sbi_stop_all(pmu);
 
 	if (riscv_pmu_use_irq) {
 		cpu_hw_evt->irq = riscv_pmu_irq;
@@ -1174,7 +1218,7 @@ static int pmu_sbi_starting_cpu(unsigned int cpu, struct hlist_node *node)
 	return 0;
 }
 
-static int pmu_sbi_dying_cpu(unsigned int cpu, struct hlist_node *node)
+static int rvpmu_dying_cpu(unsigned int cpu, struct hlist_node *node)
 {
 	if (riscv_pmu_use_irq) {
 		disable_percpu_irq(riscv_pmu_irq);
@@ -1189,7 +1233,7 @@ static int pmu_sbi_dying_cpu(unsigned int cpu, struct hlist_node *node)
 	return 0;
 }
 
-static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pdev)
+static int rvpmu_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pdev)
 {
 	int ret;
 	struct cpu_hw_events __percpu *hw_events = pmu->hw_events;
@@ -1229,7 +1273,7 @@ static int pmu_sbi_setup_irqs(struct riscv_pmu *pmu, struct platform_device *pde
 		return -ENODEV;
 	}
 
-	ret = request_percpu_irq(riscv_pmu_irq, pmu_sbi_ovf_handler, "riscv-pmu", hw_events);
+	ret = request_percpu_irq(riscv_pmu_irq, rvpmu_ovf_handler, "riscv-pmu", hw_events);
 	if (ret) {
 		pr_err("registering percpu irq failed [%d]\n", ret);
 		return ret;
@@ -1305,7 +1349,7 @@ static void riscv_pmu_destroy(struct riscv_pmu *pmu)
 	cpuhp_state_remove_instance(CPUHP_AP_PERF_RISCV_STARTING, &pmu->node);
 }
 
-static void pmu_sbi_event_init(struct perf_event *event)
+static void rvpmu_event_init(struct perf_event *event)
 {
 	/*
 	 * The permissions are set at event_init so that we do not depend
@@ -1319,7 +1363,7 @@ static void pmu_sbi_event_init(struct perf_event *event)
 		event->hw.flags |= PERF_EVENT_FLAG_LEGACY;
 }
 
-static void pmu_sbi_event_mapped(struct perf_event *event, struct mm_struct *mm)
+static void rvpmu_event_mapped(struct perf_event *event, struct mm_struct *mm)
 {
 	if (event->hw.flags & PERF_EVENT_FLAG_NO_USER_ACCESS)
 		return;
@@ -1347,14 +1391,14 @@ static void pmu_sbi_event_mapped(struct perf_event *event, struct mm_struct *mm)
 	 * that it is possible to do so to avoid any race.
 	 * And we must notify all cpus here because threads that currently run
 	 * on other cpus will try to directly access the counter too without
-	 * calling pmu_sbi_ctr_start.
+	 * calling rvpmu_sbi_ctr_start.
 	 */
 	if (event->hw.flags & PERF_EVENT_FLAG_USER_ACCESS)
 		on_each_cpu_mask(mm_cpumask(mm),
-				 pmu_sbi_set_scounteren, (void *)event, 1);
+				 rvpmu_set_scounteren, (void *)event, 1);
 }
 
-static void pmu_sbi_event_unmapped(struct perf_event *event, struct mm_struct *mm)
+static void rvpmu_event_unmapped(struct perf_event *event, struct mm_struct *mm)
 {
 	if (event->hw.flags & PERF_EVENT_FLAG_NO_USER_ACCESS)
 		return;
@@ -1376,7 +1420,7 @@ static void pmu_sbi_event_unmapped(struct perf_event *event, struct mm_struct *m
 
 	if (event->hw.flags & PERF_EVENT_FLAG_USER_ACCESS)
 		on_each_cpu_mask(mm_cpumask(mm),
-				 pmu_sbi_reset_scounteren, (void *)event, 1);
+				 rvpmu_reset_scounteren, (void *)event, 1);
 }
 
 static void riscv_pmu_update_counter_access(void *info)
@@ -1419,7 +1463,7 @@ static const struct ctl_table sbi_pmu_sysctl_table[] = {
 	},
 };
 
-static int pmu_sbi_device_probe(struct platform_device *pdev)
+static int rvpmu_device_probe(struct platform_device *pdev)
 {
 	struct riscv_pmu *pmu = NULL;
 	int ret = -ENODEV;
@@ -1430,7 +1474,7 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
 	if (!pmu)
 		return -ENOMEM;
 
-	num_counters = pmu_sbi_find_num_ctrs();
+	num_counters = rvpmu_find_num_ctrs();
 	if (num_counters < 0) {
 		pr_err("SBI PMU extension doesn't provide any counters\n");
 		goto out_free;
@@ -1443,10 +1487,10 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
 	}
 
 	/* cache all the information about counters now */
-	if (pmu_sbi_get_ctrinfo(num_counters, &cmask))
+	if (rvpmu_get_ctrinfo(num_counters, &cmask))
 		goto out_free;
 
-	ret = pmu_sbi_setup_irqs(pmu, pdev);
+	ret = rvpmu_setup_irqs(pmu, pdev);
 	if (ret < 0) {
 		pr_info("Perf sampling/filtering is not supported as sscof extension is not available\n");
 		pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
@@ -1456,17 +1500,17 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
 	pmu->pmu.attr_groups = riscv_pmu_attr_groups;
 	pmu->pmu.parent = &pdev->dev;
 	pmu->cmask = cmask;
-	pmu->ctr_start = pmu_sbi_ctr_start;
-	pmu->ctr_stop = pmu_sbi_ctr_stop;
-	pmu->event_map = pmu_sbi_event_map;
-	pmu->ctr_get_idx = pmu_sbi_ctr_get_idx;
-	pmu->ctr_get_width = pmu_sbi_ctr_get_width;
-	pmu->ctr_clear_idx = pmu_sbi_ctr_clear_idx;
-	pmu->ctr_read = pmu_sbi_ctr_read;
-	pmu->event_init = pmu_sbi_event_init;
-	pmu->event_mapped = pmu_sbi_event_mapped;
-	pmu->event_unmapped = pmu_sbi_event_unmapped;
-	pmu->csr_index = pmu_sbi_csr_index;
+	pmu->ctr_start = rvpmu_ctr_start;
+	pmu->ctr_stop = rvpmu_ctr_stop;
+	pmu->event_map = rvpmu_event_map;
+	pmu->ctr_get_idx = rvpmu_ctr_get_idx;
+	pmu->ctr_get_width = rvpmu_ctr_get_width;
+	pmu->ctr_clear_idx = rvpmu_ctr_clear_idx;
+	pmu->ctr_read = rvpmu_ctr_read;
+	pmu->event_init = rvpmu_event_init;
+	pmu->event_mapped = rvpmu_event_mapped;
+	pmu->event_unmapped = rvpmu_event_unmapped;
+	pmu->csr_index = rvpmu_csr_index;
 
 	ret = riscv_pm_pmu_register(pmu);
 	if (ret)
@@ -1522,14 +1566,14 @@ static int pmu_sbi_device_probe(struct platform_device *pdev)
 	return ret;
 }
 
-static struct platform_driver pmu_sbi_driver = {
-	.probe		= pmu_sbi_device_probe,
+static struct platform_driver rvpmu_driver = {
+	.probe		= rvpmu_device_probe,
 	.driver		= {
 		.name	= RISCV_PMU_SBI_PDEV_NAME,
 	},
 };
 
-static int __init pmu_sbi_devinit(void)
+static int __init rvpmu_devinit(void)
 {
 	int ret;
 	struct platform_device *pdev;
@@ -1547,20 +1591,20 @@ static int __init pmu_sbi_devinit(void)
 
 	ret = cpuhp_setup_state_multi(CPUHP_AP_PERF_RISCV_STARTING,
 				      "perf/riscv/pmu:starting",
-				      pmu_sbi_starting_cpu, pmu_sbi_dying_cpu);
+				      rvpmu_starting_cpu, rvpmu_dying_cpu);
 	if (ret) {
 		pr_err("CPU hotplug notifier could not be registered: %d\n",
 		       ret);
 		return ret;
 	}
 
-	ret = platform_driver_register(&pmu_sbi_driver);
+	ret = platform_driver_register(&rvpmu_driver);
 	if (ret)
 		return ret;
 
 	pdev = platform_device_register_simple(RISCV_PMU_SBI_PDEV_NAME, -1, NULL, 0);
 	if (IS_ERR(pdev)) {
-		platform_driver_unregister(&pmu_sbi_driver);
+		platform_driver_unregister(&rvpmu_driver);
 		return PTR_ERR(pdev);
 	}
 
@@ -1569,4 +1613,4 @@ static int __init pmu_sbi_devinit(void)
 
 	return ret;
 }
-device_initcall(pmu_sbi_devinit)
+device_initcall(rvpmu_devinit)

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:29 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:29 -0700
Subject: [PATCH v6 15/21] RISC-V: perf: Use config2/vendor table for event
 to counter mapping
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-15-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

The counter restriction specified in the json file is passed to
the drivers via config2 paarameter in perf attributes. This allows
any platform vendor to define their custom mapping between event and
hpmcounters without any rules defined in the ISA.

For legacy events, the platform vendor may define the mapping in
the driver in the vendor event table.
The fixed cycle and instruction counters are fixed (0 and 2
respectively) by the ISA and maps to the legacy events. The platform
vendor must specify this in the driver if intended to be used while
profiling. Otherwise, they can just specify the alternate hpmcounters
that may monitor and/or sample the cycle/instruction counts.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 drivers/perf/riscv_pmu_sbi.c   | 90 ++++++++++++++++++++++++++++++++++--------
 include/linux/perf/riscv_pmu.h |  2 +
 2 files changed, 76 insertions(+), 16 deletions(-)

diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 5bfcd3821f57..4b4f151a0744 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -76,6 +76,7 @@ static ssize_t __maybe_unused rvpmu_format_show(struct device *dev, struct devic
 	RVPMU_ATTR_ENTRY(_name, rvpmu_format_show, (char *)_config)
 
 PMU_FORMAT_ATTR(firmware, "config:62-63");
+PMU_FORMAT_ATTR(counterid_mask, "config2:0-31");
 
 static bool sbi_v2_available;
 static bool sbi_v3_available;
@@ -120,6 +121,7 @@ static const struct attribute_group *riscv_sbi_pmu_attr_groups[] = {
 static struct attribute *riscv_cdeleg_pmu_formats_attr[] = {
 	RVPMU_FORMAT_ATTR_ENTRY(event, RVPMU_CDELEG_PMU_FORMAT_ATTR),
 	&format_attr_firmware.attr,
+	&format_attr_counterid_mask.attr,
 	NULL,
 };
 
@@ -1480,24 +1482,80 @@ static int rvpmu_deleg_find_ctrs(void)
 	return num_hw_ctr;
 }
 
+/*
+ * The json file must correctly specify counter 0 or counter 2 is available
+ * in the counter lists for cycle/instret events. Otherwise, the drivers have
+ * no way to figure out if a fixed counter must be used and pick a programmable
+ * counter if available.
+ */
 static int get_deleg_fixed_hw_idx(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
-	return -EINVAL;
+	struct hw_perf_event *hwc = &event->hw;
+	bool guest_events = event->attr.config1 & RISCV_PMU_CONFIG1_GUEST_EVENTS;
+
+	if (guest_events) {
+		if (hwc->event_base == SBI_PMU_HW_CPU_CYCLES)
+			return 0;
+		if (hwc->event_base == SBI_PMU_HW_INSTRUCTIONS)
+			return 2;
+		else
+			return -EINVAL;
+	}
+
+	if (!event->attr.config2)
+		return -EINVAL;
+
+	if (event->attr.config2 & RISCV_PMU_CYCLE_FIXED_CTR_MASK)
+		return 0; /* CY counter */
+	else if (event->attr.config2 & RISCV_PMU_INSTRUCTION_FIXED_CTR_MASK)
+		return 2; /* IR counter */
+	else
+		return -EINVAL;
 }
 
 static int get_deleg_next_hpm_hw_idx(struct cpu_hw_events *cpuc, struct perf_event *event)
 {
-	unsigned long hw_ctr_mask = 0;
+	u32 hw_ctr_mask = 0, temp_mask = 0;
+	u32 type = event->attr.type;
+	u64 config = event->attr.config;
+	int ret;
 
-	/*
-	 * TODO: Treat every hpmcounter can monitor every event for now.
-	 * The event to counter mapping should come from the json file.
-	 * The mapping should also tell if sampling is supported or not.
-	 */
+	/* Select only available hpmcounters */
+	hw_ctr_mask = cmask & (~0x7) & ~(cpuc->used_hw_ctrs[0]);
+
+	switch (type) {
+	case PERF_TYPE_HARDWARE:
+		temp_mask = current_pmu_hw_event_map[config].counter_mask;
+		break;
+	case PERF_TYPE_HW_CACHE:
+		ret = cdeleg_pmu_event_find_cache(config, NULL, &temp_mask);
+		if (ret)
+			return ret;
+		break;
+	case PERF_TYPE_RAW:
+		/*
+		 * Mask off the counters that can't monitor this event (specified via json)
+		 * The counter mask for this event is set in config2 via the property 'Counter'
+		 * in the json file or manual configuration of config2. If the config2 is not set,
+		 * it is assumed all the available hpmcounters can monitor this event.
+		 * Note: This assumption may fail for virtualization use case where they hypervisor
+		 * (e.g. KVM) virtualizes the counter. Any event to counter mapping provided by the
+		 * guest is meaningless from a hypervisor perspective. Thus, the hypervisor doesn't
+		 * set config2 when creating kernel counter and relies default host mapping.
+		 */
+		if (event->attr.config2)
+			temp_mask = event->attr.config2;
+		break;
+	default:
+		break;
+	}
+
+	if (temp_mask)
+		hw_ctr_mask &= temp_mask;
+
+	if (!hw_ctr_mask)
+		return -EINVAL;
 
-	/* Select only hpmcounters */
-	hw_ctr_mask = cmask & (~0x7);
-	hw_ctr_mask &= ~(cpuc->used_hw_ctrs[0]);
 	return __ffs(hw_ctr_mask);
 }
 
@@ -1526,10 +1584,6 @@ static int rvpmu_deleg_ctr_get_idx(struct perf_event *event)
 	u64 priv_filter;
 	int idx;
 
-	/*
-	 * TODO: We should not rely on SBI Perf encoding to check if the event
-	 * is a fixed one or not.
-	 */
 	if (!is_sampling_event(event)) {
 		idx = get_deleg_fixed_hw_idx(cpuc, event);
 		if (idx == 0 || idx == 2) {
@@ -1547,10 +1601,14 @@ static int rvpmu_deleg_ctr_get_idx(struct perf_event *event)
 		goto out_err;
 found_idx:
 	priv_filter = get_deleg_priv_filter_bits(event);
+	if (test_and_set_bit(idx, cpuc->used_hw_ctrs))
+		goto out_err;
 	update_deleg_hpmevent(idx, hwc->config, priv_filter);
+	return idx;
 skip_update:
-	if (!test_and_set_bit(idx, cpuc->used_hw_ctrs))
-		return idx;
+	if (test_and_set_bit(idx, cpuc->used_hw_ctrs))
+		goto out_err;
+	return idx;
 out_err:
 	return -ENOENT;
 }
diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
index f6a710c83a4c..06171e7aadfb 100644
--- a/include/linux/perf/riscv_pmu.h
+++ b/include/linux/perf/riscv_pmu.h
@@ -30,6 +30,8 @@
 #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1
 
 #define RISCV_PMU_DELEG_RAW_EVENT_MASK GENMASK_ULL(55, 0)
+#define RISCV_PMU_CYCLE_FIXED_CTR_MASK 0x01
+#define RISCV_PMU_INSTRUCTION_FIXED_CTR_MASK 0x04
 
 #define HW_OP_UNSUPPORTED		0xFFFF
 #define CACHE_OP_UNSUPPORTED		0xFFFF

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:28 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:28 -0700
Subject: [PATCH v6 14/21] RISC-V: perf: Skip PMU SBI extension when not
 implemented
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-14-285b72ed65a9@meta.com>

From: Charlie Jenkins <charlie at rivosinc.com>

When the PMU SBI extension is not implemented, sbi_v2_available should
not be set to true. The SBI implementation for counter config matching
and firmware counter read  should also be skipped when the SBI extension
is not implemented.

Signed-off-by: Atish Patra <atishp at meta.com>
Signed-off-by: Charlie Jenkins <charlie at rivosinc.com>
---
 drivers/perf/riscv_pmu_sbi.c | 48 ++++++++++++++++++++++++++------------------
 1 file changed, 28 insertions(+), 20 deletions(-)

diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 1f16df9d0dd0..5bfcd3821f57 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -479,27 +479,31 @@ static void rvpmu_sbi_check_event(struct sbi_pmu_event_data *edata)
 	}
 }
 
-static void rvpmu_sbi_check_std_events(struct work_struct *work)
+static void rvpmu_check_std_events(struct work_struct *work)
 {
 	int ret;
 
-	if (sbi_v3_available) {
-		ret = pmu_sbi_check_event_info();
-		if (ret)
-			pr_err("pmu_sbi_check_event_info failed with error %d\n", ret);
-		return;
-	}
+	if (riscv_pmu_sbi_available()) {
+		if (sbi_v3_available) {
+			ret = pmu_sbi_check_event_info();
+			if (ret)
+				pr_err("pmu_sbi_check_event_info failed with error %d\n", ret);
+			return;
+		}
 
-	for (int i = 0; i < ARRAY_SIZE(pmu_hw_event_sbi_map); i++)
-		rvpmu_sbi_check_event(&pmu_hw_event_sbi_map[i]);
+		for (int i = 0; i < ARRAY_SIZE(pmu_hw_event_sbi_map); i++)
+			rvpmu_sbi_check_event(&pmu_hw_event_sbi_map[i]);
 
-	for (int i = 0; i < ARRAY_SIZE(pmu_cache_event_sbi_map); i++)
-		for (int j = 0; j < ARRAY_SIZE(pmu_cache_event_sbi_map[i]); j++)
-			for (int k = 0; k < ARRAY_SIZE(pmu_cache_event_sbi_map[i][j]); k++)
-				rvpmu_sbi_check_event(&pmu_cache_event_sbi_map[i][j][k]);
+		for (int i = 0; i < ARRAY_SIZE(pmu_cache_event_sbi_map); i++)
+			for (int j = 0; j < ARRAY_SIZE(pmu_cache_event_sbi_map[i]); j++)
+				for (int k = 0; k < ARRAY_SIZE(pmu_cache_event_sbi_map[i][j]); k++)
+					rvpmu_sbi_check_event(&pmu_cache_event_sbi_map[i][j][k]);
+	} else {
+		DO_ONCE_LITE_IF(1, pr_info, "Boot time config matching not required for smcdeleg\n");
+	}
 }
 
-static DECLARE_WORK(check_std_events_work, rvpmu_sbi_check_std_events);
+static DECLARE_WORK(check_std_events_work, rvpmu_check_std_events);
 
 static ssize_t rvpmu_format_show(struct device *dev,
 				 struct device_attribute *attr, char *buf)
@@ -692,6 +696,9 @@ static int rvpmu_sbi_ctr_get_idx(struct perf_event *event)
 
 	cflags = rvpmu_sbi_get_filter_flags(event);
 
+	if (!riscv_pmu_sbi_available())
+		return -ENOENT;
+
 	/*
 	 * In legacy mode, we have to force the fixed counters for those events
 	 * but not in the user access mode as we want to use the other counters
@@ -967,7 +974,7 @@ static u64 rvpmu_ctr_read(struct perf_event *event)
 		return val;
 	}
 
-	if (pmu_sbi_is_fw_event(event)) {
+	if (pmu_sbi_is_fw_event(event) && riscv_pmu_sbi_available()) {
 		ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_FW_READ,
 				hwc->idx, 0, 0, 0, 0, 0);
 		if (ret.error)
@@ -2045,12 +2052,13 @@ static int __init rvpmu_devinit(void)
 	int ret;
 	struct platform_device *pdev;
 
-	if (sbi_spec_version >= sbi_mk_version(0, 3) &&
-	    sbi_probe_extension(SBI_EXT_PMU))
-		static_branch_enable(&riscv_pmu_sbi_available);
+	if (sbi_probe_extension(SBI_EXT_PMU)) {
+		if (sbi_spec_version >= sbi_mk_version(0, 3))
+			static_branch_enable(&riscv_pmu_sbi_available);
+		if (sbi_spec_version >= sbi_mk_version(2, 0))
+			sbi_v2_available = true;
+	}
 
-	if (sbi_spec_version >= sbi_mk_version(2, 0))
-		sbi_v2_available = true;
 	/*
 	 * We need all three extensions to be present to access the counters
 	 * in S-mode via Supervisor Counter delegation.

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:27 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:27 -0700
Subject: [PATCH v6 13/21] RISC-V: perf: Implement supervisor counter
 delegation support
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-13-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

There are few new RISC-V ISA exensions (ssccfg, sscsrind, smcntrpmf) which
allows the hpmcounter/hpmevents to be programmed directly from S-mode. The
implementation detects the ISA extension at runtime and uses them if
available instead of SBI PMU extension. SBI PMU extension will still be
used for firmware counters if the user requests it.

The current linux driver relies on event encoding defined by SBI PMU
specification for standard perf events. However, there are no standard
event encoding available in the ISA. In the future, we may want to
decouple the counter delegation and SBI PMU completely. In that case,
counter delegation supported platforms must rely on the event encoding
defined in the perf json file or in the pmu driver.

For firmware events, it will continue to use the SBI PMU encoding as
one can not support firmware event without SBI PMU.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 arch/riscv/include/asm/csr.h   |   1 +
 drivers/perf/riscv_pmu_sbi.c   | 574 +++++++++++++++++++++++++++++++++--------
 include/linux/perf/riscv_pmu.h |   3 +
 3 files changed, 473 insertions(+), 105 deletions(-)

diff --git a/arch/riscv/include/asm/csr.h b/arch/riscv/include/asm/csr.h
index 26cb78dee2fd..25ebf853bfef 100644
--- a/arch/riscv/include/asm/csr.h
+++ b/arch/riscv/include/asm/csr.h
@@ -266,6 +266,7 @@
 #endif
 
 #define SISELECT_SSCCFG_BASE		0x40
+#define HPMEVENT_MASK			GENMASK_ULL(63, 56)
 
 /* mseccfg bits */
 #define MSECCFG_PMM			ENVCFG_PMM
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 46a25979e95e..1f16df9d0dd0 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -27,6 +27,8 @@
 #include <asm/cpufeature.h>
 #include <asm/vendor_extensions.h>
 #include <asm/vendor_extensions/andes.h>
+#include <asm/hwcap.h>
+#include <asm/csr_ind.h>
 
 #define ALT_SBI_PMU_OVERFLOW(__ovl)					\
 asm volatile(ALTERNATIVE_2(						\
@@ -59,7 +61,20 @@ asm volatile(ALTERNATIVE(						\
 #define PERF_EVENT_FLAG_USER_ACCESS	BIT(SYSCTL_USER_ACCESS)
 #define PERF_EVENT_FLAG_LEGACY		BIT(SYSCTL_LEGACY)
 
-PMU_FORMAT_ATTR(event, "config:0-55");
+#define RVPMU_SBI_PMU_FORMAT_ATTR	"config:0-47"
+#define RVPMU_CDELEG_PMU_FORMAT_ATTR	"config:0-55"
+
+static ssize_t __maybe_unused rvpmu_format_show(struct device *dev, struct device_attribute *attr,
+						char *buf);
+
+#define RVPMU_ATTR_ENTRY(_name, _func, _config)	(			\
+	&((struct dev_ext_attribute[]) {				\
+		{ __ATTR(_name, 0444, _func, NULL), (void *)_config }	\
+	})[0].attr.attr)
+
+#define RVPMU_FORMAT_ATTR_ENTRY(_name, _config) \
+	RVPMU_ATTR_ENTRY(_name, rvpmu_format_show, (char *)_config)
+
 PMU_FORMAT_ATTR(firmware, "config:62-63");
 
 static bool sbi_v2_available;
@@ -67,7 +82,11 @@ static bool sbi_v3_available;
 static DEFINE_STATIC_KEY_FALSE(sbi_pmu_snapshot_available);
 #define sbi_pmu_snapshot_available() \
 	static_branch_unlikely(&sbi_pmu_snapshot_available)
+
 static DEFINE_STATIC_KEY_FALSE(riscv_pmu_sbi_available);
+#define riscv_pmu_sbi_available() \
+		static_branch_likely(&riscv_pmu_sbi_available)
+
 static DEFINE_STATIC_KEY_FALSE(riscv_pmu_cdeleg_available);
 
 /* Avoid unnecessary code patching in the one time booting path*/
@@ -82,19 +101,35 @@ static DEFINE_STATIC_KEY_FALSE(riscv_pmu_cdeleg_available);
 #define riscv_pmu_sbi_available() \
 		static_branch_likely(&riscv_pmu_sbi_available)
 
-static struct attribute *riscv_arch_formats_attr[] = {
-	&format_attr_event.attr,
+static struct attribute *riscv_sbi_pmu_formats_attr[] = {
+	RVPMU_FORMAT_ATTR_ENTRY(event, RVPMU_SBI_PMU_FORMAT_ATTR),
+	&format_attr_firmware.attr,
+	NULL,
+};
+
+static struct attribute_group riscv_sbi_pmu_format_group = {
+	.name = "format",
+	.attrs = riscv_sbi_pmu_formats_attr,
+};
+
+static const struct attribute_group *riscv_sbi_pmu_attr_groups[] = {
+	&riscv_sbi_pmu_format_group,
+	NULL,
+};
+
+static struct attribute *riscv_cdeleg_pmu_formats_attr[] = {
+	RVPMU_FORMAT_ATTR_ENTRY(event, RVPMU_CDELEG_PMU_FORMAT_ATTR),
 	&format_attr_firmware.attr,
 	NULL,
 };
 
-static struct attribute_group riscv_pmu_format_group = {
+static struct attribute_group riscv_cdeleg_pmu_format_group = {
 	.name = "format",
-	.attrs = riscv_arch_formats_attr,
+	.attrs = riscv_cdeleg_pmu_formats_attr,
 };
 
-static const struct attribute_group *riscv_pmu_attr_groups[] = {
-	&riscv_pmu_format_group,
+static const struct attribute_group *riscv_cdeleg_pmu_attr_groups[] = {
+	&riscv_cdeleg_pmu_format_group,
 	NULL,
 };
 
@@ -466,6 +501,14 @@ static void rvpmu_sbi_check_std_events(struct work_struct *work)
 
 static DECLARE_WORK(check_std_events_work, rvpmu_sbi_check_std_events);
 
+static ssize_t rvpmu_format_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct dev_ext_attribute *eattr = container_of(attr,
+				struct dev_ext_attribute, attr);
+	return sysfs_emit(buf, "%s\n", (char *)eattr->var);
+}
+
 static int rvpmu_ctr_get_width(int idx)
 {
 	return pmu_ctr_list[idx].width;
@@ -583,6 +626,38 @@ static uint8_t rvpmu_csr_index(struct perf_event *event)
 	return pmu_ctr_list[event->hw.idx].csr - CSR_CYCLE;
 }
 
+static uint64_t get_deleg_priv_filter_bits(struct perf_event *event)
+{
+	u64 priv_filter_bits = 0;
+	bool guest_events = false;
+
+	if (event->attr.config1 & RISCV_PMU_CONFIG1_GUEST_EVENTS)
+		guest_events = true;
+	if (event->attr.exclude_kernel)
+		priv_filter_bits |= guest_events ? HPMEVENT_VSINH : HPMEVENT_SINH;
+	if (event->attr.exclude_user)
+		priv_filter_bits |= guest_events ? HPMEVENT_VUINH : HPMEVENT_UINH;
+	if (guest_events && event->attr.exclude_hv)
+		priv_filter_bits |= HPMEVENT_SINH;
+	if (event->attr.exclude_host)
+		priv_filter_bits |= HPMEVENT_UINH | HPMEVENT_SINH;
+	if (event->attr.exclude_guest)
+		priv_filter_bits |= HPMEVENT_VSINH | HPMEVENT_VUINH;
+
+	return priv_filter_bits;
+}
+
+static bool pmu_sbi_is_fw_event(struct perf_event *event)
+{
+	u32 type = event->attr.type;
+	u64 config = event->attr.config;
+
+	if (type == PERF_TYPE_RAW && ((config >> 63) == 1))
+		return true;
+	else
+		return false;
+}
+
 static unsigned long rvpmu_sbi_get_filter_flags(struct perf_event *event)
 {
 	unsigned long cflags = 0;
@@ -611,7 +686,8 @@ static int rvpmu_sbi_ctr_get_idx(struct perf_event *event)
 	struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
 	struct sbiret ret;
 	int idx;
-	uint64_t cbase = 0, cmask = rvpmu->cmask;
+	u64 cbase = 0;
+	unsigned long ctr_mask = rvpmu->cmask;
 	unsigned long cflags = 0;
 
 	cflags = rvpmu_sbi_get_filter_flags(event);
@@ -624,21 +700,23 @@ static int rvpmu_sbi_ctr_get_idx(struct perf_event *event)
 	if ((hwc->flags & PERF_EVENT_FLAG_LEGACY) && (event->attr.type == PERF_TYPE_HARDWARE)) {
 		if (event->attr.config == PERF_COUNT_HW_CPU_CYCLES) {
 			cflags |= SBI_PMU_CFG_FLAG_SKIP_MATCH;
-			cmask = 1;
+			ctr_mask = 1;
 		} else if (event->attr.config == PERF_COUNT_HW_INSTRUCTIONS) {
 			cflags |= SBI_PMU_CFG_FLAG_SKIP_MATCH;
-			cmask = BIT(CSR_INSTRET - CSR_CYCLE);
+			ctr_mask = BIT(CSR_INSTRET - CSR_CYCLE);
 		}
+	} else if (pmu_sbi_is_fw_event(event)) {
+		ctr_mask = firmware_cmask;
 	}
 
 	/* retrieve the available counter index */
 #if defined(CONFIG_32BIT)
 	ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
-			cmask, cflags, hwc->event_base, hwc->config,
+			ctr_mask, cflags, hwc->event_base, hwc->config,
 			hwc->config >> 32);
 #else
 	ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_CFG_MATCH, cbase,
-			cmask, cflags, hwc->event_base, hwc->config, 0);
+			ctr_mask, cflags, hwc->event_base, hwc->config, 0);
 #endif
 	if (ret.error) {
 		pr_debug("Not able to find a counter for event %lx config %llx\n",
@@ -647,7 +725,7 @@ static int rvpmu_sbi_ctr_get_idx(struct perf_event *event)
 	}
 
 	idx = ret.value;
-	if (!test_bit(idx, &rvpmu->cmask) || !pmu_ctr_list[idx].value)
+	if (!test_bit(idx, &ctr_mask) || !pmu_ctr_list[idx].value)
 		return -ENOENT;
 
 	/* Additional sanity check for the counter id */
@@ -697,29 +775,96 @@ static int sbi_pmu_event_find_cache(u64 config)
 	return ret;
 }
 
-static bool pmu_sbi_is_fw_event(struct perf_event *event)
+static int rvpmu_sbi_event_map(struct perf_event *event, u64 *econfig)
 {
 	u32 type = event->attr.type;
 	u64 config = event->attr.config;
 
-	if ((type == PERF_TYPE_RAW) && ((config >> 63) == 1))
-		return true;
-	else
-		return false;
+	/*
+	 * Ensure we are finished checking standard hardware events for
+	 * validity before allowing userspace to configure any events.
+	 */
+	flush_work(&check_std_events_work);
+
+	return riscv_pmu_get_event_info(type, config, econfig);
 }
 
-static int rvpmu_sbi_event_map(struct perf_event *event, u64 *econfig)
+static int cdeleg_pmu_event_find_cache(u64 config, u64 *eventid, uint32_t *counter_mask)
+{
+	unsigned int cache_type, cache_op, cache_result;
+
+	if (!current_pmu_cache_event_map)
+		return -ENOENT;
+
+	cache_type = (config >>  0) & 0xff;
+	if (cache_type >= PERF_COUNT_HW_CACHE_MAX)
+		return -EINVAL;
+
+	cache_op = (config >>  8) & 0xff;
+	if (cache_op >= PERF_COUNT_HW_CACHE_OP_MAX)
+		return -EINVAL;
+
+	cache_result = (config >> 16) & 0xff;
+	if (cache_result >= PERF_COUNT_HW_CACHE_RESULT_MAX)
+		return -EINVAL;
+
+	if (eventid)
+		*eventid = current_pmu_cache_event_map[cache_type][cache_op]
+						      [cache_result].event_id;
+	if (counter_mask)
+		*counter_mask = current_pmu_cache_event_map[cache_type][cache_op]
+							   [cache_result].counter_mask;
+
+	return 0;
+}
+
+static int rvpmu_cdeleg_event_map(struct perf_event *event, u64 *econfig)
 {
 	u32 type = event->attr.type;
 	u64 config = event->attr.config;
+	int ret = 0;
 
 	/*
-	 * Ensure we are finished checking standard hardware events for
-	 * validity before allowing userspace to configure any events.
+	 * There are two ways standard perf events can be mapped to platform specific
+	 * encoding.
+	 * 1. The vendor may specify the encodings in the driver.
+	 * 2. The Perf tool for RISC-V may remap the standard perf event to platform
+	 * specific encoding.
+	 *
+	 * As RISC-V ISA doesn't define any standard event encoding. Thus, perf tool allows
+	 * vendor to define it via json file. The encoding defined in the json will override
+	 * the perf legacy encoding. However, some user may want to run performance
+	 * monitoring without perf tool as well. That's why, vendors may specify the event
+	 * encoding in the driver as well if they want to support that use case too.
+	 * If an encoding is defined in the json, it will be encoded as a raw event.
 	 */
-	flush_work(&check_std_events_work);
 
-	return riscv_pmu_get_event_info(type, config, econfig);
+	switch (type) {
+	case PERF_TYPE_HARDWARE:
+		if (config >= PERF_COUNT_HW_MAX)
+			return -EINVAL;
+		if (!current_pmu_hw_event_map)
+			return -ENOENT;
+
+		*econfig = current_pmu_hw_event_map[config].event_id;
+		if (*econfig == HW_OP_UNSUPPORTED)
+			ret = -ENOENT;
+		break;
+	case PERF_TYPE_HW_CACHE:
+		ret = cdeleg_pmu_event_find_cache(config, econfig, NULL);
+		if (*econfig == HW_OP_UNSUPPORTED)
+			ret = -ENOENT;
+		break;
+	case PERF_TYPE_RAW:
+		*econfig = config & RISCV_PMU_DELEG_RAW_EVENT_MASK;
+		break;
+	default:
+		ret = -ENOENT;
+		break;
+	}
+
+	/* event_base is not used for counter delegation */
+	return ret;
 }
 
 static void pmu_sbi_snapshot_free(struct riscv_pmu *pmu)
@@ -805,7 +950,7 @@ static int pmu_sbi_snapshot_setup(struct riscv_pmu *pmu, int cpu)
 	return 0;
 }
 
-static u64 rvpmu_sbi_ctr_read(struct perf_event *event)
+static u64 rvpmu_ctr_read(struct perf_event *event)
 {
 	struct hw_perf_event *hwc = &event->hw;
 	int idx = hwc->idx;
@@ -882,10 +1027,6 @@ static void rvpmu_sbi_ctr_start(struct perf_event *event, u64 ival)
 	if (ret.error && (ret.error != SBI_ERR_ALREADY_STARTED))
 		pr_err("Starting counter idx %d failed with error %d\n",
 			hwc->idx, sbi_err_map_linux_errno(ret.error));
-
-	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
-	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
-		rvpmu_set_scounteren((void *)event);
 }
 
 static void rvpmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
@@ -896,10 +1037,6 @@ static void rvpmu_sbi_ctr_stop(struct perf_event *event, unsigned long flag)
 	struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
 	struct riscv_pmu_snapshot_data *sdata = cpu_hw_evt->snapshot_addr;
 
-	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
-	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
-		rvpmu_reset_scounteren((void *)event);
-
 	if (sbi_pmu_snapshot_available())
 		flag |= SBI_PMU_STOP_FLAG_TAKE_SNAPSHOT;
 
@@ -935,12 +1072,6 @@ static int rvpmu_sbi_find_num_ctrs(void)
 		return sbi_err_map_linux_errno(ret.error);
 }
 
-static u32 rvpmu_deleg_find_ctrs(void)
-{
-	/* TODO */
-	return 0;
-}
-
 static int rvpmu_sbi_get_ctrinfo(u32 nsbi_ctr, u32 *num_fw_ctr, u32 *num_hw_ctr)
 {
 	struct sbiret ret;
@@ -1018,55 +1149,75 @@ static inline void rvpmu_sbi_stop_hw_ctrs(struct riscv_pmu *pmu)
 	}
 }
 
-/*
- * This function starts all the used counters in two step approach.
- * Any counter that did not overflow can be start in a single step
- * while the overflowed counters need to be started with updated initialization
- * value.
- */
-static inline void rvpmu_sbi_start_ovf_ctrs_sbi(struct cpu_hw_events *cpu_hw_evt,
-						u64 ctr_ovf_mask)
+static void rvpmu_deleg_ctr_start_mask(unsigned long mask)
 {
-	int idx = 0, i;
-	struct perf_event *event;
-	unsigned long flag = SBI_PMU_START_FLAG_SET_INIT_VALUE;
-	unsigned long ctr_start_mask = 0;
-	uint64_t max_period;
-	struct hw_perf_event *hwc;
-	u64 init_val = 0;
+	unsigned long scountinhibit_val = 0;
 
-	for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) {
-		ctr_start_mask = cpu_hw_evt->used_hw_ctrs[i] & ~ctr_ovf_mask;
-		/* Start all the counters that did not overflow in a single shot */
-		if (ctr_start_mask) {
-			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, i * BITS_PER_LONG,
-				  ctr_start_mask, 0, 0, 0, 0);
-		}
-	}
+	scountinhibit_val = csr_read(CSR_SCOUNTINHIBIT);
+	scountinhibit_val &= ~mask;
+
+	csr_write(CSR_SCOUNTINHIBIT, scountinhibit_val);
+}
+
+static void rvpmu_deleg_ctr_enable_irq(struct perf_event *event)
+{
+	unsigned long hpmevent_curr;
+	unsigned long of_mask;
+	struct hw_perf_event *hwc = &event->hw;
+	int counter_idx = hwc->idx;
+	unsigned long sip_val = csr_read(CSR_SIP);
+
+	if (!is_sampling_event(event) || (sip_val & SIP_LCOFIP))
+		return;
 
-	/* Reinitialize and start all the counter that overflowed */
-	while (ctr_ovf_mask) {
-		if (ctr_ovf_mask & 0x01) {
-			event = cpu_hw_evt->events[idx];
-			hwc = &event->hw;
-			max_period = riscv_pmu_ctr_get_width_mask(event);
-			init_val = local64_read(&hwc->prev_count) & max_period;
 #if defined(CONFIG_32BIT)
-			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, idx, 1,
-				  flag, init_val, init_val >> 32, 0);
+	hpmevent_curr = csr_ind_read(CSR_SIREG5, SISELECT_SSCCFG_BASE, counter_idx);
+	of_mask = (u32)~HPMEVENTH_OF;
 #else
-			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, idx, 1,
-				  flag, init_val, 0, 0);
+	hpmevent_curr = csr_ind_read(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx);
+	of_mask = ~HPMEVENT_OF;
 #endif
-			perf_event_update_userpage(event);
-		}
-		ctr_ovf_mask = ctr_ovf_mask >> 1;
-		idx++;
-	}
+
+	hpmevent_curr &= of_mask;
+#if defined(CONFIG_32BIT)
+	csr_ind_write(CSR_SIREG4, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_curr);
+#else
+	csr_ind_write(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_curr);
+#endif
+}
+
+static void rvpmu_deleg_ctr_start(struct perf_event *event, u64 ival)
+{
+	unsigned long scountinhibit_val = 0;
+	struct hw_perf_event *hwc = &event->hw;
+
+#if defined(CONFIG_32BIT)
+	csr_ind_write(CSR_SIREG, SISELECT_SSCCFG_BASE, hwc->idx, ival & 0xFFFFFFFF);
+	csr_ind_write(CSR_SIREG4, SISELECT_SSCCFG_BASE, hwc->idx, ival >> BITS_PER_LONG);
+#else
+	csr_ind_write(CSR_SIREG, SISELECT_SSCCFG_BASE, hwc->idx, ival);
+#endif
+
+	rvpmu_deleg_ctr_enable_irq(event);
+
+	scountinhibit_val = csr_read(CSR_SCOUNTINHIBIT);
+	scountinhibit_val &= ~(1 << hwc->idx);
+
+	csr_write(CSR_SCOUNTINHIBIT, scountinhibit_val);
+}
+
+static void rvpmu_deleg_ctr_stop_mask(unsigned long mask)
+{
+	unsigned long scountinhibit_val = 0;
+
+	scountinhibit_val = csr_read(CSR_SCOUNTINHIBIT);
+	scountinhibit_val |= mask;
+
+	csr_write(CSR_SCOUNTINHIBIT, scountinhibit_val);
 }
 
-static inline void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_evt,
-						     u64 ctr_ovf_mask)
+static void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_hw_evt,
+					      u64 ctr_ovf_mask)
 {
 	int i, idx = 0;
 	struct perf_event *event;
@@ -1100,15 +1251,53 @@ static inline void rvpmu_sbi_start_ovf_ctrs_snapshot(struct cpu_hw_events *cpu_h
 	}
 }
 
-static void rvpmu_sbi_start_overflow_mask(struct riscv_pmu *pmu,
-					  u64 ctr_ovf_mask)
+/*
+ * This function starts all the used counters in two step approach.
+ * Any counter that did not overflow can be start in a single step
+ * while the overflowed counters need to be started with updated initialization
+ * value.
+ */
+static void rvpmu_start_overflow_mask(struct riscv_pmu *pmu, u64 ctr_ovf_mask)
 {
+	int idx = 0, i;
+	struct perf_event *event;
+	unsigned long ctr_start_mask = 0;
+	u64 max_period, init_val = 0;
+	struct hw_perf_event *hwc;
 	struct cpu_hw_events *cpu_hw_evt = this_cpu_ptr(pmu->hw_events);
 
 	if (sbi_pmu_snapshot_available())
-		rvpmu_sbi_start_ovf_ctrs_snapshot(cpu_hw_evt, ctr_ovf_mask);
-	else
-		rvpmu_sbi_start_ovf_ctrs_sbi(cpu_hw_evt, ctr_ovf_mask);
+		return rvpmu_sbi_start_ovf_ctrs_snapshot(cpu_hw_evt, ctr_ovf_mask);
+
+	/* Start all the counters that did not overflow */
+	if (riscv_pmu_cdeleg_available()) {
+		ctr_start_mask = cpu_hw_evt->used_hw_ctrs[0] & ~ctr_ovf_mask;
+		rvpmu_deleg_ctr_start_mask(ctr_start_mask);
+	} else {
+		for (i = 0; i < BITS_TO_LONGS(RISCV_MAX_COUNTERS); i++) {
+			ctr_start_mask = cpu_hw_evt->used_hw_ctrs[i] & ~ctr_ovf_mask;
+			/* Start all the counters that did not overflow in a single shot */
+			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_START, i * BITS_PER_LONG,
+				  ctr_start_mask, 0, 0, 0, 0);
+		}
+	}
+
+	/* Reinitialize and start all the counter that overflowed */
+	while (ctr_ovf_mask) {
+		if (ctr_ovf_mask & 0x01) {
+			event = cpu_hw_evt->events[idx];
+			hwc = &event->hw;
+			max_period = riscv_pmu_ctr_get_width_mask(event);
+			init_val = local64_read(&hwc->prev_count) & max_period;
+			if (riscv_pmu_cdeleg_available())
+				rvpmu_deleg_ctr_start(event, init_val);
+			else
+				rvpmu_sbi_ctr_start(event, init_val);
+			perf_event_update_userpage(event);
+		}
+		ctr_ovf_mask = ctr_ovf_mask >> 1;
+		idx++;
+	}
 }
 
 static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
@@ -1143,10 +1332,18 @@ static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
 	}
 
 	pmu = to_riscv_pmu(event->pmu);
-	rvpmu_sbi_stop_hw_ctrs(pmu);
+	if (riscv_pmu_cdeleg_available())
+		rvpmu_deleg_ctr_stop_mask(cpu_hw_evt->used_hw_ctrs[0]);
+	else
+		rvpmu_sbi_stop_hw_ctrs(pmu);
 
-	/* Overflow status register should only be read after counter are stopped */
-	if (sbi_pmu_snapshot_available())
+	/*
+	 * Overflow status register should only be read after counter are stopped.
+	 * In counter delegation mode the overflows are reported in scountovf, not
+	 * in the SBI snapshot area, so read the CSR directly even when an SBI PMU
+	 * snapshot is also available.
+	 */
+	if (sbi_pmu_snapshot_available() && !riscv_pmu_cdeleg_available())
 		overflow = sdata->ctr_overflow_mask;
 	else
 		ALT_SBI_PMU_OVERFLOW(overflow);
@@ -1212,25 +1409,182 @@ static irqreturn_t rvpmu_ovf_handler(int irq, void *dev)
 		hw_evt->state = 0;
 	}
 
-	rvpmu_sbi_start_overflow_mask(pmu, overflowed_ctrs);
+	rvpmu_start_overflow_mask(pmu, overflowed_ctrs);
 	perf_sample_event_took(sched_clock() - start_clock);
 
 	return IRQ_HANDLED;
 }
 
+static int get_deleg_hw_ctr_width(int counter_offset)
+{
+	unsigned long hpm_warl;
+	int num_bits;
+
+	if (counter_offset < 3 || counter_offset > 31)
+		return 0;
+
+	hpm_warl = csr_ind_warl(CSR_SIREG, SISELECT_SSCCFG_BASE, counter_offset, -1);
+	num_bits = __fls(hpm_warl);
+
+#if defined(CONFIG_32BIT)
+	/*
+	 * The low half contributes a full BITS_PER_LONG bits when the counter is
+	 * wider than 32 bits; the high half's __fls() gives the remaining width.
+	 */
+	hpm_warl = csr_ind_warl(CSR_SIREG4, SISELECT_SSCCFG_BASE, counter_offset, -1);
+	if (hpm_warl)
+		num_bits = BITS_PER_LONG + __fls(hpm_warl);
+#endif
+	return num_bits;
+}
+
+static int rvpmu_deleg_find_ctrs(void)
+{
+	int i, num_hw_ctr = 0;
+	union sbi_pmu_ctr_info cinfo;
+	unsigned long scountinhibit_old = 0;
+
+	/* Do a WARL write/read to detect which hpmcounters have been delegated */
+	scountinhibit_old = csr_read(CSR_SCOUNTINHIBIT);
+	csr_write(CSR_SCOUNTINHIBIT, -1);
+	cmask = csr_read(CSR_SCOUNTINHIBIT);
+
+	csr_write(CSR_SCOUNTINHIBIT, scountinhibit_old);
+
+	for_each_set_bit(i, &cmask, RISCV_MAX_HW_COUNTERS) {
+		if (unlikely(i == 1))
+			continue; /* This should never happen as TM is read only */
+		cinfo.value = 0;
+		cinfo.type = SBI_PMU_CTR_TYPE_HW;
+		/*
+		 * If counter delegation is enabled, the csr stored to the cinfo will
+		 * be a virtual counter that the delegation attempts to read.
+		 */
+		cinfo.csr = CSR_CYCLE + i;
+		if (i == 0 || i == 2)
+			cinfo.width = 63;
+		else
+			cinfo.width = get_deleg_hw_ctr_width(i);
+
+		num_hw_ctr++;
+		pmu_ctr_list[i].value = cinfo.value;
+	}
+
+	return num_hw_ctr;
+}
+
+static int get_deleg_fixed_hw_idx(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+	return -EINVAL;
+}
+
+static int get_deleg_next_hpm_hw_idx(struct cpu_hw_events *cpuc, struct perf_event *event)
+{
+	unsigned long hw_ctr_mask = 0;
+
+	/*
+	 * TODO: Treat every hpmcounter can monitor every event for now.
+	 * The event to counter mapping should come from the json file.
+	 * The mapping should also tell if sampling is supported or not.
+	 */
+
+	/* Select only hpmcounters */
+	hw_ctr_mask = cmask & (~0x7);
+	hw_ctr_mask &= ~(cpuc->used_hw_ctrs[0]);
+	return __ffs(hw_ctr_mask);
+}
+
+static void update_deleg_hpmevent(int counter_idx, uint64_t event_value, uint64_t filter_bits)
+{
+	u64 hpmevent_value = 0;
+
+	/* OF bit should be enable during the start if sampling is requested */
+	hpmevent_value = (event_value & ~HPMEVENT_MASK) | filter_bits | HPMEVENT_OF;
+#if defined(CONFIG_32BIT)
+	csr_ind_write(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_value & 0xFFFFFFFF);
+	if (riscv_isa_extension_available(NULL, SSCOFPMF))
+		csr_ind_write(CSR_SIREG5, SISELECT_SSCCFG_BASE, counter_idx,
+			      hpmevent_value >> BITS_PER_LONG);
+#else
+	csr_ind_write(CSR_SIREG2, SISELECT_SSCCFG_BASE, counter_idx, hpmevent_value);
+#endif
+}
+
+static int rvpmu_deleg_ctr_get_idx(struct perf_event *event)
+{
+	struct hw_perf_event *hwc = &event->hw;
+	struct riscv_pmu *rvpmu = to_riscv_pmu(event->pmu);
+	struct cpu_hw_events *cpuc = this_cpu_ptr(rvpmu->hw_events);
+	unsigned long hw_ctr_max_id;
+	u64 priv_filter;
+	int idx;
+
+	/*
+	 * TODO: We should not rely on SBI Perf encoding to check if the event
+	 * is a fixed one or not.
+	 */
+	if (!is_sampling_event(event)) {
+		idx = get_deleg_fixed_hw_idx(cpuc, event);
+		if (idx == 0 || idx == 2) {
+			/* Priv mode filter bits are only available if smcntrpmf is present */
+			if (riscv_isa_extension_available(NULL, SMCNTRPMF))
+				goto found_idx;
+			else
+				goto skip_update;
+		}
+	}
+
+	hw_ctr_max_id = __fls(cmask);
+	idx = get_deleg_next_hpm_hw_idx(cpuc, event);
+	if (idx < 3 || idx > hw_ctr_max_id)
+		goto out_err;
+found_idx:
+	priv_filter = get_deleg_priv_filter_bits(event);
+	update_deleg_hpmevent(idx, hwc->config, priv_filter);
+skip_update:
+	if (!test_and_set_bit(idx, cpuc->used_hw_ctrs))
+		return idx;
+out_err:
+	return -ENOENT;
+}
+
 static void rvpmu_ctr_start(struct perf_event *event, u64 ival)
 {
-	rvpmu_sbi_ctr_start(event, ival);
-	/* TODO: Counter delegation implementation */
+	struct hw_perf_event *hwc = &event->hw;
+
+	if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
+		rvpmu_deleg_ctr_start(event, ival);
+	else
+		rvpmu_sbi_ctr_start(event, ival);
+
+	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
+	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
+		rvpmu_set_scounteren((void *)event);
 }
 
 static void rvpmu_ctr_stop(struct perf_event *event, unsigned long flag)
 {
-	rvpmu_sbi_ctr_stop(event, flag);
-	/* TODO: Counter delegation implementation */
+	struct hw_perf_event *hwc = &event->hw;
+
+	if ((hwc->flags & PERF_EVENT_FLAG_USER_ACCESS) &&
+	    (hwc->flags & PERF_EVENT_FLAG_USER_READ_CNT))
+		rvpmu_reset_scounteren((void *)event);
+
+	if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event)) {
+		/*
+		 * The counter is already stopped. No need to stop again. Counter
+		 * mapping will be reset in clear_idx function.
+		 */
+		if (flag != RISCV_PMU_STOP_FLAG_RESET)
+			rvpmu_deleg_ctr_stop_mask((1 << hwc->idx));
+		else
+			update_deleg_hpmevent(hwc->idx, 0, 0);
+	} else {
+		rvpmu_sbi_ctr_stop(event, flag);
+	}
 }
 
-static int rvpmu_find_ctrs(void)
+static u32 rvpmu_find_ctrs(void)
 {
 	u32 num_sbi_counters = 0, num_deleg_counters = 0;
 	u32 num_hw_ctr = 0, num_fw_ctr = 0, num_ctr = 0;
@@ -1270,20 +1624,18 @@ static int rvpmu_find_ctrs(void)
 
 static int rvpmu_event_map(struct perf_event *event, u64 *econfig)
 {
-	return rvpmu_sbi_event_map(event, econfig);
-	/* TODO: Counter delegation implementation */
+	if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
+		return rvpmu_cdeleg_event_map(event, econfig);
+	else
+		return rvpmu_sbi_event_map(event, econfig);
 }
 
 static int rvpmu_ctr_get_idx(struct perf_event *event)
 {
-	return rvpmu_sbi_ctr_get_idx(event);
-	/* TODO: Counter delegation implementation */
-}
-
-static u64 rvpmu_ctr_read(struct perf_event *event)
-{
-	return rvpmu_sbi_ctr_read(event);
-	/* TODO: Counter delegation implementation */
+	if (riscv_pmu_cdeleg_available() && !pmu_sbi_is_fw_event(event))
+		return rvpmu_deleg_ctr_get_idx(event);
+	else
+		return rvpmu_sbi_ctr_get_idx(event);
 }
 
 static int rvpmu_starting_cpu(unsigned int cpu, struct hlist_node *node)
@@ -1301,7 +1653,16 @@ static int rvpmu_starting_cpu(unsigned int cpu, struct hlist_node *node)
 		csr_write(CSR_SCOUNTEREN, 0x2);
 
 	/* Stop all the counters so that they can be enabled from perf */
-	rvpmu_sbi_stop_all(pmu);
+	if (riscv_pmu_cdeleg_available()) {
+		rvpmu_deleg_ctr_stop_mask(cmask);
+		if (riscv_pmu_sbi_available()) {
+			/* Stop the firmware counters as well */
+			sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_STOP, 0, firmware_cmask,
+				  0, 0, 0, 0);
+		}
+	} else {
+		rvpmu_sbi_stop_all(pmu);
+	}
 
 	if (riscv_pmu_use_irq) {
 		cpu_hw_evt->irq = riscv_pmu_irq;
@@ -1600,8 +1961,11 @@ static int rvpmu_device_probe(struct platform_device *pdev)
 		pmu->pmu.capabilities |= PERF_PMU_CAP_NO_EXCLUDE;
 	}
 
-	pmu->pmu.attr_groups = riscv_pmu_attr_groups;
 	pmu->pmu.parent = &pdev->dev;
+	if (riscv_pmu_cdeleg_available_boot())
+		pmu->pmu.attr_groups = riscv_cdeleg_pmu_attr_groups;
+	else
+		pmu->pmu.attr_groups = riscv_sbi_pmu_attr_groups;
 	pmu->cmask = cmask;
 	pmu->ctr_start = rvpmu_ctr_start;
 	pmu->ctr_stop = rvpmu_ctr_stop;
diff --git a/include/linux/perf/riscv_pmu.h b/include/linux/perf/riscv_pmu.h
index 6c75106989b6..f6a710c83a4c 100644
--- a/include/linux/perf/riscv_pmu.h
+++ b/include/linux/perf/riscv_pmu.h
@@ -20,6 +20,7 @@
  */
 
 #define RISCV_MAX_COUNTERS	64
+#define RISCV_MAX_HW_COUNTERS	32
 #define RISCV_OP_UNSUPP		(-EOPNOTSUPP)
 #define RISCV_PMU_SBI_PDEV_NAME	"riscv-pmu-sbi"
 #define RISCV_PMU_LEGACY_PDEV_NAME	"riscv-pmu-legacy"
@@ -28,6 +29,8 @@
 
 #define RISCV_PMU_CONFIG1_GUEST_EVENTS 0x1
 
+#define RISCV_PMU_DELEG_RAW_EVENT_MASK GENMASK_ULL(55, 0)
+
 #define HW_OP_UNSUPPORTED		0xFFFF
 #define CACHE_OP_UNSUPPORTED		0xFFFF
 

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:30 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:30 -0700
Subject: [PATCH v6 16/21] RISC-V: perf: Add legacy event encodings via
 sysfs
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-16-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

Define sysfs details for the legacy events so that any tool can
parse these to understand the minimum set of legacy events
supported by the platform. The sysfs entry will describe both event
encoding and corresponding counter map so that an perf event can be
programmed accordingly.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 drivers/perf/riscv_pmu_sbi.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 4b4f151a0744..00b84b28117a 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -130,7 +130,20 @@ static struct attribute_group riscv_cdeleg_pmu_format_group = {
 	.attrs = riscv_cdeleg_pmu_formats_attr,
 };
 
+#define RVPMU_EVENT_ATTR_RESOLVE(m) #m
+#define RVPMU_EVENT_CMASK_ATTR(_name, _var, config, mask) \
+	PMU_EVENT_ATTR_STRING(_name, rvpmu_event_attr_##_var, \
+			      "event=" RVPMU_EVENT_ATTR_RESOLVE(config) \
+			      ",counterid_mask=" RVPMU_EVENT_ATTR_RESOLVE(mask))
+
+#define RVPMU_EVENT_ATTR_PTR(name) (&rvpmu_event_attr_##name.attr.attr)
+
+static struct attribute_group riscv_cdeleg_pmu_event_group __ro_after_init = {
+	.name = "events",
+};
+
 static const struct attribute_group *riscv_cdeleg_pmu_attr_groups[] = {
+	&riscv_cdeleg_pmu_event_group,
 	&riscv_cdeleg_pmu_format_group,
 	NULL,
 };
@@ -431,11 +444,14 @@ struct riscv_vendor_pmu_events {
 	const struct riscv_pmu_event *hw_event_map;
 	const struct riscv_pmu_event (*cache_event_map)[PERF_COUNT_HW_CACHE_OP_MAX]
 						       [PERF_COUNT_HW_CACHE_RESULT_MAX];
+	struct attribute **attrs_events;
 };
 
-#define RISCV_VENDOR_PMU_EVENTS(_vendorid, _archid, _implid, _hw_event_map, _cache_event_map) \
+#define RISCV_VENDOR_PMU_EVENTS(_vendorid, _archid, _implid, _hw_event_map, \
+				_cache_event_map, _attrs) \
 	{ .vendorid = _vendorid, .archid = _archid, .implid = _implid, \
-	  .hw_event_map = _hw_event_map, .cache_event_map = _cache_event_map },
+	  .hw_event_map = _hw_event_map, .cache_event_map = _cache_event_map, \
+	  .attrs_events = _attrs },
 
 static struct riscv_vendor_pmu_events pmu_vendor_events_table[] = {
 };
@@ -457,6 +473,8 @@ static void rvpmu_vendor_register_events(void)
 		    pmu_vendor_events_table[i].archid == arch_id) {
 			current_pmu_hw_event_map = pmu_vendor_events_table[i].hw_event_map;
 			current_pmu_cache_event_map = pmu_vendor_events_table[i].cache_event_map;
+			riscv_cdeleg_pmu_event_group.attrs =
+							pmu_vendor_events_table[i].attrs_events;
 			break;
 		}
 	}

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:25 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:25 -0700
Subject: [PATCH v6 11/21] RISC-V: perf: Modify the counter discovery
 mechanism
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-11-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

If both counter delegation and SBI PMU is present, the counter
delegation will be used for hardware pmu counters while the SBI PMU
will be used for firmware counters. Thus, the driver has to probe
the counters info via SBI PMU to distinguish the firmware counters.

The hybrid scheme also requires improvements of the informational
logging messages to indicate the user about underlying interface
used for each use case.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 drivers/perf/riscv_pmu_sbi.c | 131 ++++++++++++++++++++++++++++++++-----------
 1 file changed, 97 insertions(+), 34 deletions(-)

diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 7f21c16003f0..57ab15beab3e 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -67,6 +67,20 @@ static bool sbi_v3_available;
 static DEFINE_STATIC_KEY_FALSE(sbi_pmu_snapshot_available);
 #define sbi_pmu_snapshot_available() \
 	static_branch_unlikely(&sbi_pmu_snapshot_available)
+static DEFINE_STATIC_KEY_FALSE(riscv_pmu_sbi_available);
+static DEFINE_STATIC_KEY_FALSE(riscv_pmu_cdeleg_available);
+
+/* Avoid unnecessary code patching in the one time booting path*/
+#define riscv_pmu_cdeleg_available_boot() \
+	static_key_enabled(&riscv_pmu_cdeleg_available)
+#define riscv_pmu_sbi_available_boot() \
+	static_key_enabled(&riscv_pmu_sbi_available)
+
+/* Perform a runtime code patching with static key */
+#define riscv_pmu_cdeleg_available() \
+	static_branch_unlikely(&riscv_pmu_cdeleg_available)
+#define riscv_pmu_sbi_available() \
+		static_branch_likely(&riscv_pmu_sbi_available)
 
 static struct attribute *riscv_arch_formats_attr[] = {
 	&format_attr_event.attr,
@@ -89,7 +103,8 @@ static int sysctl_perf_user_access __read_mostly = SYSCTL_USER_ACCESS;
 
 /*
  * This structure is SBI specific but counter delegation also require counter
- * width, csr mapping. Reuse it for now.
+ * width, csr mapping. Reuse it for now we can have firmware counters for
+ * platfroms with counter delegation support.
  * RISC-V doesn't have heterogeneous harts yet. This need to be part of
  * per_cpu in case of harts with different pmu counters
  */
@@ -101,6 +116,8 @@ static unsigned int riscv_pmu_irq;
 
 /* Cache the available counters in a bitmask */
 static unsigned long cmask;
+/* Cache the available firmware counters in another bitmask */
+static unsigned long firmware_cmask;
 
 static int sbi_pmu_event_find_cache(u64 config);
 struct sbi_pmu_event_data {
@@ -868,34 +885,38 @@ static int rvpmu_sbi_find_num_ctrs(void)
 		return sbi_err_map_linux_errno(ret.error);
 }
 
-static int rvpmu_sbi_get_ctrinfo(int nctr, unsigned long *mask)
+static u32 rvpmu_deleg_find_ctrs(void)
+{
+	/* TODO */
+	return 0;
+}
+
+static int rvpmu_sbi_get_ctrinfo(u32 nsbi_ctr, u32 *num_fw_ctr, u32 *num_hw_ctr)
 {
 	struct sbiret ret;
-	int i, num_hw_ctr = 0, num_fw_ctr = 0;
+	int i;
 	union sbi_pmu_ctr_info cinfo;
 
-	pmu_ctr_list = kzalloc_objs(*pmu_ctr_list, nctr);
-	if (!pmu_ctr_list)
-		return -ENOMEM;
-
-	for (i = 0; i < nctr; i++) {
+	for (i = 0; i < nsbi_ctr; i++) {
 		ret = sbi_ecall(SBI_EXT_PMU, SBI_EXT_PMU_COUNTER_GET_INFO, i, 0, 0, 0, 0, 0);
 		if (ret.error)
 			/* The logical counter ids are not expected to be contiguous */
 			continue;
 
-		*mask |= BIT(i);
-
 		cinfo.value = ret.value;
-		if (cinfo.type == SBI_PMU_CTR_TYPE_FW)
-			num_fw_ctr++;
-		else
-			num_hw_ctr++;
-		pmu_ctr_list[i].value = cinfo.value;
+		if (cinfo.type == SBI_PMU_CTR_TYPE_FW) {
+			/* Track firmware counters in a different mask */
+			firmware_cmask |= BIT(i);
+			pmu_ctr_list[i].value = cinfo.value;
+			*num_fw_ctr = *num_fw_ctr + 1;
+		} else if (cinfo.type == SBI_PMU_CTR_TYPE_HW &&
+			   !riscv_pmu_cdeleg_available_boot()) {
+			*num_hw_ctr = *num_hw_ctr + 1;
+			cmask |= BIT(i);
+			pmu_ctr_list[i].value = cinfo.value;
+		}
 	}
 
-	pr_info("%d firmware and %d hardware counters\n", num_fw_ctr, num_hw_ctr);
-
 	return 0;
 }
 
@@ -1159,16 +1180,42 @@ static void rvpmu_ctr_stop(struct perf_event *event, unsigned long flag)
 	/* TODO: Counter delegation implementation */
 }
 
-static int rvpmu_find_num_ctrs(void)
+static int rvpmu_find_ctrs(void)
 {
-	return rvpmu_sbi_find_num_ctrs();
-	/* TODO: Counter delegation implementation */
-}
+	u32 num_sbi_counters = 0, num_deleg_counters = 0;
+	u32 num_hw_ctr = 0, num_fw_ctr = 0, num_ctr = 0;
+	/*
+	 * We don't know how many firmware counters are available. Just allocate
+	 * for maximum counters the driver can support. The default is 64 anyways.
+	 */
+	pmu_ctr_list = kcalloc(RISCV_MAX_COUNTERS, sizeof(*pmu_ctr_list),
+			       GFP_KERNEL);
+	if (!pmu_ctr_list)
+		return -ENOMEM;
 
-static int rvpmu_get_ctrinfo(int nctr, unsigned long *mask)
-{
-	return rvpmu_sbi_get_ctrinfo(nctr, mask);
-	/* TODO: Counter delegation implementation */
+	if (riscv_pmu_cdeleg_available_boot())
+		num_deleg_counters = rvpmu_deleg_find_ctrs();
+
+	/* This is required for firmware counters even if the above is true */
+	if (riscv_pmu_sbi_available_boot())
+		num_sbi_counters = rvpmu_sbi_find_num_ctrs();
+
+	if (num_sbi_counters > RISCV_MAX_COUNTERS || num_deleg_counters > RISCV_MAX_COUNTERS)
+		return -ENOSPC;
+
+	/* cache all the information about counters now */
+	if (riscv_pmu_sbi_available_boot())
+		rvpmu_sbi_get_ctrinfo(num_sbi_counters, &num_fw_ctr, &num_hw_ctr);
+
+	if (riscv_pmu_cdeleg_available_boot()) {
+		pr_info("%u firmware and %u hardware counters\n", num_fw_ctr, num_deleg_counters);
+		num_ctr = num_fw_ctr + num_deleg_counters;
+	} else {
+		pr_info("%u firmware and %u hardware counters\n", num_fw_ctr, num_hw_ctr);
+		num_ctr = num_sbi_counters;
+	}
+
+	return num_ctr;
 }
 
 static int rvpmu_event_map(struct perf_event *event, u64 *econfig)
@@ -1469,12 +1516,21 @@ static int rvpmu_device_probe(struct platform_device *pdev)
 	int ret = -ENODEV;
 	int num_counters;
 
-	pr_info("SBI PMU extension is available\n");
+	if (riscv_pmu_cdeleg_available_boot()) {
+		pr_info("hpmcounters will use the counter delegation ISA extension\n");
+		if (riscv_pmu_sbi_available_boot())
+			pr_info("Firmware counters will use SBI PMU extension\n");
+		else
+			pr_info("Firmware counters will not be available as SBI PMU extension is not present\n");
+	} else if (riscv_pmu_sbi_available_boot()) {
+		pr_info("Both hpmcounters and firmware counters will use SBI PMU extension\n");
+	}
+
 	pmu = riscv_pmu_alloc();
 	if (!pmu)
 		return -ENOMEM;
 
-	num_counters = rvpmu_find_num_ctrs();
+	num_counters = rvpmu_find_ctrs();
 	if (num_counters < 0) {
 		pr_err("SBI PMU extension doesn't provide any counters\n");
 		goto out_free;
@@ -1486,9 +1542,6 @@ static int rvpmu_device_probe(struct platform_device *pdev)
 		pr_info("SBI returned more than maximum number of counters. Limiting the number of counters to %d\n", num_counters);
 	}
 
-	/* cache all the information about counters now */
-	if (rvpmu_get_ctrinfo(num_counters, &cmask))
-		goto out_free;
 
 	ret = rvpmu_setup_irqs(pmu, pdev);
 	if (ret < 0) {
@@ -1578,13 +1631,23 @@ static int __init rvpmu_devinit(void)
 	int ret;
 	struct platform_device *pdev;
 
-	if (sbi_spec_version < sbi_mk_version(0, 3) ||
-	    !sbi_probe_extension(SBI_EXT_PMU)) {
-		return 0;
-	}
+	if (sbi_spec_version >= sbi_mk_version(0, 3) &&
+	    sbi_probe_extension(SBI_EXT_PMU))
+		static_branch_enable(&riscv_pmu_sbi_available);
 
 	if (sbi_spec_version >= sbi_mk_version(2, 0))
 		sbi_v2_available = true;
+	/*
+	 * We need all three extensions to be present to access the counters
+	 * in S-mode via Supervisor Counter delegation.
+	 */
+	if (riscv_isa_extension_available(NULL, SSCCFG) &&
+	    riscv_isa_extension_available(NULL, SMCDELEG) &&
+	    riscv_isa_extension_available(NULL, SSCSRIND))
+		static_branch_enable(&riscv_pmu_cdeleg_available);
+
+	if (!(riscv_pmu_sbi_available_boot() || riscv_pmu_cdeleg_available_boot()))
+		return 0;
 
 	if (sbi_spec_version >= sbi_mk_version(3, 0))
 		sbi_v3_available = true;

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:31 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:31 -0700
Subject: [PATCH v6 17/21] RISC-V: perf: Add Qemu virt machine events
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-17-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

Qemu virt machine supports a very minimal set of legacy perf events.
Add them to the vendor table so that users can use them when
counter delegation is enabled.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 arch/riscv/include/asm/vendorid_list.h |  4 ++++
 drivers/perf/riscv_pmu_sbi.c           | 36 ++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/arch/riscv/include/asm/vendorid_list.h b/arch/riscv/include/asm/vendorid_list.h
index 7f5030ee1fcf..603aa2b21c0b 100644
--- a/arch/riscv/include/asm/vendorid_list.h
+++ b/arch/riscv/include/asm/vendorid_list.h
@@ -11,4 +11,8 @@
 #define SIFIVE_VENDOR_ID	0x489
 #define THEAD_VENDOR_ID		0x5b7
 
+#define QEMU_VIRT_VENDOR_ID		0x000
+#define QEMU_VIRT_IMPL_ID		0x000
+#define QEMU_VIRT_ARCH_ID		0x000
+
 #endif
diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 00b84b28117a..74acac54328e 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -26,6 +26,7 @@
 #include <asm/sbi.h>
 #include <asm/cpufeature.h>
 #include <asm/vendor_extensions.h>
+#include <asm/vendorid_list.h>
 #include <asm/vendor_extensions/andes.h>
 #include <asm/hwcap.h>
 #include <asm/csr_ind.h>
@@ -453,7 +454,42 @@ struct riscv_vendor_pmu_events {
 	  .hw_event_map = _hw_event_map, .cache_event_map = _cache_event_map, \
 	  .attrs_events = _attrs },
 
+/* QEMU virt PMU events */
+static const struct riscv_pmu_event qemu_virt_hw_event_map[PERF_COUNT_HW_MAX] = {
+	PERF_MAP_ALL_UNSUPPORTED,
+	[PERF_COUNT_HW_CPU_CYCLES]		= {0x01, 0xFFFFFFF8},
+	[PERF_COUNT_HW_INSTRUCTIONS]		= {0x02, 0xFFFFFFF8}
+};
+
+static const struct riscv_pmu_event qemu_virt_cache_event_map[PERF_COUNT_HW_CACHE_MAX]
+						[PERF_COUNT_HW_CACHE_OP_MAX]
+						[PERF_COUNT_HW_CACHE_RESULT_MAX] = {
+	PERF_CACHE_MAP_ALL_UNSUPPORTED,
+	[C(DTLB)][C(OP_READ)][C(RESULT_MISS)]	= {0x10019, 0xFFFFFFF8},
+	[C(DTLB)][C(OP_WRITE)][C(RESULT_MISS)]	= {0x1001B, 0xFFFFFFF8},
+
+	[C(ITLB)][C(OP_READ)][C(RESULT_MISS)]	= {0x10021, 0xFFFFFFF8},
+};
+
+RVPMU_EVENT_CMASK_ATTR(cycles, cycles, 0x01, 0xFFFFFFF8);
+RVPMU_EVENT_CMASK_ATTR(instructions, instructions, 0x02, 0xFFFFFFF8);
+RVPMU_EVENT_CMASK_ATTR(dTLB-load-misses, dTLB_load_miss, 0x10019, 0xFFFFFFF8);
+RVPMU_EVENT_CMASK_ATTR(dTLB-store-misses, dTLB_store_miss, 0x1001B, 0xFFFFFFF8);
+RVPMU_EVENT_CMASK_ATTR(iTLB-load-misses, iTLB_load_miss, 0x10021, 0xFFFFFFF8);
+
+static struct attribute *qemu_virt_event_group[] = {
+	RVPMU_EVENT_ATTR_PTR(cycles),
+	RVPMU_EVENT_ATTR_PTR(instructions),
+	RVPMU_EVENT_ATTR_PTR(dTLB_load_miss),
+	RVPMU_EVENT_ATTR_PTR(dTLB_store_miss),
+	RVPMU_EVENT_ATTR_PTR(iTLB_load_miss),
+	NULL,
+};
+
 static struct riscv_vendor_pmu_events pmu_vendor_events_table[] = {
+	RISCV_VENDOR_PMU_EVENTS(QEMU_VIRT_VENDOR_ID, QEMU_VIRT_ARCH_ID, QEMU_VIRT_IMPL_ID,
+				qemu_virt_hw_event_map, qemu_virt_cache_event_map,
+				qemu_virt_event_group)
 };
 
 static const struct riscv_pmu_event *current_pmu_hw_event_map;

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:32 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:32 -0700
Subject: [PATCH v6 18/21] tools/perf: Support event code for arch standard
 events
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-18-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

RISC-V relies on the event encoding from the json file. That includes
arch standard events. If event code is present, event is already updated
with correct encoding. No need to update it again which results in losing
the event encoding.

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 tools/perf/pmu-events/arch/riscv/arch-standard.json | 10 ++++++++++
 tools/perf/pmu-events/jevents.py                    |  6 +++++-
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/tools/perf/pmu-events/arch/riscv/arch-standard.json b/tools/perf/pmu-events/arch/riscv/arch-standard.json
new file mode 100644
index 000000000000..96e21f088558
--- /dev/null
+++ b/tools/perf/pmu-events/arch/riscv/arch-standard.json
@@ -0,0 +1,10 @@
+[
+  {
+    "EventName": "cycles",
+    "BriefDescription": "cycle executed"
+  },
+  {
+    "EventName": "instructions",
+    "BriefDescription": "instruction retired"
+  }
+]
diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 3a1bcdcdc685..457fce7a5982 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -413,7 +413,11 @@ class JsonEvent:
         self.long_desc = None
     if arch_std:
       if arch_std.lower() in _arch_std_events:
-        event = _arch_std_events[arch_std.lower()].event
+        # If the JSON event already specified an event code, the encoding has
+        # been set above; don't overwrite it with the arch standard event or
+        # the event encoding would be lost.
+        if not eventcode:
+          event = _arch_std_events[arch_std.lower()].event
         # Copy from the architecture standard event to self for undefined fields.
         for attr, value in _arch_std_events[arch_std.lower()].__dict__.items():
           if hasattr(self, attr) and not getattr(self, attr):

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:33 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:33 -0700
Subject: [PATCH v6 19/21] tools/perf: Add RISC-V CounterIDMask event field
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-19-285b72ed65a9@meta.com>

From: Atish Patra <atishp at rivosinc.com>

Counter delegation lets supervisor mode choose the hpmcounter for an event,
but the hardware may only allow a given event on a subset of counters. Add a
RISC-V specific "CounterIDMask" json event field, handled like the other
arch-specific entries in event_fields[], that carries the allowed-counter
bitmask through to the driver's existing counterid_mask (config2:0-31) format.

The value is the bitmask directly so no counter-list to bitmask conversion is
needed, and because the field is RISC-V specific it is a no-op for every other
architecture's events (unlike the shared "Counter" field).

Signed-off-by: Atish Patra <atishp at rivosinc.com>
---
 tools/perf/pmu-events/jevents.py | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/perf/pmu-events/jevents.py b/tools/perf/pmu-events/jevents.py
index 457fce7a5982..c1ed8a05c9a4 100755
--- a/tools/perf/pmu-events/jevents.py
+++ b/tools/perf/pmu-events/jevents.py
@@ -396,6 +396,7 @@ class JsonEvent:
         ('EnAllSlices', 'enallslices='),
         ('SliceId', 'sliceid='),
         ('ThreadMask', 'threadmask='),
+        ('CounterIDMask', 'counterid_mask='),
     ]
     for key, value in event_fields:
       if key in jd and not is_zero(jd[key]):

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:34 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:34 -0700
Subject: [PATCH v6 20/21] TEST(do-not-upstream): fake qemu-virt PMU events
 for cdeleg counter-mask testing
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-20-285b72ed65a9@meta.com>

From: Atish Patra <atishp at meta.com>

Adds fake-any/fake-ctr3/fake-ctr34 (event codes 0xF0x QEMU doesn't model) with
counterid_masks, to exercise the counter-delegation allocation + counter-mask
constraint in QEMU (events read 0 = allocated/programmed, vs 'not supported').

Signed-off-by: Atish Patra <atishp at meta.com>
---
 drivers/perf/riscv_pmu_sbi.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/perf/riscv_pmu_sbi.c b/drivers/perf/riscv_pmu_sbi.c
index 74acac54328e..3c0829c0a42a 100644
--- a/drivers/perf/riscv_pmu_sbi.c
+++ b/drivers/perf/riscv_pmu_sbi.c
@@ -476,6 +476,12 @@ RVPMU_EVENT_CMASK_ATTR(instructions, instructions, 0x02, 0xFFFFFFF8);
 RVPMU_EVENT_CMASK_ATTR(dTLB-load-misses, dTLB_load_miss, 0x10019, 0xFFFFFFF8);
 RVPMU_EVENT_CMASK_ATTR(dTLB-store-misses, dTLB_store_miss, 0x1001B, 0xFFFFFFF8);
 RVPMU_EVENT_CMASK_ATTR(iTLB-load-misses, iTLB_load_miss, 0x10021, 0xFFFFFFF8);
+/*
+ * FAKE events for cdeleg mechanism testing: event codes QEMU does NOT model.
+ */
+RVPMU_EVENT_CMASK_ATTR(fake-any, fake_any, 0xF00, 0xFFFFFFF8);
+RVPMU_EVENT_CMASK_ATTR(fake-ctr3, fake_ctr3, 0xF01, 0x8);
+RVPMU_EVENT_CMASK_ATTR(fake-ctr34, fake_ctr34, 0xF02, 0x18);
 
 static struct attribute *qemu_virt_event_group[] = {
 	RVPMU_EVENT_ATTR_PTR(cycles),
@@ -483,6 +489,9 @@ static struct attribute *qemu_virt_event_group[] = {
 	RVPMU_EVENT_ATTR_PTR(dTLB_load_miss),
 	RVPMU_EVENT_ATTR_PTR(dTLB_store_miss),
 	RVPMU_EVENT_ATTR_PTR(iTLB_load_miss),
+	RVPMU_EVENT_ATTR_PTR(fake_any),
+	RVPMU_EVENT_ATTR_PTR(fake_ctr3),
+	RVPMU_EVENT_ATTR_PTR(fake_ctr34),
 	NULL,
 };
 

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun  8 23:01:35 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 08 Jun 2026 23:01:35 -0700
Subject: [PATCH v6 21/21] TEST(do-not-upstream): fake qemu vendor JSON +
 mapfile entry for CounterIDMask path
In-Reply-To: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
References: <20260608-counter_delegation-v6-0-285b72ed65a9@meta.com>
Message-ID: <20260608-counter_delegation-v6-21-285b72ed65a9@meta.com>

From: Atish Patra <atishp at meta.com>

arch/riscv/qemu/virt/events.json: fake-json-{any,ctr3,ctr34,ctr6} with EventCode
+ CounterIDMask; mapfile.csv: 0x0-0x0-0x0 -> qemu/virt. Exercises jevents
CounterIDMask -> counterid_mask= -> config2 -> cdeleg counter allocation.

Signed-off-by: Atish Patra <atishp at meta.com>
---
 tools/perf/pmu-events/arch/riscv/mapfile.csv       |  1 +
 .../pmu-events/arch/riscv/qemu/virt/events.json    | 26 ++++++++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/tools/perf/pmu-events/arch/riscv/mapfile.csv b/tools/perf/pmu-events/arch/riscv/mapfile.csv
index 87cfb0e0849f..3533a8c0253f 100644
--- a/tools/perf/pmu-events/arch/riscv/mapfile.csv
+++ b/tools/perf/pmu-events/arch/riscv/mapfile.csv
@@ -24,3 +24,4 @@
 0x602-0x3-0x0,v1,openhwgroup/cva6,core
 0x67e-0x80000000db0000[89]0-0x[[:xdigit:]]+,v1,starfive/dubhe-80,core
 0x31e-0x8000000000008a45-0x[[:xdigit:]]+,v1,andes/ax45,core
+0x0-0x0-0x0,v1,qemu/virt,core
diff --git a/tools/perf/pmu-events/arch/riscv/qemu/virt/events.json b/tools/perf/pmu-events/arch/riscv/qemu/virt/events.json
new file mode 100644
index 000000000000..294c4ed645f6
--- /dev/null
+++ b/tools/perf/pmu-events/arch/riscv/qemu/virt/events.json
@@ -0,0 +1,26 @@
+[
+  {
+    "EventName": "fake-json-any",
+    "EventCode": "0xF10",
+    "CounterIDMask": "0xFFFFFFF8",
+    "BriefDescription": "FAKE json event (any hpmcounter 3-31) - QEMU does not model 0xF10"
+  },
+  {
+    "EventName": "fake-json-ctr3",
+    "EventCode": "0xF11",
+    "CounterIDMask": "0x8",
+    "BriefDescription": "FAKE json event constrained to hpmcounter3"
+  },
+  {
+    "EventName": "fake-json-ctr34",
+    "EventCode": "0xF12",
+    "CounterIDMask": "0x18",
+    "BriefDescription": "FAKE json event constrained to hpmcounter3,4"
+  },
+  {
+    "EventName": "fake-json-ctr6",
+    "EventCode": "0xF13",
+    "CounterIDMask": "0x40",
+    "BriefDescription": "FAKE json event constrained to hpmcounter6 (out of a small pmu-mask)"
+  }
+]

-- 
2.53.0-Meta



From fustini at kernel.org  Mon Jun  8 23:14:37 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 8 Jun 2026 23:14:37 -0700
Subject: [PATCH 00/12] Add TH1520 USB support
In-Reply-To: <a8dc863b1692b4d327b4b9700dd56a4754120561.camel@icenowy.me>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
 <aieT4WmWK9416M9E@thelio>
 <a8dc863b1692b4d327b4b9700dd56a4754120561.camel@icenowy.me>
Message-ID: <aievTZ5hqHGL-pTh@thelio>

On Tue, Jun 09, 2026 at 01:10:41PM +0800, Icenowy Zheng wrote:
> ? 2026-06-08?? 21:17 -0700?Drew Fustini???
> > On Thu, May 07, 2026 at 04:16:58PM +0800, Icenowy Zheng wrote:
> > > This patchset adds support for T-Head TH1520's USB functionality,
> > > and
> > > enabled it on the Lichee Pi 4A board.
> > > 
> > > The first 3 patches add support for the MISC subsystem clock
> > > contrtoller, which contains some USB clocks.
> > > 
> > > The next 2 patches add support for the USB PHY of T-Head TH1520,
> > > which
> > > is a wrapped Synopsys USB3.0 FemtoPHY with a little integration
> > > quirk;
> > > the controller itself is a properly configured DWC3 controller with
> > > sane
> > > default register values set.
> > > 
> > > Then one patch adds the USB PHY and controller nodes to the TH1520
> > > DTSI
> > > file.
> > > 
> > > The remaining half of this patchset dedicates to enablement of USB
> > > on
> > > TH1520, because of the onboard hub of that board -- its USB2
> > > signals are
> > > behind a switch that needs to be toggled on, and Vbus supplies for
> > > both
> > > the hub itself and downstream ports are managed via I2C-expanded
> > > GPIOs
> > > (because the SoC does not have enough GPIO pins).
> > 
> > Hi, thanks for working on USB. I tried to apply it to next-20260601
> > and
> > several of the dts patches no longer apply cleanly. Could you rebase?
> 
> I think the reason is that one of the GPIO expansion chip is added to
> the DT for enabling Wi-Fi.

Yeah, I tried to resolve the conflicts but I'm not sure what the correct
resolution is.

a20241c08385 ("riscv: dts: thead: Enable WiFi on Lichee Pi 4A") adds
'clock-frquency = <400000>' to &i2c1 while this series instead sets
'clock-frequency = <100000>'. That commit also sets i2c1_pins
'bias-pull-up = <2100>' while this series sets bias-disable.

> I am not sure whether the next revision of this patchset will contain
> all things, maybe I will split out at least the USB PHY part.

I think splitting out would work, too.

Thanks,
Drew


From fustini at kernel.org  Mon Jun  8 23:15:39 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 8 Jun 2026 23:15:39 -0700
Subject: [PATCH 02/12] clk: thead: th1520-ap: add support for MISC subsys
 clocks
In-Reply-To: <93b867c1b7f5526cc25cb04f838432cd752f5981.camel@icenowy.me>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
 <20260507081710.4090814-3-zhengxingda@iscas.ac.cn>
 <aier9XppLeCkJydw@thelio>
 <93b867c1b7f5526cc25cb04f838432cd752f5981.camel@icenowy.me>
Message-ID: <aievi0s-3SO8hV6a@thelio>

On Tue, Jun 09, 2026 at 02:01:43PM +0800, Icenowy Zheng wrote:
> ? 2026-06-08?? 23:00 -0700?Drew Fustini???
> > On Thu, May 07, 2026 at 04:17:00PM +0800, Icenowy Zheng wrote:
> > > The TH1520 SoC contains a MISC_SUBSYS clock controller, which
> > > allows
> > > controlling of USB related clocks and MMC/SD controller AHB bus
> > > clocks.
> > > 
> > > Add support for this clock controller, in order to enable USB
> > > support.
> > > 
> > > Signed-off-by: Icenowy Zheng <zhengxingda at iscas.ac.cn>
> > > ---
> > > ?drivers/clk/thead/clk-th1520-ap.c | 64
> > > +++++++++++++++++++++++++++++++
> > > ?1 file changed, 64 insertions(+)
> > > 
> > > diff --git a/drivers/clk/thead/clk-th1520-ap.c
> > > b/drivers/clk/thead/clk-th1520-ap.c
> > > index 3a6847f1c950f..24f785f0b329a 100644
> > > --- a/drivers/clk/thead/clk-th1520-ap.c
> > > +++ b/drivers/clk/thead/clk-th1520-ap.c
> > [...]
> > > @@ -1609,6 +1663,12 @@ static int th1520_clk_probe(struct
> > > platform_device *pdev)
> > > ?			return ret;
> > > ?	}
> > > ?
> > > +	if (plat_data == &th1520_ap_platdata) {
> > > +		ret = devm_clk_hw_register(dev,
> > > &usb_suspend_div_clk.hw);
> > > +		if (ret)
> > > +			return ret;
> > > +	}
> > 
> > Should usb_suspend_div_clk.hw instead be registered under
> > 'if (plat_data == &th1520_ap_platdata)'?
> 
> Do you mean misc_platdata?
> 
> Yes, this is an copy-n-paste error that deserves a fix.

Hah, yes, I also had a typo :)

Thanks,
Drew


From fustini at kernel.org  Mon Jun  8 23:16:11 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 8 Jun 2026 23:16:11 -0700
Subject: [PATCH 03/12] riscv: dts: thead: add device tree node for MISC
 clock controller
In-Reply-To: <67790d90737c13127100510020262d6921810e34.camel@icenowy.me>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
 <20260507081710.4090814-4-zhengxingda@iscas.ac.cn>
 <aiehUzl-qZeZDjXP@thelio>
 <67790d90737c13127100510020262d6921810e34.camel@icenowy.me>
Message-ID: <aievq4dae3GHHq0c@thelio>

On Tue, Jun 09, 2026 at 01:35:11PM +0800, Icenowy Zheng wrote:
> ? 2026-06-08?? 22:14 -0700?Drew Fustini???
> > On Thu, May 07, 2026 at 04:17:01PM +0800, Icenowy Zheng wrote:
> > > The MISC_SUBSYS clock controller on TH1520 SoC is a clock
> > > controller
> > > mainly controlling USB-related clocks (which isn't utilized yet)
> > > and
> > > MMC/SD controllers' AHB bus clocks.
> > > 
> > > Add the device tree node for it along with the missing bus clock
> > > references for MMC/SD controllers.
> > 
> > Is there a functional reason to modify the mmc nodes in this series?
> 
> When the clock isn't referenced, Linux will disable it unless
> `clk_ignore_unused` parameter is passed.

Ah ok, thanks for explaining.

Drew


From wanghan at linux.alibaba.com  Mon Jun  8 23:29:51 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:51 +0800
Subject: [PATCH v3 0/8] riscv: Add reliable stack unwinding for livepatch
In-Reply-To: <20260528082310.1994388-1-wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com>
Message-ID: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>

Hi,

This is v3 of the RISC-V reliable stack unwinding series for livepatch.

The series is still based on riscv/for-next commit 0ca1724b56af
("riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT").

Patch 1 fixes the build-time mcount sorting regression for RISC-V
patchable function entries. It is independent from the livepatch
enablement work and can be picked separately if that is preferred.

Patches 2-7 add the reliable frame-pointer unwinder in reviewable
steps, following the arm64 metadata-frame-record and kunwind model but
using the RISC-V {fp, ra} frame-record convention.

Patch 8 adds the RISC-V syscall wrapper prefix used by the livepatch
selftest module.

Problem
=======

Livepatch relies on HAVE_RELIABLE_STACKTRACE to decide whether a task
can safely switch to a patched implementation. RISC-V has a
frame-pointer stack walker, but it is not yet reliable enough for
livepatch. Three pieces are missing:

  * arch_stack_walk_reliable() itself, plus the strict stack-bound
    checks and forward-progress invariants a reliable unwinder needs.
  * Explicit unwind metadata at exception, task-entry and IRQ-stack
    boundaries, so the unwinder can distinguish a final user-to-kernel
    transition from a nested kernel pt_regs frame instead of guessing
    from return addresses.
  * Agreement between the ftrace function-graph, perf callchain and
    mcount paths and the same frame-record assumptions used by the
    reliable unwinder.

There is also a prerequisite ftrace issue on the current riscv/for-next
base. Commit 0ca1724b56af ("riscv: ftrace: select
HAVE_BUILDTIME_MCOUNT_SORT") enabled build-time sorting of the mcount
table. RISC-V uses patchable function entries, and the recorded patch
site is placed before the function symbol. scripts/sorttable currently
does not take that RISC-V layout into account, so valid ftrace sites
can be filtered out before the kernel boots.

Solution
========

Patch 1 fixes scripts/sorttable so the RISC-V build-time mcount sort
path accepts patchable function entries which precede the function
symbol. The fix carries a Fixes: tag for commit 0ca1724b56af ("riscv:
ftrace: select HAVE_BUILDTIME_MCOUNT_SORT") and is otherwise
independent.

Patches 2-7 add the reliable unwinder in small, individually
reviewable steps. The design follows the same FP + metadata model
arm64 already uses for livepatch in production: the metadata frame
record in pt_regs, the unwind-state stack-bound bookkeeping, the
exception boundary handling, and the fgraph / kretprobe return-address
recovery are direct adaptations of arch/arm64/kernel/stacktrace.c,
retargeted to the RISC-V {fp, ra} frame record convention.

Changes since v2
================

  * Patch 1:
    - Split the arm64-only RELA weak-function fixup comment from the
      arm64/RISC-V shared patchable-entry offset handling.
    - Add Reviewed-by tags from Steven, Shuai and Chen Pei.

  * Patch 2:
    - Initialize frame-record metadata in the kernel stack overflow
      path as FRAME_META_TYPE_PT_REGS.
    - Explicitly set user-fork pt_regs metadata to
      FRAME_META_TYPE_FINAL.
    - Expand the commit log to document that the call_on_irq_stack
      frame-record adjustment fixes a latent RV32 issue where the
      aligned stack slot is larger than the raw {fp, ra} record.

  * Patch 3:
    - Disable KCOV instrumentation for stacktrace.o as well, and update
      the subject and commit log accordingly.

  * Patch 4:
    - Clarify the s0 preservation rationale in the commit log.
    - Add Shuai's Reviewed-by tag.

  * Patch 5:
    - Fix the new header copyright year.
    - Add Shuai's Reviewed-by tag.

  * Patch 6:
    - Keep state->regs set after kunwind_next_regs_pc(), matching
      kunwind_init_from_regs() and the arm64 reference.
    - Use RISC-V "ra" terminology instead of "LR" in a reliable
      unwinder comment.

  * Patch 7:
    - Document that the 64BIT dependency is a tested-scope guard rather
      than a hard technical requirement, and can be relaxed after RV32
      receives equivalent coverage.
    - Add Shuai's Reviewed-by tag.

  * Patch 8:
    - Add Reviewed-by tags from Marcos and Shuai.

v2: https://lore.kernel.org/all/20260528082310.1994388-1-wanghan at linux.alibaba.com/
v1: https://lore.kernel.org/all/20260527123530.2593918-1-wanghan at linux.alibaba.com/

Wang Han (8):
  scripts/sorttable: Handle RISC-V patchable ftrace entries
  riscv: stacktrace: Add frame record metadata
  riscv: stacktrace: disable KASAN and KCOV instrumentation for
    stacktrace.o
  riscv: ftrace: always preserve s0 in dynamic ftrace register frame
  riscv: stacktrace: introduce stack-bound tracking helpers
  riscv: stacktrace: switch to frame-pointer based unwinder
  riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH
  selftests/livepatch: Add RISC-V syscall wrapper prefix

 arch/riscv/Kconfig                            |   4 +
 arch/riscv/include/asm/ptrace.h               |   9 +
 arch/riscv/include/asm/stacktrace.h           |  65 +-
 arch/riscv/include/asm/stacktrace/common.h    | 159 +++++
 arch/riscv/include/asm/stacktrace/frame.h     |  53 ++
 arch/riscv/kernel/Makefile                    |   6 +
 arch/riscv/kernel/asm-offsets.c               |   4 +
 arch/riscv/kernel/entry.S                     |  43 +-
 arch/riscv/kernel/ftrace.c                    |   6 +-
 arch/riscv/kernel/head.S                      |  23 +
 arch/riscv/kernel/mcount-dyn.S                |   4 -
 arch/riscv/kernel/perf_callchain.c            |   2 +-
 arch/riscv/kernel/process.c                   |  33 +-
 arch/riscv/kernel/stacktrace.c                | 559 +++++++++++++++---
 scripts/sorttable.c                           |  11 +-
 .../livepatch/test_modules/test_klp_syscall.c |   2 +
 16 files changed, 872 insertions(+), 111 deletions(-)
 create mode 100644 arch/riscv/include/asm/stacktrace/common.h
 create mode 100644 arch/riscv/include/asm/stacktrace/frame.h

Range-diff against v2:
1:  42147458c15b ! 1:  e93530c5718e scripts/sorttable: Handle RISC-V patchable ftrace entries
    @@ Commit message
     
         Fixes: 0ca1724b56af ("riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT")
         Suggested-by: Steven Rostedt (Google) <rostedt at goodmis.org>
    +    Reviewed-by: Steven Rostedt <rostedt at goodmis.org>
    +    Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
    +    Reviewed-by: Chen Pei <cp0613 at linux.alibaba.com>
         Link: https://lore.kernel.org/all/20260527113028.4b21a5de at fedora/
         Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
     
    @@ scripts/sorttable.c: static int do_file(char const *const fname, void *addr)
     -	case EM_AARCH64:
      #ifdef MCOUNT_SORT_ENABLED
     +	case EM_AARCH64:
    ++		/* arm64 also needs RELA-based weak-function fixups. */
      		sort_reloc = true;
      		rela_type = 0x403;
     -		/* arm64 uses patchable function entry placing before function */
     +		/* fallthrough */
     +	case EM_RISCV:
    -+		/* arm64 and RISC-V place patchable entries before the function */
    ++		/* arm64 and RISC-V place patchable entries before the function. */
      		before_func = 8;
     +#else
     +	case EM_AARCH64:
2:  9f6a4bf60d10 ! 2:  5b6b411e4d9a riscv: stacktrace: Add frame record metadata
    @@ Commit message
         future reliable unwinder.
     
         Add a small metadata frame record to pt_regs and initialize it on
    -    exception entry, kernel thread fork, user fork, and early idle task
    -    setup. The record uses a zero {fp, ra} sentinel plus a type field so a
    -    later unwinder can distinguish a final user-to-kernel boundary from a
    -    nested kernel pt_regs boundary.
    +    exception entry, kernel stack overflow, kernel thread fork, user fork,
    +    and early idle task setup. The record uses a zero {fp, ra} sentinel plus
    +    a type field so a later unwinder can distinguish a final user-to-kernel
    +    boundary from a nested kernel pt_regs boundary.
     
         This follows the arm64 metadata frame-record model, adapted to the
         RISC-V {fp, ra} frame record convention.
    @@ Commit message
           * exception entry clears the metadata {fp, ra} pair and uses SPP
             (or MPP in M-mode) to record whether the pt_regs frame is the final
             user-to-kernel boundary or a nested kernel boundary;
    +      * the kernel stack overflow path builds a nested pt_regs metadata
    +        record on the overflow stack so an unwinder can resume from the
    +        pre-overflow s0 saved in PT_S0;
           * _start_kernel builds the init task's final metadata record, while
             the secondary CPU path sets up s0 before smp_callin() so idle-task
             unwinding does not inherit an undefined caller frame;
    @@ Commit message
             saved {fp, ra} with the raw frame-record size so s0 points at the
             RISC-V frame record rather than past the alignment padding.
     
    +    The call_on_irq_stack adjustment fixes a latent RV32 issue. On RV64,
    +    sizeof(struct stackframe) is equal to the stack alignment, so the old
    +    s0 value happened to point just above the saved {fp, ra}. On RV32, the
    +    raw frame record is 8 bytes while the reserved stack slot is 16-byte
    +    aligned, so the old s0 value pointed into the padding. Using the raw
    +    record size makes s0 point above the saved frame record on both RV32
    +    and RV64 while still reserving the aligned slot.
    +
         These changes keep s0 reserved for the frame-pointer chain at task and
         stack-switch boundaries.
     
    @@ arch/riscv/kernel/entry.S: SYM_CODE_START(handle_exception)
      	/*
      	 * Set the scratch register to 0, so that if a recursive exception
      	 * occurs, the exception vector knows it came from the kernel
    +@@ arch/riscv/kernel/entry.S: SYM_CODE_START_LOCAL(handle_kernel_stack_overflow)
    + 	REG_S s3, PT_BADADDR(sp)
    + 	REG_S s4, PT_CAUSE(sp)
    + 	REG_S s5, PT_TP(sp)
    ++
    ++	/*
    ++	 * Create a metadata frame record for the overflow pt_regs. The
    ++	 * overflow path is entered from kernel context, so this is a nested
    ++	 * pt_regs boundary and the unwinder can resume from the pre-overflow
    ++	 * frame pointer saved in PT_S0.
    ++	 */
    ++	REG_S zero, (S_STACKFRAME + STACKFRAME_FP)(sp)
    ++	REG_S zero, (S_STACKFRAME + STACKFRAME_RA)(sp)
    ++	li t0, FRAME_META_TYPE_PT_REGS
    ++	REG_S t0, S_STACKFRAME_TYPE(sp)
    ++	addi s0, sp, S_STACKFRAME + STACKFRAME_RECORD_SIZE
    ++
    + 	move a0, sp
    + 	tail handle_bad_stack
    + SYM_CODE_END(handle_kernel_stack_overflow)
     @@ arch/riscv/kernel/entry.S: ASM_NOKPROBE(handle_kernel_stack_overflow)
      
      SYM_CODE_START(ret_from_fork_kernel_asm)
    @@ arch/riscv/kernel/process.c: int copy_thread(struct task_struct *p, const struct
     +		/*
     +		 * Set up the unwind boundary: ensure the metadata
     +		 * frame record has its {fp,ra} sentinel zeroed and
    -+		 * point fp/s0 above the metadata record. The type
    -+		 * field is inherited from the parent's pt_regs.
    ++		 * point fp/s0 above the metadata record. Mark it as
    ++		 * FINAL since this is the outermost kernel entry for
    ++		 * the new task.
     +		 */
     +		childregs->stackframe.record.fp = 0;
     +		childregs->stackframe.record.ra = 0;
    ++		childregs->stackframe.type = FRAME_META_TYPE_FINAL;
     +		p->thread.s[0] = (unsigned long)(&childregs->stackframe)
     +				+ sizeof(struct frame_record);
     +
3:  c1cc1fdba771 ! 3:  dc86baa5b148 riscv: stacktrace: disable KASAN instrumentation for stacktrace.o
    @@ Metadata
     Author: Wang Han <wanghan at linux.alibaba.com>
     
      ## Commit message ##
    -    riscv: stacktrace: disable KASAN instrumentation for stacktrace.o
    +    riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o
     
         KASAN records stack traces for every alloc/free, which means it walks
         the unwinder very frequently. Instrumenting the stack trace collection
         code itself adds substantial overhead and makes the traces themselves
         noisier.
     
    -    Mark stacktrace.o as not KASAN-instrumented, matching the arm, arm64
    -    and x86 treatment of their stack unwinding code. This is a prerequisite
    -    preference for the upcoming reliable unwinder, but the change is valid
    -    on its own.
    +    KCOV instruments every basic-block edge. The unwinder is a hot path,
    +    especially with KASAN enabled, so KCOV instrumentation has the same kind
    +    of cost and noise problem here.
    +
    +    Mark stacktrace.o as not KASAN- or KCOV-instrumented, matching the x86
    +    treatment of its stack unwinding code. RISC-V keeps the relevant unwinder
    +    code in stacktrace.o, so a single translation-unit annotation covers the
    +    equivalent scope. This is a prerequisite preference for the upcoming
    +    reliable unwinder, but the change is valid on its own.
     
         Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
     
    @@ arch/riscv/kernel/Makefile: CFLAGS_REMOVE_return_address.o	= $(CC_FLAGS_FTRACE)
     +# can significantly impact performance. Avoid instrumenting the stack trace
     +# collection code to minimize this impact.
     +KASAN_SANITIZE_stacktrace.o := n
    ++KCOV_INSTRUMENT_stacktrace.o := n
     +
      always-$(KBUILD_BUILTIN) += vmlinux.lds
      
4:  8960c3c96143 ! 4:  a2d474a996f9 riscv: ftrace: always preserve s0 in dynamic ftrace register frame
    @@ Metadata
      ## Commit message ##
         riscv: ftrace: always preserve s0 in dynamic ftrace register frame
     
    -    The dynamic ftrace entry/exit only saved s0 (the architectural frame
    -    pointer) when HAVE_FUNCTION_GRAPH_FP_TEST was selected. The upcoming
    -    reliable frame-pointer unwinder needs s0 to be present in
    -    ftrace_regs unconditionally so it can use the frame pointer as the
    -    function-graph return-address cookie regardless of FP_TEST.
    +    struct __arch_ftrace_regs declares s0 unconditionally, and both
    +    ftrace_regs_get_frame_pointer() and ftrace_partial_regs() read it
    +    unconditionally. But the SAVE_ABI_REGS / RESTORE_ABI_REGS macros in
    +    mcount-dyn.S only stored s0 under HAVE_FUNCTION_GRAPH_FP_TEST
    +    (CONFIG_FUNCTION_GRAPH_TRACER && CONFIG_FRAME_POINTER). With
    +    CONFIG_FRAME_POINTER=n the slot held whatever was on the stack before,
    +    so any callback going through ftrace_partial_regs() saw a garbage
    +    regs->s0. RISC-V kernels default to FRAME_POINTER=y, which is why this
    +    has not bitten in practice.
     
         Save and restore s0 unconditionally in the dynamic ftrace ABI register
    -    frame. The cost is one extra REG_S/REG_L pair per traced call, which is
    -    negligible compared to the overall ftrace cost; the benefit is a
    -    consistent ftrace_regs layout for the unwinder.
    +    frame. This fixes the latent garbage-s0 case, brings the dynamic ftrace
    +    path in line with the static _mcount path (mcount.S SAVE_ABI_STATE
    +    already saves s0 unconditionally), and matches the frame layout already
    +    documented in the comment above SAVE_ABI_REGS. It is also a prerequisite
    +    for the upcoming reliable unwinder, which reads
    +    ftrace_regs_get_frame_pointer(fregs) directly.
     
    +    The cost is one extra REG_S/REG_L pair per traced call, negligible
    +    compared to the overall ftrace cost; the existing FREGS_SIZE_ON_STACK
    +    already reserved the slot, so no extra stack space is used.
    +
    +    Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
         Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
     
      ## arch/riscv/kernel/mcount-dyn.S ##
5:  5fb2633c7e6e ! 5:  b74577e4a6b1 riscv: stacktrace: introduce stack-bound tracking helpers
    @@ Commit message
         on_thread_stack() with the same semantics as before, just expressed in
         terms of the new helpers.
     
    +    Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
         Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
     
      ## arch/riscv/include/asm/stacktrace.h ##
    @@ arch/riscv/include/asm/stacktrace/common.h (new)
     + * See: arch/arm64/include/asm/stacktrace/common.h for the reference
     + * implementation.
     + *
    -+ * Copyright (C) 2024
    ++ * Copyright (C) 2026
     + */
     +#ifndef __ASM_RISCV_STACKTRACE_COMMON_H
     +#define __ASM_RISCV_STACKTRACE_COMMON_H
6:  6b3ec0c98cd8 ! 6:  ac01a5cf8317 riscv: stacktrace: switch to frame-pointer based unwinder
    @@ arch/riscv/kernel/stacktrace.c: unsigned long __get_wchan(struct task_struct *ta
     +	state->regs = regs;
     +	state->common.pc = regs->epc;
     +	state->common.fp = frame_pointer(regs);
    -+	state->regs = NULL;
     +	state->source = KUNWIND_SOURCE_REGS_PC;
     +	return 0;
     +}
    @@ arch/riscv/kernel/stacktrace.c: unsigned long __get_wchan(struct task_struct *ta
     +{
     +	/*
     +	 * At an exception boundary we can reliably consume the saved PC. We do
    -+	 * not know whether the LR was live when the exception was taken, and
    ++	 * not know whether ra was live when the exception was taken, and
     +	 * so we cannot perform the next unwind step reliably.
     +	 *
     +	 * All that matters is whether the *entire* unwind is reliable, so give
7:  90fcaa590d57 ! 7:  cd40c6ddb5d1 riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH
    @@ Commit message
         to the rest of the kernel:
     
           * select HAVE_RELIABLE_STACKTRACE under FRAME_POINTER && 64BIT, so
    -        only the configurations that actually have the metadata records
    -        and the FP-based reliable walker enable it.
    +        only the configurations with the tested metadata records and
    +        FP-based reliable walker enable it.
           * select HAVE_LIVEPATCH under the same condition and source
             kernel/livepatch/Kconfig so the livepatch menu is reachable from
             the RISC-V configuration.
     
    +    The 64BIT dependency is conservative scoping rather than a hard
    +    technical requirement: the metadata frame record, kunwind state machine
    +    and arch_stack_walk_reliable() also build on RV32, and the IRQ-stack
    +    frame-record adjustment fixes a latent RV32 issue. However, the syscall
    +    livepatch selftest and module relocation path have only been exercised
    +    on RV64 QEMU virt so far. The 64BIT gate can be relaxed in a follow-up
    +    once RV32 has equivalent coverage.
    +
         This is split out from the unwinder change so the policy decision and
         the implementation can be reviewed and reverted independently.
     
    +    Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
         Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
     
      ## arch/riscv/Kconfig ##
8:  9590be5df884 ! 8:  194d76e3a15b selftests/livepatch: Add RISC-V syscall wrapper prefix
    @@ Commit message
         RISC-V target symbol, and the syscall-related livepatch test fails on
         RISC-V.
     
    +    Reviewed-by: Marcos Paulo de Souza <mpdesouza at suse.com>
    +    Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
         Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
     
      ## tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c ##

base-commit: 0ca1724b56af054e304a9f3f60623b02a81aba3f
-- 
2.43.0


From wanghan at linux.alibaba.com  Mon Jun  8 23:29:52 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:52 +0800
Subject: [PATCH v3 1/8] scripts/sorttable: Handle RISC-V patchable ftrace entries
In-Reply-To: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com> <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
Message-ID: <20260609063002.3943001-1-wanghan@linux.alibaba.com>

RISC-V uses -fpatchable-function-entry=8,4 when the compressed ISA is
enabled and -fpatchable-function-entry=4,2 otherwise. In both cases, the
patchable NOP area starts 8 bytes before the function symbol address.
The __mcount_loc entries therefore point at the patchable NOP area
associated with a function, while nm reports the function symbol at the
entry address used for the function range check.

After RISC-V selected HAVE_BUILDTIME_MCOUNT_SORT, sorttable started
applying that range check at build time. Without allowing entries just
before the reported function address, the mcount sorter treats valid
RISC-V ftrace callsites as invalid weak-function entries and writes
them back as zero. The resulting kernel boots with no ftrace entries,
breaking dynamic ftrace and users such as livepatch.

The failure is silent during the final link because zeroing weak-function
entries is an expected sorttable operation. At boot, those zero entries
are skipped by ftrace_process_locs(), so the only obvious symptom is that
the vmlinux ftrace table has lost valid callsites and ftrace users cannot
attach to them.

CONFIG_FTRACE_SORT_STARTUP_TEST also reports the table as sorted in this
state: it only checks that the __mcount_loc entries are in ascending
order, which a fully zeroed table trivially satisfies. The original
commit relied on this check and did not see the regression.

On an affected RISC-V QEMU boot with both CONFIG_FTRACE_SORT_STARTUP_TEST
and CONFIG_FTRACE_STARTUP_TEST enabled, the sort check still passes
while ftrace reports zero usable entries and the early selftests fail:

  [    0.000000] ftrace section at ffffffff8101da98 sorted properly
  [    0.000000] ftrace: allocating 0 entries in 128 pages
  [    0.054999] Testing tracer function: .. no entries found ..FAILED!
  [    0.172407] tracer: function failed selftest, disabling
  [    0.178186] Failed to init function_graph tracer, init returned -19

Handle RISC-V like arm64 for the function-range check and allow
patchable entries up to 8 bytes before the function address.

With this fix, a RISC-V QEMU smoke boot with ftrace startup tests shows
the vmlinux ftrace table is populated and dynamic ftrace still works:

  [    0.000000] ftrace: allocating 46749 entries in 184 pages
  [    0.051115] Testing tracer function: PASSED
  [    1.283782] Testing dynamic ftrace: PASSED
  [    6.275456] Testing tracer function_graph: PASSED

Fixes: 0ca1724b56af ("riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT")
Suggested-by: Steven Rostedt (Google) <rostedt at goodmis.org>
Reviewed-by: Steven Rostedt <rostedt at goodmis.org>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Reviewed-by: Chen Pei <cp0613 at linux.alibaba.com>
Link: https://lore.kernel.org/all/20260527113028.4b21a5de at fedora/
Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
---
 scripts/sorttable.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/scripts/sorttable.c b/scripts/sorttable.c
index e8ed11c680c6..d8dc2a1b7c31 100644
--- a/scripts/sorttable.c
+++ b/scripts/sorttable.c
@@ -891,17 +891,22 @@ static int do_file(char const *const fname, void *addr)
 	table_sort_t custom_sort = NULL;
 
 	switch (elf_map_machine(ehdr)) {
-	case EM_AARCH64:
 #ifdef MCOUNT_SORT_ENABLED
+	case EM_AARCH64:
+		/* arm64 also needs RELA-based weak-function fixups. */
 		sort_reloc = true;
 		rela_type = 0x403;
-		/* arm64 uses patchable function entry placing before function */
+		/* fallthrough */
+	case EM_RISCV:
+		/* arm64 and RISC-V place patchable entries before the function. */
 		before_func = 8;
+#else
+	case EM_AARCH64:
+	case EM_RISCV:
 #endif
 		/* fallthrough */
 	case EM_386:
 	case EM_LOONGARCH:
-	case EM_RISCV:
 	case EM_S390:
 	case EM_X86_64:
 		custom_sort = sort_relative_table_with_data;
-- 
2.43.0



From wanghan at linux.alibaba.com  Mon Jun  8 23:29:53 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:53 +0800
Subject: [PATCH v3 2/8] riscv: stacktrace: Add frame record metadata
In-Reply-To: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com> <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
Message-ID: <20260609063002.3943001-2-wanghan@linux.alibaba.com>

Reliable frame-pointer unwinding needs an explicit way to identify
exception boundaries and the final entry frame. The existing unwinder
infers those boundaries from return addresses, which is too loose for a
future reliable unwinder.

Add a small metadata frame record to pt_regs and initialize it on
exception entry, kernel stack overflow, kernel thread fork, user fork,
and early idle task setup. The record uses a zero {fp, ra} sentinel plus
a type field so a later unwinder can distinguish a final user-to-kernel
boundary from a nested kernel pt_regs boundary.

This follows the arm64 metadata frame-record model, adapted to the
RISC-V {fp, ra} frame record convention.

The metadata is established at the RISC-V entry boundaries that need an
explicit unwind marker:

  * exception entry clears the metadata {fp, ra} pair and uses SPP
    (or MPP in M-mode) to record whether the pt_regs frame is the final
    user-to-kernel boundary or a nested kernel boundary;
  * the kernel stack overflow path builds a nested pt_regs metadata
    record on the overflow stack so an unwinder can resume from the
    pre-overflow s0 saved in PT_S0;
  * _start_kernel builds the init task's final metadata record, while
    the secondary CPU path sets up s0 before smp_callin() so idle-task
    unwinding does not inherit an undefined caller frame;
  * copy_thread creates matching final metadata records for new kernel
    and user tasks, and keeps s0 available for the frame-pointer chain;
  * call_on_irq_stack still reserves an aligned stack slot, but links the
    saved {fp, ra} with the raw frame-record size so s0 points at the
    RISC-V frame record rather than past the alignment padding.

The call_on_irq_stack adjustment fixes a latent RV32 issue. On RV64,
sizeof(struct stackframe) is equal to the stack alignment, so the old
s0 value happened to point just above the saved {fp, ra}. On RV32, the
raw frame record is 8 bytes while the reserved stack slot is 16-byte
aligned, so the old s0 value pointed into the padding. Using the raw
record size makes s0 point above the saved frame record on both RV32
and RV64 while still reserving the aligned slot.

These changes keep s0 reserved for the frame-pointer chain at task and
stack-switch boundaries.

Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
---
 arch/riscv/include/asm/ptrace.h           |  9 ++++
 arch/riscv/include/asm/stacktrace/frame.h | 53 +++++++++++++++++++++++
 arch/riscv/kernel/asm-offsets.c           |  4 ++
 arch/riscv/kernel/entry.S                 | 43 ++++++++++++++++--
 arch/riscv/kernel/head.S                  | 23 ++++++++++
 arch/riscv/kernel/process.c               | 33 +++++++++++++-
 6 files changed, 159 insertions(+), 6 deletions(-)
 create mode 100644 arch/riscv/include/asm/stacktrace/frame.h

diff --git a/arch/riscv/include/asm/ptrace.h b/arch/riscv/include/asm/ptrace.h
index addc8188152f..4b9b0f279214 100644
--- a/arch/riscv/include/asm/ptrace.h
+++ b/arch/riscv/include/asm/ptrace.h
@@ -8,6 +8,7 @@
 
 #include <uapi/asm/ptrace.h>
 #include <asm/csr.h>
+#include <asm/stacktrace/frame.h>
 #include <linux/compiler.h>
 
 #ifndef __ASSEMBLER__
@@ -53,6 +54,14 @@ struct pt_regs {
 	unsigned long cause;
 	/* a0 value before the syscall */
 	unsigned long orig_a0;
+
+	/*
+	 * This frame record is entirely zeroed on exception entry, allowing the
+	 * unwinder to identify exception boundaries. The type field encodes
+	 * whether the exception was taken from user (FINAL) or kernel (PT_REGS)
+	 * mode.
+	 */
+	struct frame_record_meta stackframe;
 };
 
 #define PTRACE_SYSEMU			0x1f
diff --git a/arch/riscv/include/asm/stacktrace/frame.h b/arch/riscv/include/asm/stacktrace/frame.h
new file mode 100644
index 000000000000..5720a6c65fe8
--- /dev/null
+++ b/arch/riscv/include/asm/stacktrace/frame.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef __ASM_RISCV_STACKTRACE_FRAME_H
+#define __ASM_RISCV_STACKTRACE_FRAME_H
+
+/*
+ * See: arch/arm64/include/asm/stacktrace/frame.h for the reference
+ * implementation.
+ */
+
+/*
+ * - FRAME_META_TYPE_NONE
+ *
+ *   This value is reserved.
+ *
+ * - FRAME_META_TYPE_FINAL
+ *
+ *   The record is the last entry on the stack.
+ *   Unwinding should terminate successfully.
+ *
+ * - FRAME_META_TYPE_PT_REGS
+ *
+ *   The record is embedded within a struct pt_regs, recording the registers at
+ *   an arbitrary point in time.
+ *   Unwinding should consume pt_regs::epc, followed by pt_regs::ra.
+ *
+ * Note: all other values are reserved and should result in unwinding
+ * terminating with an error.
+ */
+#define FRAME_META_TYPE_NONE		0
+#define FRAME_META_TYPE_FINAL		1
+#define FRAME_META_TYPE_PT_REGS		2
+
+#ifndef __ASSEMBLER__
+/*
+ * A standard RISC-V frame record.
+ */
+struct frame_record {
+	unsigned long fp;
+	unsigned long ra;
+};
+
+/*
+ * A metadata frame record indicating a special unwind.
+ * The record::{fp,ra} fields must be zero to indicate the presence of
+ * metadata.
+ */
+struct frame_record_meta {
+	struct frame_record record;
+	unsigned long type;
+};
+#endif /* __ASSEMBLER__ */
+
+#endif /* __ASM_RISCV_STACKTRACE_FRAME_H */
diff --git a/arch/riscv/kernel/asm-offsets.c b/arch/riscv/kernel/asm-offsets.c
index af827448a609..8dfcb5a44bb8 100644
--- a/arch/riscv/kernel/asm-offsets.c
+++ b/arch/riscv/kernel/asm-offsets.c
@@ -131,6 +131,9 @@ void asm_offsets(void)
 	OFFSET(PT_BADADDR, pt_regs, badaddr);
 	OFFSET(PT_CAUSE, pt_regs, cause);
 
+	DEFINE(S_STACKFRAME,		offsetof(struct pt_regs, stackframe));
+	DEFINE(S_STACKFRAME_TYPE,	offsetof(struct pt_regs, stackframe.type));
+
 	OFFSET(SUSPEND_CONTEXT_REGS, suspend_context, regs);
 
 	OFFSET(HIBERN_PBE_ADDR, pbe, address);
@@ -501,6 +504,7 @@ void asm_offsets(void)
 	OFFSET(SBI_HART_BOOT_STACK_PTR_OFFSET, sbi_hart_boot_data, stack_ptr);
 
 	DEFINE(STACKFRAME_SIZE_ON_STACK, ALIGN(sizeof(struct stackframe), STACK_ALIGN));
+	DEFINE(STACKFRAME_RECORD_SIZE, sizeof(struct stackframe));
 	OFFSET(STACKFRAME_FP, stackframe, fp);
 	OFFSET(STACKFRAME_RA, stackframe, ra);
 #ifdef CONFIG_FUNCTION_TRACER
diff --git a/arch/riscv/kernel/entry.S b/arch/riscv/kernel/entry.S
index d011fb51c59a..8df74d14b551 100644
--- a/arch/riscv/kernel/entry.S
+++ b/arch/riscv/kernel/entry.S
@@ -11,6 +11,7 @@
 #include <asm/asm.h>
 #include <asm/csr.h>
 #include <asm/scs.h>
+#include <asm/stacktrace/frame.h>
 #include <asm/unistd.h>
 #include <asm/page.h>
 #include <asm/thread_info.h>
@@ -193,6 +194,27 @@ SYM_CODE_START(handle_exception)
 	REG_S s4, PT_CAUSE(sp)
 	REG_S s5, PT_TP(sp)
 
+	/*
+	 * Create a metadata frame record. The unwinder will use this to
+	 * identify and unwind exception boundaries.
+	 */
+	REG_S zero, (S_STACKFRAME + STACKFRAME_FP)(sp) /* stackframe.record.fp = 0 */
+	REG_S zero, (S_STACKFRAME + STACKFRAME_RA)(sp) /* stackframe.record.ra = 0 */
+#ifdef CONFIG_RISCV_M_MODE
+	li t0, SR_MPP
+	and t0, s1, t0
+#else
+	andi t0, s1, SR_SPP
+#endif
+	bnez t0, 1f
+	li t0, FRAME_META_TYPE_FINAL
+	j 2f
+1:
+	li t0, FRAME_META_TYPE_PT_REGS
+2:
+	REG_S t0, S_STACKFRAME_TYPE(sp)
+	addi s0, sp, S_STACKFRAME + STACKFRAME_RECORD_SIZE
+
 	/*
 	 * Set the scratch register to 0, so that if a recursive exception
 	 * occurs, the exception vector knows it came from the kernel
@@ -349,6 +371,19 @@ SYM_CODE_START_LOCAL(handle_kernel_stack_overflow)
 	REG_S s3, PT_BADADDR(sp)
 	REG_S s4, PT_CAUSE(sp)
 	REG_S s5, PT_TP(sp)
+
+	/*
+	 * Create a metadata frame record for the overflow pt_regs. The
+	 * overflow path is entered from kernel context, so this is a nested
+	 * pt_regs boundary and the unwinder can resume from the pre-overflow
+	 * frame pointer saved in PT_S0.
+	 */
+	REG_S zero, (S_STACKFRAME + STACKFRAME_FP)(sp)
+	REG_S zero, (S_STACKFRAME + STACKFRAME_RA)(sp)
+	li t0, FRAME_META_TYPE_PT_REGS
+	REG_S t0, S_STACKFRAME_TYPE(sp)
+	addi s0, sp, S_STACKFRAME + STACKFRAME_RECORD_SIZE
+
 	move a0, sp
 	tail handle_bad_stack
 SYM_CODE_END(handle_kernel_stack_overflow)
@@ -357,8 +392,8 @@ ASM_NOKPROBE(handle_kernel_stack_overflow)
 
 SYM_CODE_START(ret_from_fork_kernel_asm)
 	call schedule_tail
-	move a0, s1 /* fn_arg */
-	move a1, s0 /* fn */
+	move a0, s3 /* fn_arg */
+	move a1, s2 /* fn */
 	move a2, sp /* pt_regs */
 	call ret_from_fork_kernel
 	j ret_from_exception
@@ -383,7 +418,7 @@ SYM_FUNC_START(call_on_irq_stack)
 	addi	sp, sp, -STACKFRAME_SIZE_ON_STACK
 	REG_S	ra, STACKFRAME_RA(sp)
 	REG_S	s0, STACKFRAME_FP(sp)
-	addi	s0, sp, STACKFRAME_SIZE_ON_STACK
+	addi	s0, sp, STACKFRAME_RECORD_SIZE
 
 	/* Switch to the per-CPU shadow call stack */
 	scs_save_current
@@ -399,7 +434,7 @@ SYM_FUNC_START(call_on_irq_stack)
 	scs_load_current
 
 	/* Switch back to the thread stack and restore ra and s0 */
-	addi	sp, s0, -STACKFRAME_SIZE_ON_STACK
+	addi	sp, s0, -STACKFRAME_RECORD_SIZE
 	REG_L	ra, STACKFRAME_RA(sp)
 	REG_L	s0, STACKFRAME_FP(sp)
 	addi	sp, sp, STACKFRAME_SIZE_ON_STACK
diff --git a/arch/riscv/kernel/head.S b/arch/riscv/kernel/head.S
index f6a8ca49e627..00e16a24f149 100644
--- a/arch/riscv/kernel/head.S
+++ b/arch/riscv/kernel/head.S
@@ -14,6 +14,7 @@
 #include <asm/hwcap.h>
 #include <asm/image.h>
 #include <asm/scs.h>
+#include <asm/stacktrace/frame.h>
 #include <asm/usercfi.h>
 #include "efi-header.S"
 
@@ -177,6 +178,14 @@ secondary_start_sbi:
 	REG_S a0, (a1)
 1:
 #endif
+
+	/*
+	 * Set up the frame pointer for the secondary idle task so reliable
+	 * stack unwinding terminates at the metadata frame in task_pt_regs().
+	 * Without this, the first frame records can inherit an undefined caller
+	 * fp and unwind past smp_callin() into .Lsecondary_park.
+	 */
+	addi s0, sp, S_STACKFRAME + STACKFRAME_RECORD_SIZE
 	scs_load_current
 	call smp_callin
 #endif /* CONFIG_SMP */
@@ -305,6 +314,20 @@ SYM_CODE_START(_start_kernel)
 	la tp, init_task
 	la sp, init_thread_union + THREAD_SIZE
 	addi sp, sp, -PT_SIZE_ON_STACK
+
+	/*
+	 * Set up a metadata frame record for the init task so that
+	 * the unwinder can identify the outermost frame by its
+	 * {fp, ra} = {0, 0} sentinel at the bottom of pt_regs.
+	 * fp/s0 points above the metadata record (RISC-V
+	 * convention).
+	 */
+	REG_S zero, (S_STACKFRAME + STACKFRAME_FP)(sp)
+	REG_S zero, (S_STACKFRAME + STACKFRAME_RA)(sp)
+	li t0, FRAME_META_TYPE_FINAL
+	REG_S t0, S_STACKFRAME_TYPE(sp)
+	addi s0, sp, S_STACKFRAME + STACKFRAME_RECORD_SIZE
+
 #if defined(CONFIG_RISCV_SBI) && defined(CONFIG_RISCV_USER_CFI)
 	li a7, SBI_EXT_FWFT
 	li a6, SBI_EXT_FWFT_SET
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index b2df7f72241a..0dc90bf7a652 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -258,8 +258,23 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 		/* Supervisor/Machine, irqs on: */
 		childregs->status = SR_PP | SR_PIE;
 
-		p->thread.s[0] = (unsigned long)args->fn;
-		p->thread.s[1] = (unsigned long)args->fn_arg;
+		/*
+		 * Set up a metadata frame record at the bottom of the
+		 * stack for the unwinder. Use FRAME_META_TYPE_FINAL
+		 * since this is the outermost kernel entry for the new
+		 * task. The frame_record::{fp,ra} are already zero from
+		 * memset().
+		 *
+		 * fp/s0 points above the metadata record (RISC-V
+		 * convention). fn and fn_arg are passed via s2/s3,
+		 * keeping s0 available for the frame pointer chain.
+		 */
+		childregs->stackframe.type = FRAME_META_TYPE_FINAL;
+
+		p->thread.s[0] = (unsigned long)(&childregs->stackframe)
+				+ sizeof(struct frame_record);
+		p->thread.s[2] = (unsigned long)args->fn;
+		p->thread.s[3] = (unsigned long)args->fn_arg;
 		p->thread.ra = (unsigned long)ret_from_fork_kernel_asm;
 	} else {
 		/* allocate new shadow stack if needed. In case of CLONE_VM we have to */
@@ -278,6 +293,20 @@ int copy_thread(struct task_struct *p, const struct kernel_clone_args *args)
 		if (clone_flags & CLONE_SETTLS)
 			childregs->tp = tls;
 		childregs->a0 = 0; /* Return value of fork() */
+
+		/*
+		 * Set up the unwind boundary: ensure the metadata
+		 * frame record has its {fp,ra} sentinel zeroed and
+		 * point fp/s0 above the metadata record. Mark it as
+		 * FINAL since this is the outermost kernel entry for
+		 * the new task.
+		 */
+		childregs->stackframe.record.fp = 0;
+		childregs->stackframe.record.ra = 0;
+		childregs->stackframe.type = FRAME_META_TYPE_FINAL;
+		p->thread.s[0] = (unsigned long)(&childregs->stackframe)
+				+ sizeof(struct frame_record);
+
 		p->thread.ra = (unsigned long)ret_from_fork_user_asm;
 	}
 	p->thread.riscv_v_flags = 0;
-- 
2.43.0



From wanghan at linux.alibaba.com  Mon Jun  8 23:29:57 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:57 +0800
Subject: [PATCH v3 6/8] riscv: stacktrace: switch to frame-pointer based unwinder
In-Reply-To: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com> <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
Message-ID: <20260609063002.3943001-6-wanghan@linux.alibaba.com>

Replace the open-coded frame-pointer walker in arch_stack_walk() with a
robust kunwind state machine, modelled on arch/arm64/kernel/stacktrace.c
and retargeted to the RISC-V {fp, ra} frame record convention. The new
walker tracks stack bounds, consumes frame records monotonically,
understands the metadata pt_regs records added in the previous frame
record metadata patch, and recovers return addresses replaced by
function graph tracing and kretprobes.

This commit introduces arch_stack_walk_reliable() but does not yet
select HAVE_RELIABLE_STACKTRACE; that is done in a follow-up Kconfig
patch so this commit can be reviewed and bisected as a pure unwinder
replacement. Until that Kconfig change lands, livepatch is not yet
enabled and arch_stack_walk_reliable() has no in-tree caller.

Three related callers are updated to keep the same frame-record
assumptions everywhere:

  * Function graph tracing: the old RISC-V unwinder matched function
    graph return-stack entries by the saved return-address slot. That
    was consistent with the static mcount path, but not with the dynamic
    ftrace path where the parent slot is ftrace_regs::ra. Use the
    architectural frame pointer as the function graph return-address
    cookie, matching the kunwind walker.

  * Perf callchains: route kernel callchain collection through
    arch_stack_walk() so perf sees the same frame-pointer unwind
    behaviour as dump_stack() and the upcoming livepatch path.

  * dump_backtrace() / __get_wchan() / show_stack(): these now go
    through arch_stack_walk(); the explicit "Call Trace:" header is
    moved into dump_backtrace() to preserve the original output.

The non-frame-pointer fallback walker is kept untouched for
!CONFIG_FRAME_POINTER builds.

Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
---
 arch/riscv/kernel/ftrace.c         |   6 +-
 arch/riscv/kernel/perf_callchain.c |   2 +-
 arch/riscv/kernel/stacktrace.c     | 559 ++++++++++++++++++++++++-----
 3 files changed, 471 insertions(+), 96 deletions(-)

diff --git a/arch/riscv/kernel/ftrace.c b/arch/riscv/kernel/ftrace.c
index b430edfb83f4..5d55199a9230 100644
--- a/arch/riscv/kernel/ftrace.c
+++ b/arch/riscv/kernel/ftrace.c
@@ -242,7 +242,8 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
 	 */
 	old = *parent;
 
-	if (!function_graph_enter(old, self_addr, frame_pointer, parent))
+	if (!function_graph_enter(old, self_addr, frame_pointer,
+				  (void *)frame_pointer))
 		*parent = return_hooker;
 }
 
@@ -264,7 +265,8 @@ void ftrace_graph_func(unsigned long ip, unsigned long parent_ip,
 	 */
 	old = *parent;
 
-	if (!function_graph_enter_regs(old, ip, frame_pointer, parent, fregs))
+	if (!function_graph_enter_regs(old, ip, frame_pointer,
+				       (void *)frame_pointer, fregs))
 		*parent = return_hooker;
 }
 #endif /* CONFIG_DYNAMIC_FTRACE */
diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c
index b465bc9eb870..436af96ea59c 100644
--- a/arch/riscv/kernel/perf_callchain.c
+++ b/arch/riscv/kernel/perf_callchain.c
@@ -44,5 +44,5 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
 		return;
 	}
 
-	walk_stackframe(NULL, regs, fill_callchain, entry);
+	arch_stack_walk(fill_callchain, entry, NULL, regs);
 }
diff --git a/arch/riscv/kernel/stacktrace.c b/arch/riscv/kernel/stacktrace.c
index 2692d3a06afa..8fcf23b046d5 100644
--- a/arch/riscv/kernel/stacktrace.c
+++ b/arch/riscv/kernel/stacktrace.c
@@ -11,98 +11,16 @@
 #include <linux/sched/task_stack.h>
 #include <linux/stacktrace.h>
 #include <linux/ftrace.h>
+#include <linux/kprobes.h>
+#include <linux/llist.h>
 
 #include <asm/stacktrace.h>
 
-#ifdef CONFIG_FRAME_POINTER
-
 /*
- * This disables KASAN checking when reading a value from another task's stack,
- * since the other task could be running on another CPU and could have poisoned
- * the stack in the meantime.
+ * Non-frame-pointer fallback unwinder.
+ * Only compiled when CONFIG_FRAME_POINTER is not enabled.
  */
-#define READ_ONCE_TASK_STACK(task, x)			\
-({							\
-	unsigned long val;				\
-	unsigned long addr = x;				\
-	if ((task) == current)				\
-		val = READ_ONCE(addr);			\
-	else						\
-		val = READ_ONCE_NOCHECK(addr);		\
-	val;						\
-})
-
-extern asmlinkage void handle_exception(void);
-extern unsigned long ret_from_exception_end;
-
-static inline int fp_is_valid(unsigned long fp, unsigned long sp)
-{
-	unsigned long low, high;
-
-	low = sp + sizeof(struct stackframe);
-	high = ALIGN(sp, THREAD_SIZE);
-
-	return !(fp < low || fp > high || fp & 0x07);
-}
-
-void notrace walk_stackframe(struct task_struct *task, struct pt_regs *regs,
-			     bool (*fn)(void *, unsigned long), void *arg)
-{
-	unsigned long fp, sp, pc;
-	int graph_idx = 0;
-	int level = 0;
-
-	if (regs) {
-		fp = frame_pointer(regs);
-		sp = user_stack_pointer(regs);
-		pc = instruction_pointer(regs);
-	} else if (task == NULL || task == current) {
-		fp = (unsigned long)__builtin_frame_address(0);
-		sp = current_stack_pointer;
-		pc = (unsigned long)walk_stackframe;
-		level = -1;
-	} else {
-		/* task blocked in __switch_to */
-		fp = task->thread.s[0];
-		sp = task->thread.sp;
-		pc = task->thread.ra;
-	}
-
-	for (;;) {
-		struct stackframe *frame;
-
-		if (unlikely(!__kernel_text_address(pc) || (level++ >= 0 && !fn(arg, pc))))
-			break;
-
-		if (unlikely(!fp_is_valid(fp, sp)))
-			break;
-
-		/* Unwind stack frame */
-		frame = (struct stackframe *)fp - 1;
-		sp = fp;
-		if (regs && (regs->epc == pc) && fp_is_valid(frame->ra, sp)) {
-			/* We hit function where ra is not saved on the stack */
-			fp = frame->ra;
-			pc = regs->ra;
-		} else {
-			fp = READ_ONCE_TASK_STACK(task, frame->fp);
-			pc = READ_ONCE_TASK_STACK(task, frame->ra);
-			pc = ftrace_graph_ret_addr(task, &graph_idx, pc,
-						   &frame->ra);
-			if (pc >= (unsigned long)handle_exception &&
-			    pc < (unsigned long)&ret_from_exception_end) {
-				if (unlikely(!fn(arg, pc)))
-					break;
-
-				pc = ((struct pt_regs *)sp)->epc;
-				fp = ((struct pt_regs *)sp)->s0;
-			}
-		}
-
-	}
-}
-
-#else /* !CONFIG_FRAME_POINTER */
+#ifndef CONFIG_FRAME_POINTER
 
 void notrace walk_stackframe(struct task_struct *task,
 	struct pt_regs *regs, bool (*fn)(void *, unsigned long), void *arg)
@@ -133,7 +51,12 @@ void notrace walk_stackframe(struct task_struct *task,
 	}
 }
 
-#endif /* CONFIG_FRAME_POINTER */
+#endif /* !CONFIG_FRAME_POINTER */
+
+/*
+ * Common trace helpers.
+ * These are used by both the FP (kunwind) and non-FP (walk_stackframe) paths.
+ */
 
 static bool print_trace_address(void *arg, unsigned long pc)
 {
@@ -146,12 +69,12 @@ static bool print_trace_address(void *arg, unsigned long pc)
 noinline void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
 		    const char *loglvl)
 {
-	walk_stackframe(task, regs, print_trace_address, (void *)loglvl);
+	printk("%sCall Trace:\n", loglvl);
+	arch_stack_walk(print_trace_address, (void *)loglvl, task, regs);
 }
 
 void show_stack(struct task_struct *task, unsigned long *sp, const char *loglvl)
 {
-	pr_cont("%sCall Trace:\n", loglvl);
 	dump_backtrace(NULL, task, loglvl);
 }
 
@@ -171,17 +94,467 @@ unsigned long __get_wchan(struct task_struct *task)
 
 	if (!try_get_task_stack(task))
 		return 0;
-	walk_stackframe(task, NULL, save_wchan, &pc);
+	arch_stack_walk(save_wchan, &pc, task, NULL);
 	put_task_stack(task);
 	return pc;
 }
 
-noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry, void *cookie,
-		     struct task_struct *task, struct pt_regs *regs)
+/*
+ * Frame-pointer-based kernel unwind infrastructure.
+ * Only compiled when CONFIG_FRAME_POINTER is enabled.
+ *
+ * See: arch/arm64/kernel/stacktrace.c for the reference implementation.
+ */
+#ifdef CONFIG_FRAME_POINTER
+
+/*
+ * Per-cpu stacks are only accessible when unwinding the current task in a
+ * non-preemptible context.
+ */
+#define STACKINFO_CPU(task, name)				\
+	({							\
+		(((task) == current) && !preemptible())		\
+			? stackinfo_get_##name()		\
+			: stackinfo_get_unknown();		\
+	})
+
+enum kunwind_source {
+	KUNWIND_SOURCE_UNKNOWN,
+	KUNWIND_SOURCE_FRAME,
+	KUNWIND_SOURCE_CALLER,
+	KUNWIND_SOURCE_TASK,
+	KUNWIND_SOURCE_REGS_PC,
+};
+
+union unwind_flags {
+	unsigned long	all;
+	struct {
+		unsigned long	fgraph : 1,
+				kretprobe : 1;
+	};
+};
+
+/*
+ * Kernel unwind state
+ *
+ * @common:    Common unwind state.
+ * @task:      The task being unwound.
+ * @graph_idx: Used by ftrace_graph_ret_addr() for optimized stack unwinding.
+ * @kr_cur:    When KRETPROBES is selected, holds the kretprobe instance
+ *             associated with the most recently encountered replacement ra
+ *             value.
+ */
+struct kunwind_state {
+	struct unwind_state common;
+	struct task_struct *task;
+	int graph_idx;
+#ifdef CONFIG_KRETPROBES
+	struct llist_node *kr_cur;
+#endif
+	enum kunwind_source source;
+	union unwind_flags flags;
+	struct pt_regs *regs;
+};
+
+static __always_inline void
+kunwind_init(struct kunwind_state *state,
+	     struct task_struct *task)
+{
+	unwind_init_common(&state->common);
+	state->task = task;
+	state->source = KUNWIND_SOURCE_UNKNOWN;
+	state->flags.all = 0;
+	state->regs = NULL;
+}
+
+/*
+ * Start an unwind from a pt_regs.
+ *
+ * The unwind will begin at the PC within the regs.
+ *
+ * The regs must be on a stack currently owned by the calling task.
+ */
+static __always_inline void
+kunwind_init_from_regs(struct kunwind_state *state,
+		       struct pt_regs *regs)
+{
+	kunwind_init(state, current);
+
+	state->regs = regs;
+	state->common.fp = frame_pointer(regs);
+	state->common.pc = instruction_pointer(regs);
+	state->source = KUNWIND_SOURCE_REGS_PC;
+}
+
+/*
+ * Start an unwind from a caller.
+ *
+ * The unwind will begin at the caller of whichever function this is inlined
+ * into.
+ *
+ * The function which invokes this must be noinline.
+ */
+static __always_inline void
+kunwind_init_from_caller(struct kunwind_state *state)
+{
+	unsigned long fp = (unsigned long)__builtin_frame_address(0);
+	struct frame_record *record = (struct frame_record *)fp - 1;
+
+	kunwind_init(state, current);
+
+	state->common.fp = READ_ONCE(record->fp);
+	state->common.pc = READ_ONCE(record->ra);
+	state->source = KUNWIND_SOURCE_CALLER;
+}
+
+/*
+ * Start an unwind from a blocked task.
+ *
+ * The unwind will begin at the blocked task's saved PC (i.e. the caller of
+ * __switch_to).
+ *
+ * The caller should ensure the task is blocked in __switch_to for the
+ * duration of the unwind, or the unwind will be bogus. It is never valid to
+ * call this for the current task.
+ */
+static __always_inline void
+kunwind_init_from_task(struct kunwind_state *state,
+		       struct task_struct *task)
+{
+	kunwind_init(state, task);
+
+	state->common.fp = task->thread.s[0];
+	state->common.pc = task->thread.ra;
+	state->source = KUNWIND_SOURCE_TASK;
+}
+
+static __always_inline int
+kunwind_recover_return_address(struct kunwind_state *state)
+{
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+	if (state->task->ret_stack &&
+	    state->common.pc == (unsigned long)return_to_handler) {
+		unsigned long orig_pc;
+
+		orig_pc = ftrace_graph_ret_addr(state->task, &state->graph_idx,
+						state->common.pc,
+						(void *)state->common.fp);
+		if (state->common.pc == orig_pc) {
+			WARN_ON_ONCE(state->task == current);
+			return -EINVAL;
+		}
+		state->common.pc = orig_pc;
+		state->flags.fgraph = 1;
+	}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
+#ifdef CONFIG_KRETPROBES
+	if (is_kretprobe_trampoline(state->common.pc)) {
+		unsigned long orig_pc;
+
+		orig_pc = kretprobe_find_ret_addr(state->task,
+						  (void *)state->common.fp,
+						  &state->kr_cur);
+		if (!orig_pc)
+			return -EINVAL;
+		state->common.pc = orig_pc;
+		state->flags.kretprobe = 1;
+	}
+#endif /* CONFIG_KRETPROBES */
+
+	return 0;
+}
+
+/*
+ * When we reach an exception boundary marked by a metadata frame record,
+ * extract pt_regs from the stack and continue unwinding from the saved
+ * context (epc and s0/fp).
+ *
+ * On RISC-V, fp points above the metadata record, so the record's
+ * frame_record portion is at fp - sizeof(struct frame_record).
+ */
+static __always_inline int
+kunwind_next_regs_pc(struct kunwind_state *state)
+{
+	struct stack_info *info;
+	unsigned long fp = state->common.fp;
+	struct pt_regs *regs;
+
+	regs = container_of((unsigned long *)(fp - sizeof(struct frame_record)),
+			    struct pt_regs, stackframe.record.fp);
+
+	info = unwind_find_stack(&state->common, (unsigned long)regs,
+				 sizeof(*regs));
+	if (!info)
+		return -EINVAL;
+
+	unwind_consume_stack(&state->common, info, (unsigned long)regs,
+			     sizeof(*regs));
+
+	state->regs = regs;
+	state->common.pc = regs->epc;
+	state->common.fp = frame_pointer(regs);
+	state->source = KUNWIND_SOURCE_REGS_PC;
+	return 0;
+}
+
+/*
+ * Handle a metadata frame record embedded in pt_regs.
+ *
+ * On RISC-V, fp points above the record (fp = metadata + 16), so the
+ * frame_record_meta starts at fp - sizeof(struct frame_record).
+ *
+ * FRAME_META_TYPE_FINAL: This is the outermost exception entry
+ *   (user -> kernel). Unwinding terminates successfully.
+ * FRAME_META_TYPE_PT_REGS: This is a nested exception entry
+ *   (kernel -> kernel). Continue unwinding from the saved context.
+ */
+static __always_inline int
+kunwind_next_frame_record_meta(struct kunwind_state *state)
+{
+	struct task_struct *tsk = state->task;
+	unsigned long fp = state->common.fp;
+	unsigned long meta_base = fp - sizeof(struct frame_record);
+	struct frame_record_meta *meta;
+	struct stack_info *info;
+
+	info = unwind_find_stack(&state->common, meta_base, sizeof(*meta));
+	if (!info)
+		return -EINVAL;
+
+	meta = (struct frame_record_meta *)meta_base;
+	switch (READ_ONCE(meta->type)) {
+	case FRAME_META_TYPE_FINAL:
+		if (meta == &task_pt_regs(tsk)->stackframe)
+			return -ENOENT;
+		WARN_ON_ONCE(tsk == current);
+		return -EINVAL;
+	case FRAME_META_TYPE_PT_REGS:
+		return kunwind_next_regs_pc(state);
+	default:
+		WARN_ON_ONCE(tsk == current);
+		return -EINVAL;
+	}
+}
+
+/*
+ * Unwind from one frame record to the next.
+ *
+ * On RISC-V, the frame record sits at fp - sizeof(struct frame_record),
+ * immediately below the address pointed to by fp/s0. This applies to both
+ * normal frame records and metadata frame records (embedded in pt_regs).
+ *
+ * A metadata record is identified by both fp and ra being zero in the
+ * frame_record portion, with a type value following at fp + 16.
+ */
+static __always_inline int
+kunwind_next_frame_record(struct kunwind_state *state)
+{
+	unsigned long fp = state->common.fp;
+	struct frame_record *record;
+	struct stack_info *info;
+	unsigned long new_fp, new_pc;
+	unsigned long record_base;
+
+	if (fp & 0x7)
+		return -EINVAL;
+
+	record_base = fp - sizeof(*record);
+
+	info = unwind_find_stack(&state->common, record_base, sizeof(*record));
+	if (!info)
+		return -EINVAL;
+
+	record = (struct frame_record *)record_base;
+	new_fp = READ_ONCE(record->fp);
+	new_pc = READ_ONCE(record->ra);
+
+	if (!new_fp && !new_pc)
+		return kunwind_next_frame_record_meta(state);
+
+	unwind_consume_stack(&state->common, info, record_base,
+			     sizeof(*record));
+
+	state->common.fp = new_fp;
+	state->common.pc = new_pc;
+	state->source = KUNWIND_SOURCE_FRAME;
+
+	return 0;
+}
+
+/*
+ * Unwind from one frame record (A) to the next frame record (B).
+ *
+ * We terminate early if the location of B indicates a malformed chain of frame
+ * records (e.g. a cycle), determined based on the location and fp value of A
+ * and the location (but not the fp value) of B.
+ */
+static __always_inline int
+kunwind_next(struct kunwind_state *state)
+{
+	int err;
+
+	state->flags.all = 0;
+
+	switch (state->source) {
+	case KUNWIND_SOURCE_FRAME:
+	case KUNWIND_SOURCE_CALLER:
+	case KUNWIND_SOURCE_TASK:
+	case KUNWIND_SOURCE_REGS_PC:
+		err = kunwind_next_frame_record(state);
+		break;
+	default:
+		err = -EINVAL;
+	}
+
+	if (err)
+		return err;
+
+	return kunwind_recover_return_address(state);
+}
+
+typedef bool (*kunwind_consume_fn)(const struct kunwind_state *state, void *cookie);
+
+static __always_inline int
+do_kunwind(struct kunwind_state *state, kunwind_consume_fn consume_state,
+	   void *cookie)
+{
+	int ret;
+
+	ret = kunwind_recover_return_address(state);
+	if (ret)
+		return ret;
+
+	while (1) {
+		if (!consume_state(state, cookie))
+			return -EINVAL;
+		ret = kunwind_next(state);
+		if (ret == -ENOENT)
+			return 0;
+		if (ret < 0)
+			return ret;
+	}
+}
+
+static __always_inline int
+kunwind_stack_walk(kunwind_consume_fn consume_state,
+		   void *cookie, struct task_struct *task,
+		   struct pt_regs *regs)
+{
+	struct task_struct *tsk = task ?: current;
+	struct stack_info stacks[] = {
+		stackinfo_get_task(tsk),
+		STACKINFO_CPU(tsk, irq),
+#ifdef CONFIG_VMAP_STACK
+		STACKINFO_CPU(tsk, overflow),
+#endif
+	};
+	struct kunwind_state state = {
+		.common = {
+			.stacks = stacks,
+			.nr_stacks = ARRAY_SIZE(stacks),
+		},
+	};
+
+	if (regs) {
+		if (tsk != current)
+			return -EINVAL;
+		kunwind_init_from_regs(&state, regs);
+	} else if (tsk == current) {
+		kunwind_init_from_caller(&state);
+	} else {
+		kunwind_init_from_task(&state, tsk);
+	}
+
+	return do_kunwind(&state, consume_state, cookie);
+}
+
+struct kunwind_consume_entry_data {
+	stack_trace_consume_fn consume_entry;
+	void *cookie;
+};
+
+static __always_inline bool
+arch_kunwind_consume_entry(const struct kunwind_state *state, void *cookie)
+{
+	struct kunwind_consume_entry_data *data = cookie;
+
+	return data->consume_entry(data->cookie, state->common.pc);
+}
+
+static __always_inline bool
+arch_reliable_kunwind_consume_entry(const struct kunwind_state *state, void *cookie)
+{
+	/*
+	 * At an exception boundary we can reliably consume the saved PC. We do
+	 * not know whether ra was live when the exception was taken, and
+	 * so we cannot perform the next unwind step reliably.
+	 *
+	 * All that matters is whether the *entire* unwind is reliable, so give
+	 * up as soon as we hit an exception boundary.
+	 */
+	if (state->source == KUNWIND_SOURCE_REGS_PC)
+		return false;
+
+	return arch_kunwind_consume_entry(state, cookie);
+}
+
+#endif /* CONFIG_FRAME_POINTER */
+
+/*
+ * arch_stack_walk - dual implementation.
+ *
+ * When CONFIG_FRAME_POINTER is enabled, uses the kunwind infrastructure for
+ * robust frame-pointer-based unwinding, consistent with arch_stack_walk_reliable.
+ *
+ * When CONFIG_FRAME_POINTER is disabled, falls back to the simple stack scan
+ * in walk_stackframe().
+ */
+#ifdef CONFIG_FRAME_POINTER
+
+noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
+				      void *cookie, struct task_struct *task,
+				      struct pt_regs *regs)
+{
+	struct kunwind_consume_entry_data data = {
+		.consume_entry = consume_entry,
+		.cookie = cookie,
+	};
+
+	kunwind_stack_walk(arch_kunwind_consume_entry, &data, task, regs);
+}
+
+#else
+
+noinline noinstr void arch_stack_walk(stack_trace_consume_fn consume_entry,
+				      void *cookie, struct task_struct *task,
+				      struct pt_regs *regs)
 {
 	walk_stackframe(task, regs, consume_entry, cookie);
 }
 
+#endif /* CONFIG_FRAME_POINTER */
+
+/*
+ * Reliable stack walk for livepatch (CONFIG_FRAME_POINTER only).
+ */
+#ifdef CONFIG_FRAME_POINTER
+
+noinline noinstr int arch_stack_walk_reliable(stack_trace_consume_fn consume_entry,
+					      void *cookie,
+					      struct task_struct *task)
+{
+	struct kunwind_consume_entry_data data = {
+		.consume_entry = consume_entry,
+		.cookie = cookie,
+	};
+
+	return kunwind_stack_walk(arch_reliable_kunwind_consume_entry, &data,
+				  task, NULL);
+}
+
+#endif /* CONFIG_FRAME_POINTER */
+
 /*
  * Get the return address for a single stackframe and return a pointer to the
  * next frame tail.
-- 
2.43.0



From wanghan at linux.alibaba.com  Mon Jun  8 23:29:55 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:55 +0800
Subject: [PATCH v3 4/8] riscv: ftrace: always preserve s0 in dynamic ftrace register frame
In-Reply-To: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com> <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
Message-ID: <20260609063002.3943001-4-wanghan@linux.alibaba.com>

struct __arch_ftrace_regs declares s0 unconditionally, and both
ftrace_regs_get_frame_pointer() and ftrace_partial_regs() read it
unconditionally. But the SAVE_ABI_REGS / RESTORE_ABI_REGS macros in
mcount-dyn.S only stored s0 under HAVE_FUNCTION_GRAPH_FP_TEST
(CONFIG_FUNCTION_GRAPH_TRACER && CONFIG_FRAME_POINTER). With
CONFIG_FRAME_POINTER=n the slot held whatever was on the stack before,
so any callback going through ftrace_partial_regs() saw a garbage
regs->s0. RISC-V kernels default to FRAME_POINTER=y, which is why this
has not bitten in practice.

Save and restore s0 unconditionally in the dynamic ftrace ABI register
frame. This fixes the latent garbage-s0 case, brings the dynamic ftrace
path in line with the static _mcount path (mcount.S SAVE_ABI_STATE
already saves s0 unconditionally), and matches the frame layout already
documented in the comment above SAVE_ABI_REGS. It is also a prerequisite
for the upcoming reliable unwinder, which reads
ftrace_regs_get_frame_pointer(fregs) directly.

The cost is one extra REG_S/REG_L pair per traced call, negligible
compared to the overall ftrace cost; the existing FREGS_SIZE_ON_STACK
already reserved the slot, so no extra stack space is used.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
---
 arch/riscv/kernel/mcount-dyn.S | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/arch/riscv/kernel/mcount-dyn.S b/arch/riscv/kernel/mcount-dyn.S
index 082fe0b0e3c0..26c55fba8fec 100644
--- a/arch/riscv/kernel/mcount-dyn.S
+++ b/arch/riscv/kernel/mcount-dyn.S
@@ -85,9 +85,7 @@
 	addi	sp, sp, -FREGS_SIZE_ON_STACK
 	REG_S	t0,  FREGS_EPC(sp)
 	REG_S	x1,  FREGS_RA(sp)
-#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
 	REG_S	x8,  FREGS_S0(sp)
-#endif
 	REG_S	x6,  FREGS_T1(sp)
 #ifdef CONFIG_CC_IS_CLANG
 	REG_S	x7,  FREGS_T2(sp)
@@ -113,9 +111,7 @@
 	.macro RESTORE_ABI_REGS
 	REG_L	t0, FREGS_EPC(sp)
 	REG_L	x1, FREGS_RA(sp)
-#ifdef HAVE_FUNCTION_GRAPH_FP_TEST
 	REG_L	x8, FREGS_S0(sp)
-#endif
 	REG_L	x6,  FREGS_T1(sp)
 #ifdef CONFIG_CC_IS_CLANG
 	REG_L	x7,  FREGS_T2(sp)
-- 
2.43.0



From wanghan at linux.alibaba.com  Mon Jun  8 23:29:54 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:54 +0800
Subject: [PATCH v3 3/8] riscv: stacktrace: disable KASAN and KCOV instrumentation for stacktrace.o
In-Reply-To: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com> <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
Message-ID: <20260609063002.3943001-3-wanghan@linux.alibaba.com>

KASAN records stack traces for every alloc/free, which means it walks
the unwinder very frequently. Instrumenting the stack trace collection
code itself adds substantial overhead and makes the traces themselves
noisier.

KCOV instruments every basic-block edge. The unwinder is a hot path,
especially with KASAN enabled, so KCOV instrumentation has the same kind
of cost and noise problem here.

Mark stacktrace.o as not KASAN- or KCOV-instrumented, matching the x86
treatment of its stack unwinding code. RISC-V keeps the relevant unwinder
code in stacktrace.o, so a single translation-unit annotation covers the
equivalent scope. This is a prerequisite preference for the upcoming
reliable unwinder, but the change is valid on its own.

Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
---
 arch/riscv/kernel/Makefile | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index cabb99cadfb6..c565a72a36f3 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -44,6 +44,12 @@ CFLAGS_REMOVE_return_address.o	= $(CC_FLAGS_FTRACE)
 CFLAGS_REMOVE_sbi_ecall.o = $(CC_FLAGS_FTRACE)
 endif
 
+# When KASAN is enabled, a stack trace is recorded for every alloc/free, which
+# can significantly impact performance. Avoid instrumenting the stack trace
+# collection code to minimize this impact.
+KASAN_SANITIZE_stacktrace.o := n
+KCOV_INSTRUMENT_stacktrace.o := n
+
 always-$(KBUILD_BUILTIN) += vmlinux.lds
 
 obj-y	+= head.o
-- 
2.43.0



From wanghan at linux.alibaba.com  Mon Jun  8 23:29:56 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:56 +0800
Subject: [PATCH v3 5/8] riscv: stacktrace: introduce stack-bound tracking helpers
In-Reply-To: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com> <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
Message-ID: <20260609063002.3943001-5-wanghan@linux.alibaba.com>

A reliable unwinder needs to validate that every frame record it reads
is fully contained in a known kernel stack, and it needs to refuse to
walk back into a stack it has already left. Add the building blocks
for that:

  * struct stack_info / struct unwind_state in a new
    asm/stacktrace/common.h, modelled on the arm64 reference
    implementation.
  * stackinfo_get_irq() / stackinfo_get_task() / stackinfo_get_overflow()
    plus the corresponding on_*_stack() predicates in asm/stacktrace.h,
    so callers can ask "is this object on stack X?" by stack kind
    rather than open-coded address arithmetic.
  * unwind_init_common(), unwind_find_stack() and
    unwind_consume_stack() helpers that enforce the
    forward-progress-only invariant required for reliability.

No existing user is wired up to these helpers in this commit; the
unwinder switch comes in a follow-up. The header changes leave
on_thread_stack() with the same semantics as before, just expressed in
terms of the new helpers.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
---
 arch/riscv/include/asm/stacktrace.h        |  65 ++++++++-
 arch/riscv/include/asm/stacktrace/common.h | 159 +++++++++++++++++++++
 2 files changed, 222 insertions(+), 2 deletions(-)
 create mode 100644 arch/riscv/include/asm/stacktrace/common.h

diff --git a/arch/riscv/include/asm/stacktrace.h b/arch/riscv/include/asm/stacktrace.h
index b1495a7e06ce..bc87c4940379 100644
--- a/arch/riscv/include/asm/stacktrace.h
+++ b/arch/riscv/include/asm/stacktrace.h
@@ -3,8 +3,13 @@
 #ifndef _ASM_RISCV_STACKTRACE_H
 #define _ASM_RISCV_STACKTRACE_H
 
+#include <linux/percpu.h>
 #include <linux/sched.h>
+#include <linux/sched/task_stack.h>
+
+#include <asm/irq_stack.h>
 #include <asm/ptrace.h>
+#include <asm/stacktrace/common.h>
 
 struct stackframe {
 	unsigned long fp;
@@ -16,14 +21,70 @@ extern void notrace walk_stackframe(struct task_struct *task, struct pt_regs *re
 extern void dump_backtrace(struct pt_regs *regs, struct task_struct *task,
 			   const char *loglvl);
 
-static inline bool on_thread_stack(void)
+/*
+ * IRQ stack accessors
+ */
+static inline struct stack_info stackinfo_get_irq(void)
+{
+	unsigned long low = (unsigned long)raw_cpu_read(irq_stack_ptr);
+	unsigned long high = low + IRQ_STACK_SIZE;
+
+	return (struct stack_info) {
+		.low = low,
+		.high = high,
+	};
+}
+
+static inline bool on_irq_stack(unsigned long sp, unsigned long size)
+{
+	struct stack_info info = stackinfo_get_irq();
+
+	return stackinfo_on_stack(&info, sp, size);
+}
+
+/*
+ * Task stack accessors
+ */
+static inline struct stack_info stackinfo_get_task(const struct task_struct *tsk)
 {
-	return !(((unsigned long)(current->stack) ^ current_stack_pointer) & ~(THREAD_SIZE - 1));
+	unsigned long low = (unsigned long)task_stack_page(tsk);
+	unsigned long high = low + THREAD_SIZE;
+
+	return (struct stack_info) {
+		.low = low,
+		.high = high,
+	};
+}
+
+static inline bool on_task_stack(const struct task_struct *tsk,
+				 unsigned long sp, unsigned long size)
+{
+	struct stack_info info = stackinfo_get_task(tsk);
+
+	return stackinfo_on_stack(&info, sp, size);
 }
 
+/*
+ * Cast is necessary since current->stack is an opaque ptr.
+ */
+#define on_thread_stack()	(on_task_stack(current, current_stack_pointer, 1))
 
+/*
+ * Overflow stack accessors
+ */
 #ifdef CONFIG_VMAP_STACK
 DECLARE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
+
+static inline struct stack_info stackinfo_get_overflow(void)
+{
+	unsigned long low = (unsigned long)raw_cpu_ptr(overflow_stack);
+	unsigned long high = low + OVERFLOW_STACK_SIZE;
+
+	return (struct stack_info) {
+		.low = low,
+		.high = high,
+	};
+}
 #endif /* CONFIG_VMAP_STACK */
 
 #endif /* _ASM_RISCV_STACKTRACE_H */
diff --git a/arch/riscv/include/asm/stacktrace/common.h b/arch/riscv/include/asm/stacktrace/common.h
new file mode 100644
index 000000000000..360a26e34349
--- /dev/null
+++ b/arch/riscv/include/asm/stacktrace/common.h
@@ -0,0 +1,159 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * RISC-V common stack unwinder types and helpers.
+ *
+ * See: arch/arm64/include/asm/stacktrace/common.h for the reference
+ * implementation.
+ *
+ * Copyright (C) 2026
+ */
+#ifndef __ASM_RISCV_STACKTRACE_COMMON_H
+#define __ASM_RISCV_STACKTRACE_COMMON_H
+
+#include <linux/compiler.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#include <asm/stacktrace/frame.h>
+
+/**
+ * struct stack_info - describes the bounds of a stack.
+ *
+ * @low:  The lowest valid address on the stack.
+ * @high: The highest valid address on the stack.
+ */
+struct stack_info {
+	unsigned long low;
+	unsigned long high;
+};
+
+/**
+ * struct unwind_state - state used for robust unwinding.
+ *
+ * @fp:        The fp value in the frame record (or the real fp).
+ * @pc:        The ra value in the frame record (or the real ra).
+ *
+ * @stack:     The stack currently being unwound.
+ * @stacks:    An array of stacks which can be unwound.
+ * @nr_stacks: The number of stacks in @stacks.
+ */
+struct unwind_state {
+	unsigned long fp;
+	unsigned long pc;
+
+	struct stack_info stack;
+	struct stack_info *stacks;
+	int nr_stacks;
+};
+
+/**
+ * stackinfo_get_unknown() - Get an unknown stack_info.
+ *
+ * Return: a stack_info with low and high set to 0.
+ */
+static inline struct stack_info stackinfo_get_unknown(void)
+{
+	return (struct stack_info) {
+		.low = 0,
+		.high = 0,
+	};
+}
+
+/**
+ * stackinfo_on_stack() - Check whether an object is fully within a stack.
+ *
+ * @info: The stack to check against.
+ * @sp:   The base address of the object.
+ * @size: The size of the object.
+ *
+ * Return: true if the object is fully contained within the stack.
+ */
+static inline bool stackinfo_on_stack(const struct stack_info *info,
+				      unsigned long sp, unsigned long size)
+{
+	if (!info->low)
+		return false;
+
+	if (sp < info->low || sp + size < sp || sp + size > info->high)
+		return false;
+
+	return true;
+}
+
+/**
+ * unwind_init_common() - Initialize the common parts of the unwind state.
+ *
+ * @state: the unwind state to initialize.
+ */
+static inline void unwind_init_common(struct unwind_state *state)
+{
+	state->stack = stackinfo_get_unknown();
+}
+
+/**
+ * unwind_find_stack() - Find the accessible stack which entirely contains an
+ * object.
+ *
+ * @state: the current unwind state.
+ * @sp:    the base address of the object.
+ * @size:  the size of the object.
+ *
+ * Return: a pointer to the relevant stack_info if found; NULL otherwise.
+ */
+static inline struct stack_info *unwind_find_stack(struct unwind_state *state,
+						   unsigned long sp,
+						   unsigned long size)
+{
+	struct stack_info *info = &state->stack;
+
+	if (stackinfo_on_stack(info, sp, size))
+		return info;
+
+	for (int i = 0; i < state->nr_stacks; i++) {
+		info = &state->stacks[i];
+		if (stackinfo_on_stack(info, sp, size))
+			return info;
+	}
+
+	return NULL;
+}
+
+/**
+ * unwind_consume_stack() - Update stack boundaries so that future unwind steps
+ * cannot consume this object again.
+ *
+ * @state: the current unwind state.
+ * @info:  the stack_info of the stack containing the object.
+ * @sp:    the base address of the object.
+ * @size:  the size of the object.
+ *
+ * Stack transitions are strictly one-way, and once we've
+ * transitioned from one stack to another, it's never valid to
+ * unwind back to the old stack.
+ *
+ * Note that stacks can nest in several valid orders, e.g.
+ *
+ *   TASK -> IRQ -> OVERFLOW
+ *
+ * ... so we do not check the specific order of stack
+ * transitions.
+ */
+static inline void unwind_consume_stack(struct unwind_state *state,
+					struct stack_info *info,
+					unsigned long sp,
+					unsigned long size)
+{
+	struct stack_info tmp;
+
+	tmp = *info;
+	*info = stackinfo_get_unknown();
+	state->stack = tmp;
+
+	/*
+	 * Future unwind steps can only consume stack above this frame record.
+	 * Update the current stack to start immediately above it.
+	 */
+	state->stack.low = sp + size;
+}
+
+#endif /* __ASM_RISCV_STACKTRACE_COMMON_H */
-- 
2.43.0



From wanghan at linux.alibaba.com  Mon Jun  8 23:29:59 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:59 +0800
Subject: [PATCH v3 8/8] selftests/livepatch: Add RISC-V syscall wrapper prefix
In-Reply-To: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com> <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
Message-ID: <20260609063002.3943001-8-wanghan@linux.alibaba.com>

The syscall livepatch selftest resolves and patches a syscall wrapper
symbol. To use that test for RISC-V livepatch validation, add the
RISC-V FN_PREFIX definition for ARCH_HAS_SYSCALL_WRAPPER.

Without this macro, the syscall livepatch selftest cannot resolve the
RISC-V target symbol, and the syscall-related livepatch test fails on
RISC-V.

Reviewed-by: Marcos Paulo de Souza <mpdesouza at suse.com>
Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
---
 .../testing/selftests/livepatch/test_modules/test_klp_syscall.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c b/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c
index dd802783ea84..275e4b10cf59 100644
--- a/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c
+++ b/tools/testing/selftests/livepatch/test_modules/test_klp_syscall.c
@@ -18,6 +18,8 @@
 #define FN_PREFIX __s390x_
 #elif defined(__aarch64__)
 #define FN_PREFIX __arm64_
+#elif defined(__riscv)
+#define FN_PREFIX __riscv_
 #else
 /* powerpc does not select ARCH_HAS_SYSCALL_WRAPPER */
 #define FN_PREFIX
-- 
2.43.0



From wanghan at linux.alibaba.com  Mon Jun  8 23:29:58 2026
From: wanghan at linux.alibaba.com (Wang Han)
Date: Tue,  9 Jun 2026 14:29:58 +0800
Subject: [PATCH v3 7/8] riscv: Kconfig: enable HAVE_RELIABLE_STACKTRACE and HAVE_LIVEPATCH
In-Reply-To: <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com> <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
Message-ID: <20260609063002.3943001-7-wanghan@linux.alibaba.com>

Now that the metadata frame records, the kunwind state machine and
arch_stack_walk_reliable() are all in place, advertise the capability
to the rest of the kernel:

  * select HAVE_RELIABLE_STACKTRACE under FRAME_POINTER && 64BIT, so
    only the configurations with the tested metadata records and
    FP-based reliable walker enable it.
  * select HAVE_LIVEPATCH under the same condition and source
    kernel/livepatch/Kconfig so the livepatch menu is reachable from
    the RISC-V configuration.

The 64BIT dependency is conservative scoping rather than a hard
technical requirement: the metadata frame record, kunwind state machine
and arch_stack_walk_reliable() also build on RV32, and the IRQ-stack
frame-record adjustment fixes a latent RV32 issue. However, the syscall
livepatch selftest and module relocation path have only been exercised
on RV64 QEMU virt so far. The 64BIT gate can be relaxed in a follow-up
once RV32 has equivalent coverage.

This is split out from the unwinder change so the policy decision and
the implementation can be reviewed and reverted independently.

Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
---
 arch/riscv/Kconfig | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 674044754378..2921680d2132 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -185,6 +185,7 @@ config RISCV
 	select HAVE_KRETPROBES
 	# https://github.com/ClangBuiltLinux/linux/issues/1881
 	select HAVE_LD_DEAD_CODE_DATA_ELIMINATION if !LD_IS_LLD
+	select HAVE_LIVEPATCH if FRAME_POINTER && 64BIT
 	select HAVE_MOVE_PMD
 	select HAVE_MOVE_PUD
 	select HAVE_PAGE_SIZE_4KB
@@ -195,6 +196,7 @@ config RISCV
 	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
 	select HAVE_PREEMPT_DYNAMIC_KEY
 	select HAVE_REGS_AND_STACK_ACCESS_API
+	select HAVE_RELIABLE_STACKTRACE if FRAME_POINTER && 64BIT
 	select HAVE_RETHOOK
 	select HAVE_RSEQ
 	select HAVE_RUST if RUSTC_SUPPORTS_RISCV && CC_IS_CLANG
@@ -1394,3 +1396,5 @@ endmenu # "CPU Power Management"
 source "arch/riscv/kvm/Kconfig"
 
 source "drivers/acpi/Kconfig"
+
+source "kernel/livepatch/Kconfig"
-- 
2.43.0



From cuiyunhui at bytedance.com  Mon Jun  8 23:38:16 2026
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Tue, 9 Jun 2026 14:38:16 +0800
Subject: [External] Re: [PATCH v2 1/2] riscv: track effective hardware PTE
 A/D updates
In-Reply-To: <y2euih5fneiiisawwstfaqjufivpup2lag6yfme2io452v4dn6@n2tieehvqbsy>
References: <20260522142358.87589-1-cuiyunhui@bytedance.com>
 <eklh2rwzk4gcmeampzq5gj5kktspgtsm6znc56bqvg77rrg4yl@vhjrhmg6f2n2>
 <CAEEQ3w=+YXS_KE+ZeVH0TF_NQCa6aS=tQrvNyO1HA66r9TykcA@mail.gmail.com> <y2euih5fneiiisawwstfaqjufivpup2lag6yfme2io452v4dn6@n2tieehvqbsy>
Message-ID: <CAEEQ3wkSYGZQAc_m4N_SxCPEeQn2a3KmcZoLB_Q1PwND24+Hsg@mail.gmail.com>

Hi Andrew,

On Mon, May 25, 2026 at 4:44?AM Andrew Jones
<andrew.jones at oss.qualcomm.com> wrote:
>
> On Sat, May 23, 2026 at 11:58:05AM +0800, yunhui cui wrote:
> > Hi Andrew,
> >
> > On Sat, May 23, 2026 at 3:58?AM Andrew Jones
> > <andrew.jones at oss.qualcomm.com> wrote:
> > >
> > > On Fri, May 22, 2026 at 10:23:57PM +0800, Yunhui Cui wrote:
> > > > Track the effective hardware PTE A/D update mode separately from
> > > > Svadu capability discovery. When both Svade and Svadu are present,
> > > > enable SBI FWFT PTE A/D hardware updating on each online CPU via
> > > > CPUHP and use the resulting runtime state for arch_has_hw_pte_young().
> > > > Fall back to software-managed A/D updates if enabling hardware updates
> > > > fails.
> > > >
> > > > When Svadu is present without Svade, assume hardware PTE A/D updating
> > > > is enabled from boot, and document that boot-time behavior in the DT
> > > > binding.
> > > >
> > > > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> > > > Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
> > > > ---
> > > >  .../devicetree/bindings/riscv/extensions.yaml |  6 +-
> > > >  arch/riscv/include/asm/cpufeature.h           |  6 ++
> > > >  arch/riscv/include/asm/pgtable.h              |  8 +--
> > > >  arch/riscv/kernel/cpufeature.c                | 58 +++++++++++++++++--
> > > >  4 files changed, 65 insertions(+), 13 deletions(-)
> > > >
> > > > diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
> > > > index 2b0a8a93bb214..b09888e9988de 100644
> > > > --- a/Documentation/devicetree/bindings/riscv/extensions.yaml
> > > > +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
> > > > @@ -294,10 +294,10 @@ properties:
> > > >                 of the PTE A/D bits or page faults when they need updated.
> > > >              2) Only Svade present in DT => Supervisor must assume Svade to be
> > > >                 always enabled.
> > > > -            3) Only Svadu present in DT => Supervisor must assume Svadu to be
> > > > -               always enabled.
> > > > +            3) Only Svadu present in DT => Supervisor must assume Svadu is
> > > > +               enabled at boot.
> > > >              4) Both Svade and Svadu present in DT => Supervisor must assume
> > > > -               Svadu turned-off at boot time. To use Svadu, supervisor must
> > > > +               Svadu is disabled at boot time. To use Svadu, supervisor must
> > > >                 explicitly enable it using the SBI FWFT extension.
> > >
> > > Looks good to me, but I think dt binding changes are typically in separate
> > > patches.
> >
> > Okay, I'll split the DT binding update into a separate patch.
>
> Make sure the appropriate lists and maintainers are CC'ed too.
>
> >
> > >
> > > >
> > > >          - const: svadu
> > > > diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> > > > index 739fcc84bf7b2..ad9fad6eee55d 100644
> > > > --- a/arch/riscv/include/asm/cpufeature.h
> > > > +++ b/arch/riscv/include/asm/cpufeature.h
> > > > @@ -128,6 +128,12 @@ struct riscv_isa_ext_data {
> > > >  extern const struct riscv_isa_ext_data riscv_isa_ext[];
> > > >  extern const size_t riscv_isa_ext_count;
> > > >  extern bool riscv_isa_fallback;
> > > > +DECLARE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
> > > > +
> > > > +static __always_inline bool riscv_has_hw_pte_ad_updating(void)
> > > > +{
> > > > +     return static_branch_unlikely(&riscv_hw_pte_ad_updating);
> > > > +}
> > > >
> > > >  unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
> > > >  static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
> > > > diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
> > > > index a1a7c6520a095..20663a466cf6c 100644
> > > > --- a/arch/riscv/include/asm/pgtable.h
> > > > +++ b/arch/riscv/include/asm/pgtable.h
> > > > @@ -732,14 +732,14 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
> > > >  #define pgprot_dmacoherent pgprot_writecombine
> > > >
> > > >  /*
> > > > - * Both Svade and Svadu control the hardware behavior when the PTE A/D bits need to be set. By
> > > > - * default the M-mode firmware enables the hardware updating scheme when only Svadu is present in
> > > > - * DT.
> > > > + * Both Svade and Svadu control the hardware behavior when the PTE A/D bits
> > > > + * need to be set. The core MM code only cares whether hardware updating of
> > > > + * the accessed/dirty state is currently active.
> > > >   */
> > > >  #define arch_has_hw_pte_young arch_has_hw_pte_young
> > > >  static inline bool arch_has_hw_pte_young(void)
> > > >  {
> > > > -     return riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
> > > > +     return riscv_has_hw_pte_ad_updating();
> > > >  }
> > > >
> > > >  /*
> > > > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > > > index f46aa5602d74d..831dd6a7c1a06 100644
> > > > --- a/arch/riscv/kernel/cpufeature.c
> > > > +++ b/arch/riscv/kernel/cpufeature.c
> > > > @@ -35,6 +35,7 @@
> > > >  static bool any_cpu_has_zicboz;
> > > >  static bool any_cpu_has_zicbop;
> > > >  static bool any_cpu_has_zicbom;
> > > > +DEFINE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
> > > >
> > > >  unsigned long elf_hwcap __read_mostly;
> > > >
> > > > @@ -287,15 +288,60 @@ static int riscv_ext_zvfbfwma_validate(const struct riscv_isa_ext_data *data,
> > > >       return -EPROBE_DEFER;
> > > >  }
> > > >
> > > > -static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data,
> > > > -                                 const unsigned long *isa_bitmap)
> > > > +static void riscv_set_hw_pte_ad_updating(void)
> > > > +{
> > > > +     static_branch_enable(&riscv_hw_pte_ad_updating);
> > > > +}
> > > > +
> > > > +static int riscv_hw_pte_ad_updating_starting(unsigned int cpu)
> > > > +{
> > > > +     int ret;
> > > > +
> > > > +     ret = sbi_fwft_set(SBI_FWFT_PTE_AD_HW_UPDATING, 1, 0);
> > > > +     if (ret) {
> > > > +             if (ret != -EOPNOTSUPP)
> > > > +                     pr_err("CPU%u failed to enable hardware PTE A/D updating: %d\n",
> > > > +                            cpu, ret);
> > > > +             return ret;
> > > > +     }
> > > > +
> > > > +     return 0;
> > > > +}
> > > > +
> > > > +static int __init riscv_hw_pte_ad_updating_init(void)
> > > >  {
> > > > -     /* SVADE has already been detected, use SVADE only */
> > > > -     if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SVADE))
> > > > -             return -EOPNOTSUPP;
> > > > +     bool has_svade, has_svadu;
> > > > +     int state;
> > > >
> > > > +     has_svade = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADE);
> > > > +     has_svadu = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
> > > > +
> > > > +     if (!has_svadu)
> > > > +             return 0;
> > > > +
> > > > +     if (!has_svade)
> > > > +             goto enable;
> > > > +
> > > > +     state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
> > >
> > > I don't think CPUHP_AP_ONLINE_DYN is correct. Setting HW A/D is something
> > > that should be done at _STARTING time.
> >
> > I don't think moving this to _STARTING is the right fix, because this
> > callback can fail, while _STARTING callbacks are not supposed to fail.
> >
> > CPUHP_AP_ONLINE_DYN already covers both the CPUs that are online when
> > cpuhp_setup_state() is called and CPUs brought online later, e.g. with
> > maxcpus=. If FWFT setup fails for a later CPU, only that CPU's online
> > operation is aborted.
>
> The problem is that the later hotplugged harts will see the global static
> key so software won't update A/D bits and HW A/D updating won't be active
> on that hart either until after CPUHP_AP_ONLINE_DYN - risking unexpected
> exceptions. Since _STARTING callbacks can't abort hotplug and since we
> really want HW A/D active before the hart takes its first page fault, then
> maybe this needs to be done at secondary startup time.

Agreed. I'll drop the CPUHP_AP_ONLINE_DYN setup in the next version.

Instead, I plan to enable SBI_FWFT_PTE_AD_HW_UPDATING on all currently
online harts during init, before enabling the global
riscv_hw_pte_ad_updating static key. Later secondary harts will enable
the same FWFT feature at the beginning of smp_callin(), before
notify_cpu_starting() and before they are marked online.

If the init-time FWFT setup fails, the static key will remain disabled and
the kernel will fall back to software-managed A/D updates. If a later
secondary hart fails after the static key has already been enabled, that
hart bringup will be aborted. I'll also add rollback for the init-time
partial failure path.

This should remove the window where a hotplugged hart observes the global
static key but has not enabled local FWFT yet.

>
> Thanks,
> drew

Thanks,
Yunhui


From cuiyunhui at bytedance.com  Mon Jun  8 23:45:05 2026
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Tue, 9 Jun 2026 14:45:05 +0800
Subject: [External] Re: [PATCH v2 1/2] riscv: track effective hardware PTE
 A/D updates
In-Reply-To: <aiK2WPERUEvVMZqY@inochi.infowork>
References: <20260522142358.87589-1-cuiyunhui@bytedance.com> <aiK2WPERUEvVMZqY@inochi.infowork>
Message-ID: <CAEEQ3w=3qKuvPSdqKzUwcojOkwzJY2EjQTnoyaECnsiFjnKvPg@mail.gmail.com>

Hi Inochi,

On Fri, Jun 5, 2026 at 7:45?PM Inochi Amaoto <inochiama at gmail.com> wrote:
>
> On Fri, May 22, 2026 at 10:23:57PM +0800, Yunhui Cui wrote:
> > Track the effective hardware PTE A/D update mode separately from
> > Svadu capability discovery. When both Svade and Svadu are present,
> > enable SBI FWFT PTE A/D hardware updating on each online CPU via
> > CPUHP and use the resulting runtime state for arch_has_hw_pte_young().
> > Fall back to software-managed A/D updates if enabling hardware updates
> > fails.
> >
> > When Svadu is present without Svade, assume hardware PTE A/D updating
> > is enabled from boot, and document that boot-time behavior in the DT
> > binding.
> >
> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> > Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
> > ---
> >  .../devicetree/bindings/riscv/extensions.yaml |  6 +-
> >  arch/riscv/include/asm/cpufeature.h           |  6 ++
> >  arch/riscv/include/asm/pgtable.h              |  8 +--
> >  arch/riscv/kernel/cpufeature.c                | 58 +++++++++++++++++--
> >  4 files changed, 65 insertions(+), 13 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
> > index 2b0a8a93bb214..b09888e9988de 100644
> > --- a/Documentation/devicetree/bindings/riscv/extensions.yaml
> > +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
> > @@ -294,10 +294,10 @@ properties:
> >                 of the PTE A/D bits or page faults when they need updated.
> >              2) Only Svade present in DT => Supervisor must assume Svade to be
> >                 always enabled.
> > -            3) Only Svadu present in DT => Supervisor must assume Svadu to be
> > -               always enabled.
> > +            3) Only Svadu present in DT => Supervisor must assume Svadu is
> > +               enabled at boot.
> >              4) Both Svade and Svadu present in DT => Supervisor must assume
> > -               Svadu turned-off at boot time. To use Svadu, supervisor must
> > +               Svadu is disabled at boot time. To use Svadu, supervisor must
> >                 explicitly enable it using the SBI FWFT extension.
> >
> >          - const: svadu
> > diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
> > index 739fcc84bf7b2..ad9fad6eee55d 100644
> > --- a/arch/riscv/include/asm/cpufeature.h
> > +++ b/arch/riscv/include/asm/cpufeature.h
> > @@ -128,6 +128,12 @@ struct riscv_isa_ext_data {
> >  extern const struct riscv_isa_ext_data riscv_isa_ext[];
> >  extern const size_t riscv_isa_ext_count;
> >  extern bool riscv_isa_fallback;
> > +DECLARE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
> > +
>
> I think a EXPORT_SYMBOL is required, otherwise the kvm is failed to be
> built as module.

  Thanks, I'll fix it in v3.

>
> Regards,
> Inochi
>
>
> > +static __always_inline bool riscv_has_hw_pte_ad_updating(void)
> > +{
> > +     return static_branch_unlikely(&riscv_hw_pte_ad_updating);
> > +}
> >
> >  unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
> >  static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
> > diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
> > index a1a7c6520a095..20663a466cf6c 100644
> > --- a/arch/riscv/include/asm/pgtable.h
> > +++ b/arch/riscv/include/asm/pgtable.h
> > @@ -732,14 +732,14 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
> >  #define pgprot_dmacoherent pgprot_writecombine
> >
> >  /*
> > - * Both Svade and Svadu control the hardware behavior when the PTE A/D bits need to be set. By
> > - * default the M-mode firmware enables the hardware updating scheme when only Svadu is present in
> > - * DT.
> > + * Both Svade and Svadu control the hardware behavior when the PTE A/D bits
> > + * need to be set. The core MM code only cares whether hardware updating of
> > + * the accessed/dirty state is currently active.
> >   */
> >  #define arch_has_hw_pte_young arch_has_hw_pte_young
> >  static inline bool arch_has_hw_pte_young(void)
> >  {
> > -     return riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
> > +     return riscv_has_hw_pte_ad_updating();
> >  }
> >
> >  /*
> > diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> > index f46aa5602d74d..831dd6a7c1a06 100644
> > --- a/arch/riscv/kernel/cpufeature.c
> > +++ b/arch/riscv/kernel/cpufeature.c
> > @@ -35,6 +35,7 @@
> >  static bool any_cpu_has_zicboz;
> >  static bool any_cpu_has_zicbop;
> >  static bool any_cpu_has_zicbom;
> > +DEFINE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
> >
> >  unsigned long elf_hwcap __read_mostly;
> >
> > @@ -287,15 +288,60 @@ static int riscv_ext_zvfbfwma_validate(const struct riscv_isa_ext_data *data,
> >       return -EPROBE_DEFER;
> >  }
> >
> > -static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data,
> > -                                 const unsigned long *isa_bitmap)
> > +static void riscv_set_hw_pte_ad_updating(void)
> > +{
> > +     static_branch_enable(&riscv_hw_pte_ad_updating);
> > +}
> > +
> > +static int riscv_hw_pte_ad_updating_starting(unsigned int cpu)
> > +{
> > +     int ret;
> > +
> > +     ret = sbi_fwft_set(SBI_FWFT_PTE_AD_HW_UPDATING, 1, 0);
> > +     if (ret) {
> > +             if (ret != -EOPNOTSUPP)
> > +                     pr_err("CPU%u failed to enable hardware PTE A/D updating: %d\n",
> > +                            cpu, ret);
> > +             return ret;
> > +     }
> > +
> > +     return 0;
> > +}
> > +
> > +static int __init riscv_hw_pte_ad_updating_init(void)
> >  {
> > -     /* SVADE has already been detected, use SVADE only */
> > -     if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SVADE))
> > -             return -EOPNOTSUPP;
> > +     bool has_svade, has_svadu;
> > +     int state;
> >
> > +     has_svade = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADE);
> > +     has_svadu = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
> > +
> > +     if (!has_svadu)
> > +             return 0;
> > +
> > +     if (!has_svade)
> > +             goto enable;
> > +
> > +     state = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN,
> > +                               "riscv/pte-ad:starting",
> > +                               riscv_hw_pte_ad_updating_starting,
> > +                               NULL);
> > +     if (state < 0) {
> > +             pr_info("riscv: leave PTE A/D updates software-managed (%d)\n",
> > +                     state);
> > +             return 0;
> > +     }
> > +
> > +     /*
> > +      * A successful CPUHP_AP_ONLINE_DYN registration means the startup
> > +      * callback has already succeeded on all online CPUs.
> > +      */
> > +enable:
> > +     riscv_set_hw_pte_ad_updating();
> > +     pr_debug("riscv: hardware PTE A/D updating enabled\n");
> >       return 0;
> >  }
> > +arch_initcall(riscv_hw_pte_ad_updating_init);
> >
> >  static int riscv_cfilp_validate(const struct riscv_isa_ext_data *data,
> >                               const unsigned long *isa_bitmap)
> > @@ -584,7 +630,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
> >       __RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
> >       __RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
> >       __RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),
> > -     __RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate),
> > +     __RISCV_ISA_EXT_DATA(svadu, RISCV_ISA_EXT_SVADU),
> >       __RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
> >       __RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
> >       __RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
> > --
> > 2.39.5
> >

Thanks,
Yunhui


From fustini at kernel.org  Tue Jun  9 00:21:48 2026
From: fustini at kernel.org (Drew Fustini)
Date: Tue, 9 Jun 2026 00:21:48 -0700
Subject: Add fustini riscv-config to linux-next
Message-ID: <aie/DAyvda4bcdLm@x1>

Hi Mark,

I have a new tree where I will apply patches for riscv defconfigs. I
have trees for dt and clk for two riscv soc vendors in next but
defconfig patches don't belong in such branches. Conor has in the past
taken defconfig patches but he is happy for me to send pull requests
as needed based on my new defconfig branches.

Please add these to linux-next:

riscv-config https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#riscv-config-for-next
riscv-config-fixes https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#riscv-config-fixes

Thanks,
Drew


From martin at kaiser.cx  Tue Jun  9 00:27:50 2026
From: martin at kaiser.cx (Martin Kaiser)
Date: Tue, 9 Jun 2026 09:27:50 +0200
Subject: [PATCH v3 1/8] scripts/sorttable: Handle RISC-V patchable ftrace
 entries
In-Reply-To: <20260609063002.3943001-1-wanghan@linux.alibaba.com>
References: <20260528082310.1994388-1-wanghan@linux.alibaba.com>
 <cover.194d76e3a15b.v3.riscv-livepatch.wanghan@linux.alibaba.com>
 <20260609063002.3943001-1-wanghan@linux.alibaba.com>
Message-ID: <aifAdmxJtnVjshl2@nb282.user.codasip.com>

Thus wrote Wang Han (wanghan at linux.alibaba.com):

> RISC-V uses -fpatchable-function-entry=8,4 when the compressed ISA is
> enabled and -fpatchable-function-entry=4,2 otherwise. In both cases, the
> patchable NOP area starts 8 bytes before the function symbol address.
> The __mcount_loc entries therefore point at the patchable NOP area
> associated with a function, while nm reports the function symbol at the
> entry address used for the function range check.

> After RISC-V selected HAVE_BUILDTIME_MCOUNT_SORT, sorttable started
> applying that range check at build time. Without allowing entries just
> before the reported function address, the mcount sorter treats valid
> RISC-V ftrace callsites as invalid weak-function entries and writes
> them back as zero. The resulting kernel boots with no ftrace entries,
> breaking dynamic ftrace and users such as livepatch.

> The failure is silent during the final link because zeroing weak-function
> entries is an expected sorttable operation. At boot, those zero entries
> are skipped by ftrace_process_locs(), so the only obvious symptom is that
> the vmlinux ftrace table has lost valid callsites and ftrace users cannot
> attach to them.

> CONFIG_FTRACE_SORT_STARTUP_TEST also reports the table as sorted in this
> state: it only checks that the __mcount_loc entries are in ascending
> order, which a fully zeroed table trivially satisfies. The original
> commit relied on this check and did not see the regression.

> On an affected RISC-V QEMU boot with both CONFIG_FTRACE_SORT_STARTUP_TEST
> and CONFIG_FTRACE_STARTUP_TEST enabled, the sort check still passes
> while ftrace reports zero usable entries and the early selftests fail:

>   [    0.000000] ftrace section at ffffffff8101da98 sorted properly
>   [    0.000000] ftrace: allocating 0 entries in 128 pages
>   [    0.054999] Testing tracer function: .. no entries found ..FAILED!
>   [    0.172407] tracer: function failed selftest, disabling
>   [    0.178186] Failed to init function_graph tracer, init returned -19

> Handle RISC-V like arm64 for the function-range check and allow
> patchable entries up to 8 bytes before the function address.

> With this fix, a RISC-V QEMU smoke boot with ftrace startup tests shows
> the vmlinux ftrace table is populated and dynamic ftrace still works:

>   [    0.000000] ftrace: allocating 46749 entries in 184 pages
>   [    0.051115] Testing tracer function: PASSED
>   [    1.283782] Testing dynamic ftrace: PASSED
>   [    6.275456] Testing tracer function_graph: PASSED

> Fixes: 0ca1724b56af ("riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT")
> Suggested-by: Steven Rostedt (Google) <rostedt at goodmis.org>
> Reviewed-by: Steven Rostedt <rostedt at goodmis.org>
> Reviewed-by: Shuai Xue <xueshuai at linux.alibaba.com>
> Reviewed-by: Chen Pei <cp0613 at linux.alibaba.com>
> Link: https://lore.kernel.org/all/20260527113028.4b21a5de at fedora/
> Signed-off-by: Wang Han <wanghan at linux.alibaba.com>
> ---
>  scripts/sorttable.c | 11 ++++++++---
>  1 file changed, 8 insertions(+), 3 deletions(-)

> diff --git a/scripts/sorttable.c b/scripts/sorttable.c
> index e8ed11c680c6..d8dc2a1b7c31 100644
> --- a/scripts/sorttable.c
> +++ b/scripts/sorttable.c
> @@ -891,17 +891,22 @@ static int do_file(char const *const fname, void *addr)
>  	table_sort_t custom_sort = NULL;

>  	switch (elf_map_machine(ehdr)) {
> -	case EM_AARCH64:
>  #ifdef MCOUNT_SORT_ENABLED
> +	case EM_AARCH64:
> +		/* arm64 also needs RELA-based weak-function fixups. */
>  		sort_reloc = true;
>  		rela_type = 0x403;
> -		/* arm64 uses patchable function entry placing before function */
> +		/* fallthrough */
> +	case EM_RISCV:
> +		/* arm64 and RISC-V place patchable entries before the function. */
>  		before_func = 8;
> +#else
> +	case EM_AARCH64:
> +	case EM_RISCV:
>  #endif
>  		/* fallthrough */
>  	case EM_386:
>  	case EM_LOONGARCH:
> -	case EM_RISCV:
>  	case EM_S390:
>  	case EM_X86_64:
>  		custom_sort = sort_relative_table_with_data;
> -- 
> 2.43.0

I ran into this problem and came up with pretty much the same fix.

Reviewed-by: Martin Kaiser <martin at kaiser.cx>


From sunilvl at oss.qualcomm.com  Tue Jun  9 01:01:54 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Tue, 9 Jun 2026 13:31:54 +0530
Subject: [PATCH v4 02/10] riscv: Define arch_apei_get_mem_attribute for RISC-V
In-Reply-To: <20260513084325.2176952-3-himanshu.chauhan@oss.qualcomm.com>
References: <20260513084325.2176952-1-himanshu.chauhan@oss.qualcomm.com> <20260513084325.2176952-3-himanshu.chauhan@oss.qualcomm.com>
Message-ID: <CAB19ukExADA6W1pXDqVdA13BGLrtbG1nkfNKVwKyCd4yrNtdMg@mail.gmail.com>

On Wed, May 13, 2026 at 2:13?PM Himanshu Chauhan
<himanshu.chauhan at oss.qualcomm.com> wrote:
>
> ghes_map function uses arch_apei_get_mem_attribute to get the
> protection bits for a given physical address. These protection
> bits are then used to map the physical address.
>
> Signed-off-by: Himanshu Chauhan <himanshu.chauhan at oss.qualcomm.com>
> ---
>  arch/riscv/include/asm/acpi.h | 16 ++++++++++++++++
>  arch/riscv/kernel/acpi.c      | 12 ++++++++++++
>  2 files changed, 28 insertions(+)
>
> diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
> index 26ab37c171bc..c142db9f81a7 100644
> --- a/arch/riscv/include/asm/acpi.h
> +++ b/arch/riscv/include/asm/acpi.h
> @@ -14,6 +14,7 @@
>
>  /* Basic configuration for ACPI */
>  #ifdef CONFIG_ACPI
> +pgprot_t __acpi_get_mem_attribute(phys_addr_t addr);
>
>  typedef u64 phys_cpuid_t;
>  #define PHYS_CPUID_INVALID INVALID_HARTID
> @@ -27,6 +28,21 @@ extern int acpi_disabled;
>  extern int acpi_noirq;
>  extern int acpi_pci_disabled;
>
> +#ifdef CONFIG_ACPI_APEI
> +/*
> + * acpi_disable_cmcff to disable IA-32 Corrected Machine Check (CMC)
> + * Firmware-First mode. It is not required in RISC-V architecture
> + * and is present for compatibility
> + */
> +#define acpi_disable_cmcff 1
> +static inline pgprot_t arch_apei_get_mem_attribute(phys_addr_t addr)
> +{
> +       return  __acpi_get_mem_attribute(addr);
> +}
> +#else /* CONFIG_ACPI_APEI */
> +#define acpi_disable_cmcff 0
> +#endif /* !CONFIG_ACPI_APEI */
> +
>  static inline void disable_acpi(void)
>  {
>         acpi_disabled = 1;
> diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c
> index 068e0b404b6f..7a6770697999 100644
> --- a/arch/riscv/kernel/acpi.c
> +++ b/arch/riscv/kernel/acpi.c
> @@ -204,6 +204,18 @@ struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
>         return &cpu_madt_rintc[cpu];
>  }
>
> +pgprot_t __acpi_get_mem_attribute(phys_addr_t addr)
> +{
> +       u64 attr;
> +
> +       attr = efi_mem_attributes(addr);
> +       if (attr & EFI_MEMORY_WB)
> +               return PAGE_KERNEL;
> +       if ((attr & EFI_MEMORY_WC) || (attr & EFI_MEMORY_WT))
> +               return pgprot_writecombine(PAGE_KERNEL);
> +       return PAGE_KERNEL;
> +}
> +
>  /*
>   * __acpi_map_table() will be called before paging_init(), so early_ioremap()
>   * or early_memremap() should be called here to for ACPI table mapping.
>
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From anup at brainfault.org  Tue Jun  9 01:03:27 2026
From: anup at brainfault.org (Anup Patel)
Date: Tue, 9 Jun 2026 13:33:27 +0530
Subject: [PATCH] irqchip/riscv-imsic: Fix IPI target CPU mapping for
 sparse hartid topology
In-Reply-To: <20260608115935.2194813-1-fanwenhui@masscore.cn>
References: <20260608115935.2194813-1-fanwenhui@masscore.cn>
Message-ID: <CAAhSdy3iqKo=ps9rkeLUWFRTxwEi+7CkFt0z+qYmb-BAruGMwg@mail.gmail.com>

On Mon, Jun 8, 2026 at 5:29?PM Wenhui Fan <fanwenhui at masscore.cn> wrote:
>
> When the system has sparse hartid topology (e.g., only hart0 and hart8
> are online), the current IMSIC driver incorrectly calculates the MSI
> MMIO offset for each CPU. This causes IPIs targeting hart8 to be
> misdirected to hart1.

The current DT-bindings handles sparse hartid perfectly fine. The
interrupts-extended DT property of IMSIC describes the arrangement
of IMSIC files and their mapping to HARTs.

It seems there is some issue with your interrupts-extended DT
property in the IMSIC DT-node. Please share your IMSIC DT node
over here and explain the problem you are facing based on that.

>
> The root cause is that in imsic_setup_state(), the MMIO offset is
> calculated using the parent interrupt index 'i' rather than the actual
> hartid:
>     reloff = i * BIT(global->guest_index_bits) * IMSIC_MMIO_PAGE_SZ;
>
> This assumes a contiguous hartid space, which is not guaranteed in all
> systems. When only hart0 and hart8 are online, the driver receives
> nr_parent_irqs=2, with i=0 for hart0 and i=1 for hart8.
>
> Using i=1 for hart8 results in using the wrong offset which is intended
> for hart1, and causes the MSI configured for hart8 to incorrectly access
> hart1's MSI page.
>
> Fix this by using the actual hartid for offset calculation:
>     reloff = hartid * BIT(global->guest_index_bits) * IMSIC_MMIO_PAGE_SZ;
>
> Fixes: 21a8f8a0eb35 ("irqchip: Add RISC-V incoming MSI controller early driver")
> Signed-off-by: Wenhui Fan <fanwenhui at masscore.cn>
> ---
>  drivers/irqchip/irq-riscv-imsic-state.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/irqchip/irq-riscv-imsic-state.c b/drivers/irqchip/irq-riscv-imsic-state.c
> index e3ed874d8..5f737ec36 100644
> --- a/drivers/irqchip/irq-riscv-imsic-state.c
> +++ b/drivers/irqchip/irq-riscv-imsic-state.c
> @@ -894,7 +894,7 @@ int __init imsic_setup_state(struct fwnode_handle *fwnode, void *opaque)
>
>                 /* Find MMIO location of MSI page */
>                 index = nr_mmios;
> -               reloff = i * BIT(global->guest_index_bits) *
> +               reloff = hartid * BIT(global->guest_index_bits) *
>                          IMSIC_MMIO_PAGE_SZ;

Using hartid to calculate the IMSIC MMIO offset does not algin
with the "interrupts-extended" DT property defined by the IMSIC
DT-bindings.
(Refer, Documentation/devicetree/bindings/interrupt-controller/riscv,imsics.yaml)

Clearly, there is something wrong with your DTS so NACK from
my side.

Regards,
Anup


From sunilvl at oss.qualcomm.com  Tue Jun  9 01:17:03 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Tue, 9 Jun 2026 13:47:03 +0530
Subject: [PATCH v4 05/10] riscv: conditionally compile GHES NMI spool function
In-Reply-To: <20260513084325.2176952-6-himanshu.chauhan@oss.qualcomm.com>
References: <20260513084325.2176952-1-himanshu.chauhan@oss.qualcomm.com> <20260513084325.2176952-6-himanshu.chauhan@oss.qualcomm.com>
Message-ID: <CAB19ukEWxUTnouJLG9pVBkS9VcfdFP_nVdG9T6V_4dAVLDNKxQ@mail.gmail.com>

On Wed, May 13, 2026 at 2:14?PM Himanshu Chauhan
<himanshu.chauhan at oss.qualcomm.com> wrote:
>
> Compile ghes_in_nmi_spool_from_list only when NMI and SEA
> is enabled. Otherwise compilation fails with "defined but
> not used" error.
>
> Signed-off-by: Himanshu Chauhan <himanshu.chauhan at oss.qualcomm.com>
> ---
>  drivers/acpi/apei/ghes.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
> index 3236a3ce79d6..8edc2c8db1bb 100644
> --- a/drivers/acpi/apei/ghes.c
> +++ b/drivers/acpi/apei/ghes.c
> @@ -1397,6 +1397,7 @@ static int ghes_in_nmi_queue_one_entry(struct ghes *ghes,
>         return rc;
>  }
>
> +#if defined(CONFIG_HAVE_ACPI_APEI_NMI) || defined(CONFIG_ACPI_APEI_SEA)
>
>  static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list,
>                                        enum fixed_addresses fixmap_idx)
>  {
> @@ -1415,6 +1416,7 @@ static int ghes_in_nmi_spool_from_list(struct list_head *rcu_list,
>
>         return ret;
>  }
> +#endif
>
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From sunilvl at oss.qualcomm.com  Tue Jun  9 01:27:23 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Tue, 9 Jun 2026 13:57:23 +0530
Subject: [PATCH v4 07/10] riscv: Add RISC-V entries in processor type and
 ISA strings
In-Reply-To: <20260513084325.2176952-8-himanshu.chauhan@oss.qualcomm.com>
References: <20260513084325.2176952-1-himanshu.chauhan@oss.qualcomm.com> <20260513084325.2176952-8-himanshu.chauhan@oss.qualcomm.com>
Message-ID: <CAB19ukHDB6viGCM7FURuqsR_4E=bb8nd-z-Y32+mgrdBT7JB-A@mail.gmail.com>

On Wed, May 13, 2026 at 2:14?PM Himanshu Chauhan
<himanshu.chauhan at oss.qualcomm.com> wrote:
>
> Add RISCV and RISCV32/64 strings in the in processor type and ISA strings
> respectively. These are defined for cper records.
>
> Signed-off-by: Himanshu Chauhan <himanshu.chauhan at oss.qualcomm.com>
> ---
>  drivers/firmware/efi/cper.c | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
> index 06b4fdb59917..1b1ab2f1355b 100644
> --- a/drivers/firmware/efi/cper.c
> +++ b/drivers/firmware/efi/cper.c
> @@ -170,6 +170,7 @@ static const char * const proc_type_strs[] = {
>         "IA32/X64",
>         "IA64",
>         "ARM",
> +       "RISC-V",
>  };
>
>  static const char * const proc_isa_strs[] = {
> @@ -178,6 +179,8 @@ static const char * const proc_isa_strs[] = {
>         "X64",
>         "ARM A32/T32",
>         "ARM A64",
> +       "RV32/RV32E",
> +       "RV64",
>  };
>
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From changhuang.liang at starfivetech.com  Tue Jun  9 02:13:37 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Tue, 9 Jun 2026 09:13:37 +0000
Subject: [PATCH v3 18/21] pinctrl: starfive: Add StarFive JHB100 per2pok
 controller driver
In-Reply-To: <CAMRc=Md1z52A_JzMG=3Ce5nN-HMvwH0TO=t2jEqC3kdCQK8EwA@mail.gmail.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-19-changhuang.liang@starfivetech.com>
 <CAMRc=Md1z52A_JzMG=3Ce5nN-HMvwH0TO=t2jEqC3kdCQK8EwA@mail.gmail.com>
Message-ID: <ZQ4PR01MB1202592BD39A138751CE14F1F21D2@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>

Hi, Bartosz

Thanks for the review.

> On Wed, 3 Jun 2026 07:53:44 +0200, Changhuang Liang
> <changhuang.liang at starfivetech.com> said:
> > Add pinctrl driver for StarFive JHB100 SoC Peripheral-2 Power OK
> > (per2pok) pinctrl controller.
> >
> > Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> > Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> > Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
> > ---
> >  drivers/pinctrl/starfive/Kconfig              | 12 +++
> >  drivers/pinctrl/starfive/Makefile             |  1 +
> >  .../pinctrl-starfive-jhb100-per2pok.c         | 97
> +++++++++++++++++++
> >  3 files changed, 110 insertions(+)
> >  create mode 100644
> > drivers/pinctrl/starfive/pinctrl-starfive-jhb100-per2pok.c
> >
> > diff --git a/drivers/pinctrl/starfive/Kconfig
> > b/drivers/pinctrl/starfive/Kconfig
> > index edc3b6d9c8d7..bf5915e0a5f2 100644
> > --- a/drivers/pinctrl/starfive/Kconfig
> > +++ b/drivers/pinctrl/starfive/Kconfig
> > @@ -91,6 +91,18 @@ config PINCTRL_STARFIVE_JHB100_PER2
> >  	  peripherals supporting inputs, outputs, configuring pull-up/pull-down
> >  	  and interrupts on input changes.
> >
> > +config PINCTRL_STARFIVE_JHB100_PER2POK
> > +	tristate "StarFive JHB100 SoC Peripheral-2 Power OK pinctrl and GPIO
> driver"
> > +	depends on ARCH_STARFIVE || COMPILE_TEST
> > +	depends on OF
> 
> I don't see any real dependency on CONFIG_OF here, am I missing something?
> The OF ID matching is available even with !CONFIG_OF.

I will move it under config PINCTRL_STARFIVE_JHB100.

> 
> Same elsewhere.
> 
> Bart

Best Regards,
Changhuang

From lpieralisi at kernel.org  Tue Jun  9 02:19:00 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Tue, 9 Jun 2026 11:19:00 +0200
Subject: [PATCH v2 1/6] ACPI: RISC-V: Fix riscv_acpi_irq_get_dep() loop
 termination
In-Reply-To: <CAB19ukFFwm3ehzkBFr+oXRjA7VK_4_=XHFSuqdEpbVqUz8Do4Q@mail.gmail.com>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-1-23ffa16b6ebb@kernel.org>
 <CAB19ukFFwm3ehzkBFr+oXRjA7VK_4_=XHFSuqdEpbVqUz8Do4Q@mail.gmail.com>
Message-ID: <aifahCtdj8GpHN/v@lpieralisi>

On Mon, Jun 08, 2026 at 09:54:28PM +0530, Sunil V L wrote:
> Hi Lorenzo,
> 
> On Wed, Jun 3, 2026 at 1:51?PM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
> >
> > In riscv_acpi_add_irq_dep() the main loop condition would currently stop
> > the loop if an interrupt descriptor contains an interrupt for which the
> > respective GSI handle is NULL, which is not correct because subsequent
> > interrupts in the interrupt descriptor might still have a GSI dependency
> > that must not be skipped.
> >
> > Rework riscv_acpi_add_irq_dep() and the riscv_acpi_irq_get_dep() call chain
> > to fix it - by not forcing the loop to stop in order to guarantee
> > dependency detection for all the interrupt entries in the CRS descriptor.
> >
> > Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> > Cc: "Rafael J. Wysocki" <rafael at kernel.org>
> > Cc: Sunil V L <sunilvl at ventanamicro.com>
> > ---
> >  drivers/acpi/riscv/irq.c | 10 ++++++----
> >  1 file changed, 6 insertions(+), 4 deletions(-)
> >
> > diff --git a/drivers/acpi/riscv/irq.c b/drivers/acpi/riscv/irq.c
> > index 9b88d0993e88..cd83c3035cf6 100644
> > --- a/drivers/acpi/riscv/irq.c
> > +++ b/drivers/acpi/riscv/irq.c
> > @@ -299,6 +299,7 @@ static acpi_status riscv_acpi_irq_get_parent(struct acpi_resource *ares, void *c
> >                         return AE_OK;
> >
> >                 ctx->handle = riscv_acpi_get_gsi_handle(eirq->interrupts[ctx->index]);
> > +               ctx->rc = 0;
> >                 return AE_CTRL_TERMINATE;
> >         }
> >
> > @@ -314,10 +315,8 @@ static int riscv_acpi_irq_get_dep(acpi_handle handle, unsigned int index, acpi_h
> >
> >         acpi_walk_resources(handle, METHOD_NAME__CRS, riscv_acpi_irq_get_parent, &ctx);
> >         *gsi_handle = ctx.handle;
> > -       if (*gsi_handle)
> > -               return 1;
> >
> > -       return 0;
> > +       return ctx.rc;
> >  }
> >
> >  static u32 riscv_acpi_add_prt_dep(acpi_handle handle)
> > @@ -381,8 +380,11 @@ static u32 riscv_acpi_add_irq_dep(acpi_handle handle)
> >         int i;
> >
> >         for (i = 0;
> > -            riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
> > +            !riscv_acpi_irq_get_dep(handle, i, &gsi_handle);
> >              i++) {
> > +               if (!gsi_handle)
> > +                       continue;
> > +
> >                 dep_devices.count = 1;
> >                 dep_devices.handles = kzalloc_objs(*dep_devices.handles, 1);
> >                 if (!dep_devices.handles) {
> >
> Do these fixes need the Fixes tag?

I can add a Fixes: tag but I wanted first some help testing them, it
is code perusal that got me there.

> Otherwise, LGTM.
> Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>

Thanks,
Lorenzo


From lpieralisi at kernel.org  Tue Jun  9 02:31:31 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Tue, 9 Jun 2026 11:31:31 +0200
Subject: [PATCH v2 6/6] irqchip/gic-v5: Enable GICv5 IWB ACPI probe
 ordering detection
In-Reply-To: <CAJZ5v0ibZKfzJwGyUb92-K1N9C_ab0QujpAKCrvMdyygquS1Vw@mail.gmail.com>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-6-23ffa16b6ebb@kernel.org>
 <CAJZ5v0ibZKfzJwGyUb92-K1N9C_ab0QujpAKCrvMdyygquS1Vw@mail.gmail.com>
Message-ID: <aifdc2E/+YCvCnwG@lpieralisi>

On Mon, Jun 08, 2026 at 07:18:15PM +0200, Rafael J. Wysocki wrote:
> On Wed, Jun 3, 2026 at 10:21?AM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
> >
> > Register an ACPI hook in the ACPI interrupt management code for GICv5 to
> > retrieve the ACPI interrupt controller handle (if any) of the controller
> > handling a specific GSI, by updating the acpi_set_irq_model() call with
> > the gic_v5_get_gsi_handle() function pointer parameter.
> >
> > gicv5_get_gsi_handle() allows ACPI core to detect the ACPI handle
> > of the controller that manages a specific GSI interrupt.
> >
> > Update the IWB driver to clear device dependencies in ACPI core once the
> > IWB driver has probed.
> >
> > Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> > Cc: Thomas Gleixner <tglx at kernel.org>
> > Cc: Marc Zyngier <maz at kernel.org>
> > ---
> >  drivers/irqchip/irq-gic-v5-iwb.c |  5 +++++
> >  drivers/irqchip/irq-gic-v5.c     | 13 +++++++++++--
> >  2 files changed, 16 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c
> > index 9103feb70ce8..a02cb9537b15 100644
> > --- a/drivers/irqchip/irq-gic-v5-iwb.c
> > +++ b/drivers/irqchip/irq-gic-v5-iwb.c
> > @@ -269,6 +269,11 @@ static int gicv5_iwb_device_probe(struct platform_device *pdev)
> >         if (IS_ERR(iwb_node))
> >                 return PTR_ERR(iwb_node);
> >
> > +#ifdef CONFIG_ACPI
> > +       if (has_acpi_companion(&pdev->dev))
> > +               acpi_dev_clear_dependencies(ACPI_COMPANION(&pdev->dev));
> > +#endif
> 
> I would rather add a wrapper for this, along with an empty stub for
> the !CONFIG_ACPI case.

Ok, I will.

> > +
> >         return 0;
> >  }
> >
> > diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
> > index 03cc2830b260..26cfaea1af41 100644
> > --- a/drivers/irqchip/irq-gic-v5.c
> > +++ b/drivers/irqchip/irq-gic-v5.c
> > @@ -1217,11 +1217,19 @@ static struct fwnode_handle *gsi_domain_handle;
> >  static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
> >  {
> >         if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
> > -               return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> > +               return iort_iwb_handle_fwnode(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> 
> Why is this change needed?

This is a mistake, thanks for spotting it, it belongs in the previous patch
(IMO patch 5 and 6 are a single logical entity, I split it to try to keep
irqchip specific changes in one patch).

iort_iwb_handle() was refactored to return an acpi_handle not a fwnode_handle
(in preparation for adding gic_v5_get_gsi_handle() below - the dependency
chain requires acpi_handle retrieval not fwnode_handle), so the change above
belongs in patch 5, I will move this line change to patch 5 in v3.

Thanks,
Lorenzo

> >
> >         return gsi_domain_handle;
> >  }
> >
> > +static acpi_handle gic_v5_get_gsi_handle(u32 gsi)
> > +{
> > +       if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
> > +               return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> > +
> > +       return NULL;
> > +}
> > +
> >  static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
> >  {
> >         struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
> > @@ -1242,7 +1250,8 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
> >         if (ret)
> >                 goto out_irs;
> >
> > -       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id, NULL);
> > +       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id,
> > +                          gic_v5_get_gsi_handle);
> >
> >         return 0;
> >
> >
> > --


From conor at kernel.org  Tue Jun  9 02:43:33 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 9 Jun 2026 10:43:33 +0100
Subject: [PATCH v2] hwmon: add a driver for the temp/voltage sensor on
 PolarFire SoC
In-Reply-To: <fd92d7c9-9594-47b9-bd84-a6bd5ebae66d@roeck-us.net>
References: <20260603-ongoing-brunette-51e35be6d93e@spud>
 <fd92d7c9-9594-47b9-bd84-a6bd5ebae66d@roeck-us.net>
Message-ID: <20260609-estrogen-entangled-da00ac932481@spud>

On Mon, Jun 08, 2026 at 10:03:48AM -0700, Guenter Roeck wrote:
> On 6/3/26 06:19, Conor Dooley wrote:
> > From: Lars Randers <lranders at mail.dk>
> > 
> > Add a driver for the temperature and voltage sensors on PolarFire SoC.
> > The temperature reports how hot the die is, and the voltages are the
> > SoC's 1.05, 1.8 and 2.5 volt rails respectively.
> > 
> > The hardware supports alarms in theory, but there is an erratum that
> > prevents clearing them once triggered, so no support is added for them.
> > 
> > The hardware measures voltage with 16 bits, of which 1 is a sign bit and
> > the remainder holds the voltage as a fixed point integer value. It's
> > improbable that the hardware will work if the voltages are negative, so
> > the driver ignores the sign bits.
> > 
> > There's no dt support etc here because this is the child of a simple-mfd
> > syscon.
> > 
> > Signed-off-by: Lars Randers <lranders at mail.dk>
> > Co-developed-by: Conor Dooley <conor.dooley at microchip.com>
> > Signed-off-by: Conor Dooley <conor.dooley at microchip.com>
> 
> Comments inline.

Cheers.

> > v2:
> > - Fix some minor things pointed out by Sashiko including inaccurate
> >    comments, bounds checking of values read from sysfs and Kconfig
> >    dependencies.
> > - Make update_interval use milliseconds instead of microseconds
> >    (I'll add update_interval_us support when that lands, there's a
> >    proposed workaround for the erratum circulating internally, so it'll
> >    probably come alongside alarm support).
> > 
> > CC: Guenter Roeck <linux at roeck-us.net>
> > CC: Jonathan Corbet <corbet at lwn.net>
> > CC: Shuah Khan <skhan at linuxfoundation.org>
> > CC: Conor Dooley <conor.dooley at microchip.com>
> > CC: Daire McNamara <daire.mcnamara at microchip.com>
> > CC: linux-hwmon at vger.kernel.org
> > CC: linux-doc at vger.kernel.org
> > CC: linux-kernel at vger.kernel.org
> > CC: linux-riscv at lists.infradead.org
> > CC: Valentina.FernandezAlanis at microchip.com

> > +Usage Notes
> > +-----------
> > +
> > +update_interval has a permitted range of 0 to 8.
> > +
> > +
> 
> It might make sense to document what "0" means.

Sure. The interval governs how much of a delay there is between the end
of one measurement and the start of the next one. Zero means no delay,
both here and in the register. Think that answers your question below
too?

> > +static int mpfs_tvs_temp_read(struct mpfs_tvs *data, u32 attr, long *val)
> > +{
> > +	u32 tmp, control;
> > +
> > +	if (attr != hwmon_temp_input && attr != hwmon_temp_enable)
> > +		return -EOPNOTSUPP;
> > +
> > +	regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
> > +
> > +	if (attr == hwmon_temp_enable) {
> > +		*val = FIELD_GET(MPFS_TVS_CTRL_TEMP_ENABLE, control);
> > +		return 0;
> > +	}
> > +
> > +	if (!(control & MPFS_TVS_CTRL_TEMP_VALID))
> > +		return -EINVAL;
> > +
> "Invalid argument" can not be correct for data read from the chip.
> I don't know what this means. It should be either -ENODATA (no data available)
> if this is transient or -EIO (I/O error) if it is a permanent problem.
> The same applies to other validation checks.

-ENODATA then. It's realistically only possible to hit this when the
channel is disabled, although in you can also hit it in the gap
between the channel being enabled and the first measurement becoming
available.


> > +	regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
> > +	*val = FIELD_GET(MPFS_OUTPUT1_TEMP_MASK, tmp);
> > +	*val -= MPFS_TVS_K_TO_C;
> > +	*val = (1000 * *val) >> 4; /* fixed point (11.4) to millidegrees */
> > +
> > +	return 0;
> > +}

> > +static int mpfs_tvs_interval_write(struct mpfs_tvs *data, u32 attr, long val)
> > +{
> > +	unsigned long temp = val;
> > +
> > +	if (attr != hwmon_chip_update_interval)
> > +		return -EOPNOTSUPP;
> > +
> > +	temp *= 1000;
> 
> This is likely to result in overflow issues (for example if val == LONG_MAX).
> 
> > +	temp /= MPFS_TVS_INTERVAL_SCALE;
> > +
> > +	/*
> > +	 * The value is 8 bits wide, but 255 is described as
> > +	 * "255= Do single set of transfers when scoverride set"
> > +	 * but there's no scoverride bit in the tvs register region.
> > +	 * Ban using 255 since its behaviour is suspect.
> > +	 */
> > +	if (temp > 254)
> > +		return -EINVAL;
> 
> Hardware monitoring drivers should use clamp() and not return -EINVAL
> for ranges such as this. Since the valid range (in ms) is 0..8, I would
> suggest to clamp val to (0, 8) before any calculations to also avoid

Sure, I'll do that.

> the overflow issue mentioned above. That makes me wonder: What does "0"
> stand for ? 32 us or 0 us ? It does not make a difference here, but it
> may be relevant when microsecond intervals are implemented.

I think I answered this above, but 0 means 0 us between the end of a
measurement/conversion and the start of the next one. 

> > +
> > +	temp <<= MPFS_TVS_INTERVAL_OFFSET;
> > +	regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
> > +			   MPFS_TVS_INTERVAL_MASK, temp);
> 
> If regmap never returns errors this needs to be documented in the driver.

It's an mmio regmap via a syscon, it evaluates to readl()/writel() so
there's nothing that can fail /and/ return an error.
I mean, I can add if (ret) return ret, there's not a clean place to put
a comment about it I don't think.

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260609/5152edfe/attachment.sig>

From broonie at kernel.org  Tue Jun  9 04:18:50 2026
From: broonie at kernel.org (Mark Brown)
Date: Tue, 9 Jun 2026 12:18:50 +0100
Subject: Add fustini riscv-config to linux-next
In-Reply-To: <aie/DAyvda4bcdLm@x1>
References: <aie/DAyvda4bcdLm@x1>
Message-ID: <aif2mpLE3n6lJwLa@sirena.co.uk>

On Tue, Jun 09, 2026 at 12:21:48AM -0700, Drew Fustini wrote:

> Please add these to linux-next:
> 
> riscv-config https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#riscv-config-for-next
> riscv-config-fixes https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git#riscv-config-fixes

These should be added from today.

Thanks for adding your subsystem tree as a participant of linux-next.  As
you may know, this is not a judgement of your code.  The purpose of
linux-next is for integration testing and to lower the impact of
conflicts between subsystems in the next merge window.

You will need to ensure that the patches/commits in your tree/series have
been:
     * submitted under GPL v2 (or later) and include the Contributor's
        Signed-off-by,
     * posted to the relevant mailing list,
     * reviewed by you (or another maintainer of your subsystem tree),
     * successfully unit tested, and
     * destined for the current or next Linux merge window.

Basically, this should be just what you would send to Linus (or ask him
to fetch).  It is allowed to be rebased if you deem it necessary.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 488 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260609/5ecfa8b1/attachment.sig>

From wang.yechao255 at zte.com.cn  Tue Jun  9 04:28:56 2026
From: wang.yechao255 at zte.com.cn (wang.yechao255 at zte.com.cn)
Date: Tue, 9 Jun 2026 19:28:56 +0800 (CST)
Subject: =?UTF-8?B?W1BBVENIXSBBQ1BJOiBSSVNDLVY6IEZpeCBmYWxzZSB3YXJuaW5nIGluIGNwcGNfcmVhZF9mZmgoKSBmb3Igc2FtZS1DUFUgcmVhZHM=?=
Message-ID: <20260609192856874Y8AaPpKL5TnmbgiWI8DI3@zte.com.cn>

From: Wang Yechao <wang.yechao255 at zte.com.cn>

Commit 997c021abc6e ("cpufreq: CPPC: Update FIE arch_freq_scale in
ticks for non-PCC regs") changed the CPPC Frequency Invariance Engine
to read AMU counters directly from the scheduler tick for non-PCC
register spaces (like FFH), instead of deferring to a kthread. This
means cppc_read_ffh() is now called with IRQs disabled from the tick
handler, triggering the warning.

This is the same fix as commit df6e4ab654dc ("arm64: topology: Fix
false warning in counters_read_on_cpu() for same-CPU reads").

Fixes: 997c021abc6e ("cpufreq: CPPC: Update FIE arch_freq_scale in ticks for non-PCC regs")
Signed-off-by: Wang Yechao <wang.yechao255 at zte.com.cn>
---
 drivers/acpi/riscv/cppc.c | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/drivers/acpi/riscv/cppc.c b/drivers/acpi/riscv/cppc.c
index 42c1a9052470..5dce0377a8df 100644
--- a/drivers/acpi/riscv/cppc.c
+++ b/drivers/acpi/riscv/cppc.c
@@ -98,16 +98,19 @@ int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
 {
 	struct sbi_cppc_data data;

-	if (WARN_ON_ONCE(irqs_disabled()))
-		return -EPERM;
-
 	if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_SBI) {
 		if (!cppc_ext_present)
 			return -EINVAL;

 		data.reg = FFH_CPPC_SBI_REG(reg->address);

-		smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
+		if (irqs_disabled()) {
+			if (WARN_ON_ONCE(cpu != smp_processor_id()))
+				return -EPERM;
+			sbi_cppc_read(&data);
+		} else {
+			smp_call_function_single(cpu, sbi_cppc_read, &data, 1);
+		}

 		*val = data.ret.value;

@@ -115,7 +118,13 @@ int cpc_read_ffh(int cpu, struct cpc_reg *reg, u64 *val)
 	} else if (FFH_CPPC_TYPE(reg->address) == FFH_CPPC_CSR) {
 		data.reg = FFH_CPPC_CSR_NUM(reg->address);

-		smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
+		if (irqs_disabled()) {
+			if (WARN_ON_ONCE(cpu != smp_processor_id()))
+				return -EPERM;
+			cppc_ffh_csr_read(&data);
+		} else {
+			smp_call_function_single(cpu, cppc_ffh_csr_read, &data, 1);
+		}

 		*val = data.ret.value;

-- 
2.43.5


From krzk at kernel.org  Tue Jun  9 04:46:28 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 9 Jun 2026 13:46:28 +0200
Subject: [GIT PULL] RISC-V Tenstorrent devicetree changes for v7.2
In-Reply-To: <ah4Qfro/wUyhByF8@x1>
References: <ah4Qfro/wUyhByF8@x1>
Message-ID: <20260609-wise-fragrant-sturgeon-4e5eda@quoll>

On Mon, Jun 01, 2026 at 04:06:38PM -0700, Drew Fustini wrote:
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> 
>   Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> 
> are available in the Git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/tenstorrent/linux.git tags/tenstorrent-dt-for-v7.2
> 
> for you to fetch changes up to 33583baeb1ba7d328e6a9775d889036900b74cdb:
> 
>   dt-bindings: iommu: riscv: Add bindings for Tenstorrent RISC-V IOMMU (2026-05-23 17:14:35 -0700)
> 

Thanks, applied

Best regards,
Krzysztof



From krzk at kernel.org  Tue Jun  9 04:54:45 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 9 Jun 2026 13:54:45 +0200
Subject: [GIT PULL] RISC-V T-HEAD devicetree changes for v7.2
In-Reply-To: <ah4lkWh2eD6l7W7n@x1>
References: <ah4lkWh2eD6l7W7n@x1>
Message-ID: <20260609-shaggy-careful-rabbit-e0fc2a@quoll>

On Mon, Jun 01, 2026 at 05:36:33PM -0700, Drew Fustini wrote:
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> 
>   Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> 
> are available in the Git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git tags/thead-dt-for-v7.2
> 
> for you to fetch changes up to 3a5791956edbfa84d7256224167941931cbc46e7:
> 
>   riscv: dts: thead: Enable wifi on the BeagleV-Ahead (2026-05-25 01:36:56 -0700)
> 

Thanks, applied

Best regards,
Krzysztof



From krzk at kernel.org  Tue Jun  9 05:00:19 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 9 Jun 2026 14:00:19 +0200
Subject: [GIT PULL] RISC-V SpacemiT Devicetrees for v7.2
In-Reply-To: <20260602070257-KYC5031219@kernel.org>
References: <20260602070257-KYC5031219@kernel.org>
Message-ID: <20260609-pompous-imposing-dragon-fc18cb@quoll>

On Tue, Jun 02, 2026 at 07:10:07AM +0000, Yixun Lan wrote:
> Hi SoC Maintainers,
> 
>    Please pull SpacemiT's DeviceTree changes for v7.2
> 
> Yixun Lan
> 
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> 
>   Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> 
> are available in the Git repository at:
> 
>   https://github.com/spacemit-com/linux spacemit-dt-for-7.2-1

Please switch to kernel.org repo. Github is not really a trusted place
and you have kernel.org account, so not sure why Github is still there.

> 
> for you to fetch changes up to 793cc54475b49b5b558902b5c13e4bfe66530a50:
> 
>   riscv: dts: spacemit: enable PMIC on OrangePi R2S (2026-06-01 06:32:42 +0000)
> 
> ----------------------------------------------------------------
> RISC-V SpacemiT DT changes for 7.2

Thanks, applied

Best regards,
Krzysztof



From thecharlesjenkins at gmail.com  Tue Jun  9 05:09:48 2026
From: thecharlesjenkins at gmail.com (Charlie Jenkins)
Date: Tue, 9 Jun 2026 05:09:48 -0700
Subject: [PATCH v3 RESEND] riscv: hwprobe: allow querying available
 RISCV_HWPROBE_KEY_IMA_EXT_0 bits
In-Reply-To: <20250825-6d7eedc4459b72ceb07ce782@orel>
References: <20250814221646.32140-1-parisoplop@gmail.com>
 <20250825170258.24068-1-parisoplop@gmail.com>
 <20250825-6d7eedc4459b72ceb07ce782@orel>
Message-ID: <aigCjG1HbSqUTx_F@blinky>

On Mon, Aug 25, 2025 at 05:00:45PM -0500, Andrew Jones wrote:
> On Mon, Aug 25, 2025 at 08:02:21PM +0300, offtkp wrote:
> > When probing for extensions using RISCV_HWPROBE_KEY_IMA_EXT_0, a missing
> > bit in the resulting bitmask means the extension is not available or the
> > kernel is not recent enough to support the bit. Currently, there's no
> > way to differentiate between the two.
> > 
> > This adds a new riscv_hwprobe key, RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL,
> > which returns a bitmask of all the queryable extensions supported by the
> > kernel in RISCV_HWPROBE_KEY_IMA_EXT_0. This can allow programs to use a
> > fallback extension detection method when the bit they want to query is
> > not available in the kernel they are running on.
> > 
> > Signed-off-by: offtkp <parisoplop at gmail.com>
> > ---
> > Changes in v3:
> > - remove the 59 magic number and create the mask as a define
> > 
> > Conversation from v2 to show motivation for this patch as a whole:
> > 
> > > And do you have a real usecase in
> > > mind? I mean which project would benefit from this?
> > Yes, I want this feature for an x86-on-RISC-V userspace emulator
> > called felix86. We do runtime extension detection for our JIT.
> > Currently, for any extension that defines instructions we use the SIGILL
> > method previously described, because there's no way to tell with just
> > a hwprobe call whether a 0 bit means extension not present or kernel
> > too old. But we can't do this for all extensions, some don't define
> > instructions.
> > 
> > The end goal would be being able to detect an extension using hwprobe,
> > and if it's not detectable, notifying the user that we can't detect it and
> > they can mark it as enabled in the emulator's config file.
> 
> As I pointed out on v2, I don't think this patch helps. When the kernel
> is unaware of the extension, then we still know nothing about its
> availability. This is only helpful when the kernel is aware of an
> extension, but, in those cases, the current hwprobe can be trusted, so
> we don't need this.

You are correct to say that when the kernel reports that an extension as
"0" that there is no way for the userspace application to be able to
use the extension, the kernel reporting as "unaware" does not help with
this.

This patch from Paris, however, is not about dynamically increasing the
number of extensions that a userspace application can use but rather
simply about error/debug reporting.

I think this kind of reporting is a valid usecase for a hwprobe feature
and would be able to improve user experience of userspace applications.

- Charlie

> 
> The problem is there's no good way to detect extensions that the kernel
> is unaware of, which means the kernel needs to blindly expose what's in
> the DT/ACPI somehow.
> 
> Thanks,
> drew
> 
> > 
> > 
> > 
> >  Documentation/arch/riscv/hwprobe.rst  |  5 ++++-
> >  arch/riscv/include/asm/hwprobe.h      | 29 ++++++++++++++++++++++++++-
> >  arch/riscv/include/uapi/asm/hwprobe.h |  2 ++
> >  arch/riscv/kernel/sys_hwprobe.c       |  4 ++++
> >  4 files changed, 38 insertions(+), 2 deletions(-)
> > 
> > diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
> > index 2aa9be272d5d..6d77def0a46e 100644
> > --- a/Documentation/arch/riscv/hwprobe.rst
> > +++ b/Documentation/arch/riscv/hwprobe.rst
> > @@ -360,4 +360,7 @@ The following keys are defined:
> >  
> >      * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ`: The Xsfvfwmaccqqq
> >          vendor extension is supported in version 1.0 of Matrix Multiply Accumulate
> > -	Instruction Extensions Specification.
> > \ No newline at end of file
> > +	Instruction Extensions Specification.
> > +
> > +* :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL`: A bitmask containing the extensions
> > +  that can be probed using the :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0` key.
> > \ No newline at end of file
> > diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h
> > index 7fe0a379474a..a06eeec11e2c 100644
> > --- a/arch/riscv/include/asm/hwprobe.h
> > +++ b/arch/riscv/include/asm/hwprobe.h
> > @@ -8,7 +8,34 @@
> >  
> >  #include <uapi/asm/hwprobe.h>
> >  
> > -#define RISCV_HWPROBE_MAX_KEY 13
> > +#define RISCV_HWPROBE_MAX_KEY 14
> > +#define RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL_VALUE	(RISCV_HWPROBE_IMA_FD | \
> > +	RISCV_HWPROBE_IMA_C | RISCV_HWPROBE_IMA_V | RISCV_HWPROBE_EXT_ZBA | \
> > +	RISCV_HWPROBE_EXT_ZBB | RISCV_HWPROBE_EXT_ZBS | RISCV_HWPROBE_EXT_ZICBOZ | \
> > +	RISCV_HWPROBE_EXT_ZBC | RISCV_HWPROBE_EXT_ZBKB | RISCV_HWPROBE_EXT_ZBKC | \
> > +	RISCV_HWPROBE_EXT_ZBKX | RISCV_HWPROBE_EXT_ZKND | RISCV_HWPROBE_EXT_ZKNE | \
> > +	RISCV_HWPROBE_EXT_ZKNH | RISCV_HWPROBE_EXT_ZKSED | \
> > +	RISCV_HWPROBE_EXT_ZKSH | RISCV_HWPROBE_EXT_ZKT | RISCV_HWPROBE_EXT_ZVBB | \
> > +	RISCV_HWPROBE_EXT_ZVBC | RISCV_HWPROBE_EXT_ZVKB | RISCV_HWPROBE_EXT_ZVKG | \
> > +	RISCV_HWPROBE_EXT_ZVKNED | RISCV_HWPROBE_EXT_ZVKNHA | \
> > +	RISCV_HWPROBE_EXT_ZVKNHB | RISCV_HWPROBE_EXT_ZVKSED | \
> > +	RISCV_HWPROBE_EXT_ZVKSH | RISCV_HWPROBE_EXT_ZVKT | \
> > +	RISCV_HWPROBE_EXT_ZFH | RISCV_HWPROBE_EXT_ZFHMIN | \
> > +	RISCV_HWPROBE_EXT_ZIHINTNTL | RISCV_HWPROBE_EXT_ZVFH | \
> > +	RISCV_HWPROBE_EXT_ZVFHMIN | RISCV_HWPROBE_EXT_ZFA | \
> > +	RISCV_HWPROBE_EXT_ZTSO | RISCV_HWPROBE_EXT_ZACAS | \
> > +	RISCV_HWPROBE_EXT_ZICOND | RISCV_HWPROBE_EXT_ZIHINTPAUSE | \
> > +	RISCV_HWPROBE_EXT_ZVE32X | RISCV_HWPROBE_EXT_ZVE32F | \
> > +	RISCV_HWPROBE_EXT_ZVE64X | RISCV_HWPROBE_EXT_ZVE64F | \
> > +	RISCV_HWPROBE_EXT_ZVE64D | RISCV_HWPROBE_EXT_ZIMOP | \
> > +	RISCV_HWPROBE_EXT_ZCA | RISCV_HWPROBE_EXT_ZCB | RISCV_HWPROBE_EXT_ZCD | \
> > +	RISCV_HWPROBE_EXT_ZCF | RISCV_HWPROBE_EXT_ZCMOP | \
> > +	RISCV_HWPROBE_EXT_ZAWRS | RISCV_HWPROBE_EXT_SUPM | \
> > +	RISCV_HWPROBE_EXT_ZICNTR | RISCV_HWPROBE_EXT_ZIHPM | \
> > +	RISCV_HWPROBE_EXT_ZFBFMIN | RISCV_HWPROBE_EXT_ZVFBFMIN | \
> > +	RISCV_HWPROBE_EXT_ZVFBFWMA | RISCV_HWPROBE_EXT_ZICBOM | \
> > +	RISCV_HWPROBE_EXT_ZAAMO | RISCV_HWPROBE_EXT_ZALRSC | \
> > +	RISCV_HWPROBE_EXT_ZABHA)
> >  
> >  static inline bool riscv_hwprobe_key_is_valid(__s64 key)
> >  {
> > diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
> > index aaf6ad970499..a3b92df4dc05 100644
> > --- a/arch/riscv/include/uapi/asm/hwprobe.h
> > +++ b/arch/riscv/include/uapi/asm/hwprobe.h
> > @@ -82,6 +82,7 @@ struct riscv_hwprobe {
> >  #define		RISCV_HWPROBE_EXT_ZAAMO		(1ULL << 56)
> >  #define		RISCV_HWPROBE_EXT_ZALRSC	(1ULL << 57)
> >  #define		RISCV_HWPROBE_EXT_ZABHA		(1ULL << 58)
> > +/* Change RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL_VALUE when adding items. */
> >  #define RISCV_HWPROBE_KEY_CPUPERF_0	5
> >  #define		RISCV_HWPROBE_MISALIGNED_UNKNOWN	(0 << 0)
> >  #define		RISCV_HWPROBE_MISALIGNED_EMULATED	(1 << 0)
> > @@ -106,6 +107,7 @@ struct riscv_hwprobe {
> >  #define RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0	11
> >  #define RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE	12
> >  #define RISCV_HWPROBE_KEY_VENDOR_EXT_SIFIVE_0	13
> > +#define RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL 14
> >  /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
> >  
> >  /* Flags */
> > diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
> > index 0b170e18a2be..40e7fa5f85f3 100644
> > --- a/arch/riscv/kernel/sys_hwprobe.c
> > +++ b/arch/riscv/kernel/sys_hwprobe.c
> > @@ -310,6 +310,10 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
> >  		hwprobe_isa_vendor_ext_thead_0(pair, cpus);
> >  		break;
> >  
> > +	case RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL:
> > +		pair->value = RISCV_HWPROBE_KEY_IMA_EXT_0_AVAIL_VALUE;
> > +		break;
> > +
> >  	/*
> >  	 * For forward compatibility, unknown keys don't fail the whole
> >  	 * call, but get their element key set to -1 and value set to 0
> > 
> > _______________________________________________
> > linux-riscv mailing list
> > linux-riscv at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-riscv
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
> 


From krzk at kernel.org  Tue Jun  9 05:16:02 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Tue, 9 Jun 2026 14:16:02 +0200
Subject: [GIT PULL] RISC-V Sophgo Devicetrees for v7.2
In-Reply-To: <MA5PR01MB1250024541E71412DDA04B4AAFE132@MA5PR01MB12500.INDPRD01.PROD.OUTLOOK.COM>
References: <MA5PR01MB1250024541E71412DDA04B4AAFE132@MA5PR01MB12500.INDPRD01.PROD.OUTLOOK.COM>
Message-ID: <20260609-free-bloodhound-of-election-d83fe3@quoll>

On Wed, Jun 03, 2026 at 02:17:42PM +0800, Chen Wang wrote:
> Hey Arnd,
> 
> Please pull this dt changes for RISC-V/Sophgo.
> 
> BTW: Next PR, I will start using my new work email address:
> chen.wang at linux.dev.

Thanks, appreciated.

> 
> Thanks,
> 
> Chen
> 
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> 
> ? Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> 
> are available in the Git repository at:
> 
> ? https://github.com/sophgo/linux.git tags/riscv-sophgo-dt-for-v7.2
> 
> for you to fetch changes up to 903a9364e40563faf4730dc63ad7446246f494ff:
> 
> ? riscv: dts: sophgo: reduce SG2042 MSI count to 16 (2026-06-03 10:09:38
> +0800)
> 
> ----------------------------------------------------------------
> RISC-V Devicetrees for v7.2

Thanks, applied

Best regards,
Krzysztof



From linux at roeck-us.net  Tue Jun  9 05:56:00 2026
From: linux at roeck-us.net (Guenter Roeck)
Date: Tue, 9 Jun 2026 05:56:00 -0700
Subject: [PATCH v2] hwmon: add a driver for the temp/voltage sensor on
 PolarFire SoC
In-Reply-To: <20260609-estrogen-entangled-da00ac932481@spud>
References: <20260603-ongoing-brunette-51e35be6d93e@spud>
 <fd92d7c9-9594-47b9-bd84-a6bd5ebae66d@roeck-us.net>
 <20260609-estrogen-entangled-da00ac932481@spud>
Message-ID: <35577504-76cf-4dd3-8f98-5fde03fc0a1f@roeck-us.net>

On 6/9/26 02:43, Conor Dooley wrote:
> On Mon, Jun 08, 2026 at 10:03:48AM -0700, Guenter Roeck wrote:
>> On 6/3/26 06:19, Conor Dooley wrote:
>>> From: Lars Randers <lranders at mail.dk>
>>>
>>> Add a driver for the temperature and voltage sensors on PolarFire SoC.
>>> The temperature reports how hot the die is, and the voltages are the
>>> SoC's 1.05, 1.8 and 2.5 volt rails respectively.
>>>
>>> The hardware supports alarms in theory, but there is an erratum that
>>> prevents clearing them once triggered, so no support is added for them.
>>>
>>> The hardware measures voltage with 16 bits, of which 1 is a sign bit and
>>> the remainder holds the voltage as a fixed point integer value. It's
>>> improbable that the hardware will work if the voltages are negative, so
>>> the driver ignores the sign bits.
>>>
>>> There's no dt support etc here because this is the child of a simple-mfd
>>> syscon.
>>>
>>> Signed-off-by: Lars Randers <lranders at mail.dk>
>>> Co-developed-by: Conor Dooley <conor.dooley at microchip.com>
>>> Signed-off-by: Conor Dooley <conor.dooley at microchip.com>
>>
>> Comments inline.
> 
> Cheers.
> 
...
>>
>> If regmap never returns errors this needs to be documented in the driver.
> 
> It's an mmio regmap via a syscon, it evaluates to readl()/writel() so
> there's nothing that can fail /and/ return an error.
> I mean, I can add if (ret) return ret, there's not a clean place to put
> a comment about it I don't think.
> 

No, there is no need to add dummy error checks.  Just add a comment
either at the top of the driver or maybe even better where the regmap
is initialized and explain the above.

Guenter



From cuiyunhui at bytedance.com  Tue Jun  9 06:00:17 2026
From: cuiyunhui at bytedance.com (Yunhui Cui)
Date: Tue,  9 Jun 2026 21:00:17 +0800
Subject: [PATCH v3 0/3] riscv: support effective hardware PTE A/D updates
Message-ID: <20260609130021.99899-1-cuiyunhui@bytedance.com>

This series makes RISC-V track hardware PTE A/D updating by the
effective runtime state instead of treating Svadu discovery alone as
enough.

When both Svade and Svadu are present, Svadu is disabled at boot and
must be enabled through SBI FWFT.  The series enables FWFT PTE A/D
hardware updating on all currently online CPUs before enabling the
global static key, and enables it for later hotplug CPUs early in
smp_callin(), before they are marked online.  If FWFT setup fails, the
kernel falls back to software-managed A/D updates.

It also makes live PTE access/permission updates use cmpxchg-based
merges so that software updates do not lose concurrently
hardware-updated accessed, dirty, or soft-dirty state.

Changes since v2:
- Split the devicetree binding clarification into a separate patch.
- Avoid CPUHP_AP_ONLINE_DYN for FWFT setup; enable FWFT for current
  online CPUs during init and for hotplug CPUs early in smp_callin().
- Export riscv_hw_pte_ad_updating for modular KVM.
- Preserve _PAGE_SOFT_DIRTY together with A/D bits and rename the helper
  variable to avoid implying only hardware bits are preserved.

Yunhui Cui (3):
  dt-bindings: riscv: clarify Svadu boot-time behavior
  riscv: track effective hardware PTE A/D updating
  riscv: preserve A/D and soft-dirty state across PTE updates

 .../devicetree/bindings/riscv/extensions.yaml |  6 +-
 arch/riscv/include/asm/cpufeature.h           |  8 ++
 arch/riscv/include/asm/pgtable.h              | 27 ++++--
 arch/riscv/kernel/cpufeature.c                | 89 +++++++++++++++++--
 arch/riscv/kernel/smpboot.c                   |  4 +
 arch/riscv/mm/pgtable.c                       | 68 +++++++++++---
 6 files changed, 175 insertions(+), 27 deletions(-)

-- 
2.39.5


From cuiyunhui at bytedance.com  Tue Jun  9 06:00:18 2026
From: cuiyunhui at bytedance.com (Yunhui Cui)
Date: Tue,  9 Jun 2026 21:00:18 +0800
Subject: [PATCH v3 1/3] dt-bindings: riscv: clarify Svadu boot-time behavior
In-Reply-To: <20260609130021.99899-1-cuiyunhui@bytedance.com>
References: <20260609130021.99899-1-cuiyunhui@bytedance.com>
Message-ID: <20260609130021.99899-2-cuiyunhui@bytedance.com>

Clarify that systems which advertise only Svadu have hardware PTE A/D
updating enabled at boot, while systems advertising both Svade and Svadu
must enable Svadu explicitly with SBI FWFT.

Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
---
 Documentation/devicetree/bindings/riscv/extensions.yaml | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb214..b09888e9988de 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -294,10 +294,10 @@ properties:
                of the PTE A/D bits or page faults when they need updated.
             2) Only Svade present in DT => Supervisor must assume Svade to be
                always enabled.
-            3) Only Svadu present in DT => Supervisor must assume Svadu to be
-               always enabled.
+            3) Only Svadu present in DT => Supervisor must assume Svadu is
+               enabled at boot.
             4) Both Svade and Svadu present in DT => Supervisor must assume
-               Svadu turned-off at boot time. To use Svadu, supervisor must
+               Svadu is disabled at boot time. To use Svadu, supervisor must
                explicitly enable it using the SBI FWFT extension.
 
         - const: svadu
-- 
2.39.5



From cuiyunhui at bytedance.com  Tue Jun  9 06:00:19 2026
From: cuiyunhui at bytedance.com (Yunhui Cui)
Date: Tue,  9 Jun 2026 21:00:19 +0800
Subject: [PATCH v3 2/3] riscv: track effective hardware PTE A/D updating
In-Reply-To: <20260609130021.99899-1-cuiyunhui@bytedance.com>
References: <20260609130021.99899-1-cuiyunhui@bytedance.com>
Message-ID: <20260609130021.99899-3-cuiyunhui@bytedance.com>

Track whether hardware PTE A/D updating is effectively active separately
from Svadu discovery. Enable FWFT on all online harts before advertising
hardware A/D updating globally, and require secondary harts to enable it
before they are marked online.

Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
---
 arch/riscv/include/asm/cpufeature.h |  8 +++
 arch/riscv/kernel/cpufeature.c      | 89 +++++++++++++++++++++++++++--
 arch/riscv/kernel/smpboot.c         |  4 ++
 3 files changed, 95 insertions(+), 6 deletions(-)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 739fcc84bf7b2..ba3d74f6006a6 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -128,6 +128,14 @@ struct riscv_isa_ext_data {
 extern const struct riscv_isa_ext_data riscv_isa_ext[];
 extern const size_t riscv_isa_ext_count;
 extern bool riscv_isa_fallback;
+DECLARE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
+
+static __always_inline bool riscv_has_hw_pte_ad_updating(void)
+{
+	return static_branch_unlikely(&riscv_hw_pte_ad_updating);
+}
+
+int riscv_enable_hw_pte_ad_updating(void);
 
 unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
 static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index f46aa5602d74d..f144797fa2dc8 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -15,6 +15,7 @@
 #include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/smp.h>
 #include <asm/acpi.h>
 #include <asm/alternative.h>
 #include <asm/bugs.h>
@@ -35,6 +36,9 @@
 static bool any_cpu_has_zicboz;
 static bool any_cpu_has_zicbop;
 static bool any_cpu_has_zicbom;
+DEFINE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
+EXPORT_SYMBOL_GPL(riscv_hw_pte_ad_updating);
+static bool riscv_hw_pte_ad_updating_requires_fwft __read_mostly;
 
 unsigned long elf_hwcap __read_mostly;
 
@@ -287,15 +291,88 @@ static int riscv_ext_zvfbfwma_validate(const struct riscv_isa_ext_data *data,
 	return -EPROBE_DEFER;
 }
 
-static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data,
-				    const unsigned long *isa_bitmap)
+static void riscv_set_hw_pte_ad_updating(void)
+{
+	static_branch_enable(&riscv_hw_pte_ad_updating);
+}
+
+static int riscv_enable_local_hw_pte_ad_updating(void)
+{
+	return sbi_fwft_set(SBI_FWFT_PTE_AD_HW_UPDATING, 1, 0);
+}
+
+static int riscv_set_online_hw_pte_ad_updating(bool enable)
+{
+	return sbi_fwft_set_online_cpus(SBI_FWFT_PTE_AD_HW_UPDATING,
+					   enable, 0);
+}
+
+int riscv_enable_hw_pte_ad_updating(void)
+{
+	unsigned int cpu;
+	int ret;
+
+	if (!riscv_has_hw_pte_ad_updating() ||
+	    !riscv_hw_pte_ad_updating_requires_fwft)
+		return 0;
+
+	cpu = smp_processor_id();
+	ret = riscv_enable_local_hw_pte_ad_updating();
+	if (ret)
+		pr_err("CPU%u failed to enable hardware PTE A/D updating: %d\n",
+		       cpu, ret);
+
+	return ret;
+}
+
+static void riscv_disable_hw_pte_ad_updating(int error)
+{
+	int ret;
+
+	riscv_hw_pte_ad_updating_requires_fwft = false;
+	if (error != -EOPNOTSUPP)
+		pr_err("Failed to enable hardware PTE A/D updating: %d\n",
+		       error);
+
+	ret = riscv_set_online_hw_pte_ad_updating(false);
+	if (ret && ret != -EOPNOTSUPP)
+		pr_err("Failed to rollback hardware PTE A/D updating: %d\n",
+		       ret);
+
+	pr_info("riscv: leave PTE A/D updates software-managed (%d)\n",
+		error);
+}
+
+static int __init riscv_hw_pte_ad_updating_init(void)
 {
-	/* SVADE has already been detected, use SVADE only */
-	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SVADE))
-		return -EOPNOTSUPP;
+	bool has_svade, has_svadu;
+	int ret;
 
+	has_svade = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADE);
+	has_svadu = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
+
+	if (!has_svadu)
+		return 0;
+
+	if (has_svade) {
+		riscv_hw_pte_ad_updating_requires_fwft = true;
+		ret = riscv_set_online_hw_pte_ad_updating(true);
+		if (ret) {
+			riscv_disable_hw_pte_ad_updating(ret);
+			return 0;
+		}
+	}
+
+	/*
+	 * At this point hardware PTE A/D updating is active for all online
+	 * harts, either from boot or from the FWFT setup above. Later harts
+	 * must do the same in secondary startup before they are marked online.
+	 */
+	riscv_set_hw_pte_ad_updating();
+	pr_debug("riscv: hardware PTE A/D updating enabled\n");
 	return 0;
 }
+arch_initcall(riscv_hw_pte_ad_updating_init);
 
 static int riscv_cfilp_validate(const struct riscv_isa_ext_data *data,
 				const unsigned long *isa_bitmap)
@@ -584,7 +661,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
 	__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
 	__RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),
-	__RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate),
+	__RISCV_ISA_EXT_DATA(svadu, RISCV_ISA_EXT_SVADU),
 	__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
 	__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
 	__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index 8b628580fe118..4fe62f96bcca2 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -27,6 +27,7 @@
 #include <linux/sched/mm.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
@@ -221,6 +222,9 @@ asmlinkage __visible void smp_callin(void)
 	struct mm_struct *mm = &init_mm;
 	unsigned int curr_cpuid = smp_processor_id();
 
+	if (riscv_enable_hw_pte_ad_updating())
+		return;
+
 	if (has_vector()) {
 		/*
 		 * Return as early as possible so the hart with a mismatching
-- 
2.39.5



From cuiyunhui at bytedance.com  Tue Jun  9 06:00:20 2026
From: cuiyunhui at bytedance.com (Yunhui Cui)
Date: Tue,  9 Jun 2026 21:00:20 +0800
Subject: [PATCH v3 3/3] riscv: preserve A/D and soft-dirty state across PTE updates
In-Reply-To: <20260609130021.99899-1-cuiyunhui@bytedance.com>
References: <20260609130021.99899-1-cuiyunhui@bytedance.com>
Message-ID: <20260609130021.99899-4-cuiyunhui@bytedance.com>

Use cmpxchg-based PTE updates so software permission changes do not lose
concurrent A/D updates from hardware. Preserve soft-dirty state as well,
since RISC-V marks PTEs dirty and soft-dirty together.

Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
---
 arch/riscv/include/asm/pgtable.h | 27 +++++++++----
 arch/riscv/mm/pgtable.c          | 68 ++++++++++++++++++++++++++------
 2 files changed, 77 insertions(+), 18 deletions(-)

diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 5d5756bda82e3..02286b48dc471 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -678,15 +678,21 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
 static inline void ptep_set_wrprotect(struct mm_struct *mm,
 				      unsigned long address, pte_t *ptep)
 {
-	pte_t read_pte = READ_ONCE(*ptep);
+	pte_t old_pte;
+	pte_t pte;
 	/*
 	 * ptep_set_wrprotect can be called for shadow stack ranges too.
 	 * shadow stack memory is XWR = 010 and thus clearing _PAGE_WRITE will lead to
 	 * encoding 000b which is wrong encoding with V = 1. This should lead to page fault
 	 * but we dont want this wrong configuration to be set in page tables.
 	 */
-	atomic_long_set((atomic_long_t *)ptep,
-			((pte_val(read_pte) & ~(unsigned long)_PAGE_WRITE) | _PAGE_READ));
+	pte = READ_ONCE(*ptep);
+	do {
+		old_pte = pte;
+		pte = pte_wrprotect(pte);
+		pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep), pte_val(old_pte),
+					       pte_val(pte));
+	} while (pte_val(pte) != pte_val(old_pte));
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -742,14 +748,14 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
 #define pgprot_dmacoherent pgprot_writecombine
 
 /*
- * Both Svade and Svadu control the hardware behavior when the PTE A/D bits need to be set. By
- * default the M-mode firmware enables the hardware updating scheme when only Svadu is present in
- * DT.
+ * Both Svade and Svadu control the hardware behavior when the PTE A/D bits
+ * need to be set. The core MM code only cares whether hardware updating of
+ * the accessed/dirty state is currently active.
  */
 #define arch_has_hw_pte_young arch_has_hw_pte_young
 static inline bool arch_has_hw_pte_young(void)
 {
-	return riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
+	return riscv_has_hw_pte_ad_updating();
 }
 
 /*
@@ -1040,6 +1046,13 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
 	ptep_set_wrprotect(mm, address, (pte_t *)pmdp);
 }
 
+#define __HAVE_ARCH_PUDP_SET_WRPROTECT
+static inline void pudp_set_wrprotect(struct mm_struct *mm,
+				      unsigned long address, pud_t *pudp)
+{
+	ptep_set_wrprotect(mm, address, (pte_t *)pudp);
+}
+
 #define pmdp_establish pmdp_establish
 static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 				unsigned long address, pmd_t *pmdp, pmd_t pmd)
diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c
index 9c4427d0b1874..98eed19ea70de 100644
--- a/arch/riscv/mm/pgtable.c
+++ b/arch/riscv/mm/pgtable.c
@@ -5,23 +5,55 @@
 #include <linux/kernel.h>
 #include <linux/pgtable.h>
 
+#define RISCV_PTE_ACCESS_FLAG_MASK	(_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC | \
+					 _PAGE_ACCESSED | _PAGE_DIRTY | \
+					 _PAGE_SOFT_DIRTY)
+
+static inline unsigned long riscv_pte_access_flags(unsigned long cur,
+						   unsigned long entry)
+{
+	unsigned long pteval;
+	unsigned long preserved_flags;
+
+	preserved_flags = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SOFT_DIRTY;
+	pteval = cur & ~RISCV_PTE_ACCESS_FLAG_MASK;
+	pteval |= entry & (RISCV_PTE_ACCESS_FLAG_MASK & ~preserved_flags);
+	pteval |= (cur | entry) & preserved_flags;
+
+	return pteval;
+}
+
 int ptep_set_access_flags(struct vm_area_struct *vma,
 			  unsigned long address, pte_t *ptep,
 			  pte_t entry, int dirty)
 {
+	unsigned long old_pteval;
+	unsigned long new_pteval;
+	unsigned long prev_pteval;
+	bool changed;
+
+	old_pteval = pte_val(ptep_get(ptep));
+	do {
+		new_pteval = riscv_pte_access_flags(old_pteval, pte_val(entry));
+		if (new_pteval == old_pteval)
+			break;
+
+		prev_pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval,
+					      new_pteval);
+		if (prev_pteval == old_pteval)
+			break;
+
+		old_pteval = prev_pteval;
+	} while (1);
+
+	changed = old_pteval != new_pteval;
 	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)) {
-		if (!pte_same(ptep_get(ptep), entry)) {
-			__set_pte_at(vma->vm_mm, ptep, entry);
-			/* Here only not svadu is impacted */
+		if (changed)
 			flush_tlb_page(vma, address);
-			return true;
-		}
 
-		return false;
+		return changed;
 	}
 
-	if (!pte_same(ptep_get(ptep), entry))
-		__set_pte_at(vma->vm_mm, ptep, entry);
 	/*
 	 * update_mmu_cache will unconditionally execute, handling both
 	 * the case that the PTE changed and the spurious fault case.
@@ -32,9 +64,23 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
 bool ptep_test_and_clear_young(struct vm_area_struct *vma,
 		unsigned long address, pte_t *ptep)
 {
-	if (!pte_young(ptep_get(ptep)))
-		return false;
-	return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep));
+	unsigned long old_pteval;
+	unsigned long new_pteval;
+	unsigned long prev_pteval;
+
+	old_pteval = pte_val(ptep_get(ptep));
+	do {
+		if (!(old_pteval & _PAGE_ACCESSED))
+			return false;
+
+		new_pteval = pte_val(pte_mkold(__pte(old_pteval)));
+		prev_pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval,
+					      new_pteval);
+		if (prev_pteval == old_pteval)
+			return true;
+
+		old_pteval = prev_pteval;
+	} while (1);
 }
 EXPORT_SYMBOL_GPL(ptep_test_and_clear_young);
 
-- 
2.39.5



From dlan at kernel.org  Tue Jun  9 06:25:20 2026
From: dlan at kernel.org (Yixun Lan)
Date: Tue, 9 Jun 2026 13:25:20 +0000
Subject: [GIT PULL] RISC-V SpacemiT Devicetrees for v7.2
In-Reply-To: <20260609-pompous-imposing-dragon-fc18cb@quoll>
References: <20260602070257-KYC5031219@kernel.org>
 <20260609-pompous-imposing-dragon-fc18cb@quoll>
Message-ID: <20260609132520-GKE3727415@kernel.org>

Hi Krzysztof, 

On 14:00 Tue 09 Jun     , Krzysztof Kozlowski wrote:
> On Tue, Jun 02, 2026 at 07:10:07AM +0000, Yixun Lan wrote:
> > Hi SoC Maintainers,
> > 
> >    Please pull SpacemiT's DeviceTree changes for v7.2
> > 
> > Yixun Lan
> > 
> > The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> > 
> >   Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> > 
> > are available in the Git repository at:
> > 
> >   https://github.com/spacemit-com/linux spacemit-dt-for-7.2-1
> 
> Please switch to kernel.org repo. Github is not really a trusted place
> and you have kernel.org account, so not sure why Github is still there.
> 
Ok, thanks for the reminder, I could do the switch in next merge window

For reason why I still use Github, mainly because I got kernel.org account
after taking the maintainer role, then never change the repo address..

> > 
> > for you to fetch changes up to 793cc54475b49b5b558902b5c13e4bfe66530a50:
> > 
> >   riscv: dts: spacemit: enable PMIC on OrangePi R2S (2026-06-01 06:32:42 +0000)
> > 
> > ----------------------------------------------------------------
> > RISC-V SpacemiT DT changes for 7.2
> 
> Thanks, applied
> 
Thank you!

-- 
Yixun Lan (dlan)


From mani at kernel.org  Tue Jun  9 07:03:31 2026
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 9 Jun 2026 19:33:31 +0530
Subject: [PATCH v2 4/5] dt-bindings: PCI: spacemit: Introduce Spacemit K3
 PCIe host controller
In-Reply-To: <20260517014841.254085-5-inochiama@gmail.com>
References: <20260517014841.254085-1-inochiama@gmail.com>
 <20260517014841.254085-5-inochiama@gmail.com>
Message-ID: <kwan2ci7umcckod2623tt2ebwaz6v7ypczz3bqmhfxc6awrkfc@jrjf73wzehcc>

On Sun, May 17, 2026 at 09:48:39AM +0800, Inochi Amaoto wrote:
> Add binding support for the PCIe controller on the SpacemiT K3 SoC.
> This controller is almost a standard Synopsys DesignWare PCIe IP,
> with some extra link and reset state control.
> 
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>

Why can't you reuse the existing spacemit,k1-pcie-host.yaml binding? I see very
few differences which could be added using conditionals. Also, this binding
defines the PHY property in the controller node, which is a way backwards as we
now prefer to define these in Root Port node as spacemit,k1-pcie-host.yaml does.

- Mani

> ---
>  .../bindings/pci/spacemit,k3-pcie-host.yaml   | 135 ++++++++++++++++++
>  1 file changed, 135 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/spacemit,k3-pcie-host.yaml
> 
> diff --git a/Documentation/devicetree/bindings/pci/spacemit,k3-pcie-host.yaml b/Documentation/devicetree/bindings/pci/spacemit,k3-pcie-host.yaml
> new file mode 100644
> index 000000000000..46147a37a9ce
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/spacemit,k3-pcie-host.yaml
> @@ -0,0 +1,135 @@
> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
> +%YAML 1.2
> +---
> +$id: http://devicetree.org/schemas/pci/spacemit,k3-pcie-host.yaml#
> +$schema: http://devicetree.org/meta-schemas/core.yaml#
> +
> +title: SpacemiT K3 PCI Express Host Controller
> +
> +maintainers:
> +  - Inochi Amaoto <inochiama at gmail.com>
> +
> +description:
> +  The SpacemiT K3 SoC PCIe host controller is based on the Synopsys
> +  DesignWare PCIe IP. The controller uses the external MSI interrupt
> +  controller.
> +
> +allOf:
> +  - $ref: /schemas/pci/pci-host-bridge.yaml#
> +  - $ref: /schemas/pci/snps,dw-pcie.yaml#
> +
> +properties:
> +  compatible:
> +    const: spacemit,k3-pcie
> +
> +  reg:
> +    items:
> +      - description: DesignWare PCIe registers
> +      - description: Data Bus Interface (DBI) shadow registers
> +      - description: ATU address space
> +      - description: PCIe configuration space
> +      - description: Link control registers
> +
> +  reg-names:
> +    items:
> +      - const: dbi
> +      - const: dbi2
> +      - const: atu
> +      - const: config
> +      - const: link
> +
> +  clocks:
> +    items:
> +      - description: DWC PCIe Data Bus Interface (DBI) clock
> +      - description: DWC PCIe application AXI-bus master interface clock
> +      - description: DWC PCIe application AXI-bus slave interface clock
> +
> +  clock-names:
> +    items:
> +      - const: dbi
> +      - const: mstr
> +      - const: slv
> +
> +  resets:
> +    items:
> +      - description: DWC PCIe Data Bus Interface (DBI) reset
> +      - description: DWC PCIe application AXI-bus master interface reset
> +      - description: DWC PCIe application AXI-bus slave interface reset
> +
> +  reset-names:
> +    items:
> +      - const: dbi
> +      - const: mstr
> +      - const: slv
> +
> +  msi-parent: true
> +
> +  phys:
> +    description:
> +      PHY phandle from the Combo PHY, the lane number does not depends
> +      on this, since the number of lanes provided by Combo PHY can be
> +      1 or 2.
> +    minItems: 1
> +    maxItems: 6
> +
> +  phy-names:
> +    minItems: 1
> +    maxItems: 6
> +
> +  spacemit,apmu:
> +    $ref: /schemas/types.yaml#/definitions/phandle-array
> +    description:
> +      A phandle that refers to the APMU system controller, whose regmap is
> +      used in managing resets and link state, along with and offset of its
> +      reset control register.
> +    items:
> +      - items:
> +          - description: phandle to APMU system controller
> +          - description: register offset
> +
> +required:
> +  - clocks
> +  - clock-names
> +  - resets
> +  - reset-names
> +  - msi-parent
> +  - spacemit,apmu
> +
> +unevaluatedProperties: false
> +
> +examples:
> +  - |
> +    #include <dt-bindings/interrupt-controller/irq.h>
> +
> +    soc {
> +      #address-cells = <2>;
> +      #size-cells = <2>;
> +
> +      pcie at 80000000 {
> +        compatible = "spacemit,k3-pcie";
> +        reg = <0x0  0x80000000 0x0 0x00001000>,
> +              <0x0  0x80100000 0x0 0x00001000>,
> +              <0x0  0x80300000 0x0 0x00003f20>,
> +              <0x11 0x00000000 0x0 0x00010000>,
> +              <0x0  0x82900000 0x0 0x00001000>;
> +        reg-names = "dbi", "dbi2", "atu", "config", "link";
> +        device_type = "pci";
> +        #address-cells = <3>;
> +        #size-cells = <2>;
> +        clocks = <&syscon_apmu 89>,
> +                 <&syscon_apmu 56>,
> +                 <&syscon_apmu 57>;
> +        clock-names = "dbi", "mstr", "slv";
> +        msi-parent = <&simsic>;
> +        ranges = <0x01000000 0x00 0x00010000 0x11 0x00010000 0x0 0x00100000>,
> +                 <0x02000000 0x0  0x00110000 0x11 0x00110000 0x0 0x7fef0000>,
> +                 <0x43000000 0x18 0x00000000 0x18 0x00000000 0x1 0x00000000>;
> +        resets = <&syscon_apmu 76>,
> +                 <&syscon_apmu 78>,
> +                 <&syscon_apmu 77>;
> +        reset-names = "dbi", "mstr", "slv";
> +        linux,pci-domain = <0>;
> +        spacemit,apmu = <&syscon_apmu 0x1f0>;
> +      };
> +    };
> +
> -- 
> 2.54.0
> 

-- 
????????? ????????


From mani at kernel.org  Tue Jun  9 07:18:12 2026
From: mani at kernel.org (Manivannan Sadhasivam)
Date: Tue, 9 Jun 2026 19:48:12 +0530
Subject: [PATCH v2 5/5] PCI: spacemit-k1: Add Spacemit K3 PCIe host
 controller support
In-Reply-To: <20260517014841.254085-6-inochiama@gmail.com>
References: <20260517014841.254085-1-inochiama@gmail.com>
 <20260517014841.254085-6-inochiama@gmail.com>
Message-ID: <wztjdv4t5cn7djj3jyvheest7rn5nr2g3efzwods2fz3yy5wn2@hbl644sd6fst>

On Sun, May 17, 2026 at 09:48:40AM +0800, Inochi Amaoto wrote:
> The PCIe controller on Spacemit K3 is almost a standard Synopsys
> DesignWare PCIe IP with extra link and reset control. Unlike
> the PCIe controller on K1, this controller supports external MSI
> interrupt controller and can use multiple PHYs at the same time.
> 
> Add driver to support PCIe controller on Spacemit K3 PCIe.
> 
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> ---
>  drivers/pci/controller/dwc/Kconfig            |   4 +-
>  drivers/pci/controller/dwc/pcie-spacemit-k1.c | 169 ++++++++++++++++++
>  2 files changed, 171 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index f2fde13107f2..fae971ecd876 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -439,7 +439,7 @@ config PCIE_SOPHGO_DW
>  	  Sophgo SoCs.
>  
>  config PCIE_SPACEMIT_K1
> -	tristate "SpacemiT K1 PCIe controller (host mode)"
> +	tristate "SpacemiT K1/K3 PCIe controller (host mode)"

Can you just say 'SpacemiT PCIe controller (host mode)"? I believe I asked Alex
while adding K1 support and he said this driver might not support future IP
revisions, but here we are.

>  	depends on ARCH_SPACEMIT || COMPILE_TEST
>  	depends on HAS_IOMEM
>  	select PCIE_DW_HOST
> @@ -447,7 +447,7 @@ config PCIE_SPACEMIT_K1
>  	default ARCH_SPACEMIT
>  	help
>  	  Enables support for the DesignWare based PCIe controller in
> -	  the SpacemiT K1 SoC operating in host mode.  Three controllers
> +	  the SpacemiT K1/K3 SoC operating in host mode. Three controllers
>  	  are available on the K1 SoC; the first of these shares a PHY
>  	  with a USB 3.0 host controller (one or the other can be used).
>  
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index 7f6f1df31cd8..7854d26220a9 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -23,6 +23,7 @@
>  
>  #define PCI_VENDOR_ID_SPACEMIT		0x201f
>  #define PCI_DEVICE_ID_SPACEMIT_K1	0x0001
> +#define PCI_DEVICE_ID_SPACEMIT_K3	0x0002
>  
>  /* Offsets and field definitions for link management registers */
>  #define K1_PHY_AHB_IRQ_EN			0x0000
> @@ -32,8 +33,20 @@
>  #define SMLH_LINK_UP			BIT(1)
>  #define RDLH_LINK_UP			BIT(12)
>  
> +#define INTR_STATUS				0x0010
> +
>  #define INTR_ENABLE				0x0014
>  #define MSI_CTRL_INT			BIT(11)
> +#define RDLH_LINK_UP_INT		BIT(20)
> +
> +#define K3_PHY_AHB_IRQSTATUS_INTX		0x0008
> +
> +#define K3_ADDR_INTR_STATUS1			0x0018
> +
> +#define K3_CACHE_MSTR_AWCACHE_MODE	GENMASK(14, 11)
> +#define K3_CACHE_MSTR_AWCACHE_BEHAVIOR	0xf
> +
> +#define K3_MAX_PHY_NUMBER		6

What does this mean? 6 ports?

>  
>  /* Some controls require APMU regmap access */
>  #define SYSCON_APMU			"spacemit,apmu"
> @@ -48,6 +61,9 @@
>  
>  #define PCIE_CONTROL_LOGIC			0x0004
>  #define PCIE_SOFT_RESET			BIT(0)
> +#define PCIE_PERSTN_OE			BIT(24)
> +#define PCIE_PERSTN_OUT			BIT(25)
> +#define PCIE_IGNORE_PERSTN		BIT(31)
>  
>  struct k1_pcie {
>  	struct dw_pcie pci;
> @@ -262,6 +278,152 @@ static const struct dw_pcie_ops k1_pcie_ops = {
>  	.stop_link	= k1_pcie_stop_link,
>  };
>  
> +static int k3_pcie_enable_phy(struct k1_pcie *pcie)
> +{
> +	int i, ret;
> +
> +	for (i = 0; i < pcie->phy_count; i++) {
> +		ret = phy_init(pcie->phy[i]);
> +		if (ret)
> +			goto err_phy;
> +	}
> +
> +	return 0;
> +
> +err_phy:
> +	while (--i >= 0)
> +		phy_exit(pcie->phy[i]);
> +
> +	return ret;
> +}
> +
> +static int k3_pcie_init(struct dw_pcie_rp *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct k1_pcie *k1 = to_k1_pcie(pci);
> +	u32 reset_ctrl = k1->pmu_off + PCIE_CLK_RESET_CONTROL;
> +	u32 val;
> +	int ret;
> +
> +	regmap_clear_bits(k1->pmu, reset_ctrl, LTSSM_EN);
> +
> +	k1_pcie_toggle_soft_reset(k1);
> +
> +	ret = k1_pcie_enable_resources(k1);
> +	if (ret)
> +		return ret;
> +
> +	regmap_set_bits(k1->pmu, reset_ctrl, PCIE_AUX_PWR_DET);
> +	regmap_clear_bits(k1->pmu, reset_ctrl, APP_HOLD_PHY_RST);
> +
> +	ret = k3_pcie_enable_phy(k1);
> +	if (ret) {
> +		k1_pcie_disable_resources(k1);
> +		return ret;
> +	}
> +
> +	/* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */

What does this mean?

> +	regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> +			PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT);
> +	usleep_range(1000, 2000);
> +	regmap_clear_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC, PCIE_PERSTN_OUT);
> +
> +	msleep(PCIE_T_PVPERL_MS);
> +
> +	/*
> +	 * Put the controller in root complex mode, and indicate that
> +	 * Vaux (3.3v) is present.
> +	 */

How can the driver confirm without checking DT for vpcie3v3aux-supply?

> +	regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> +			PCIE_PERSTN_OUT | PCIE_PERSTN_OE);
> +
> +	val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> +	val = u32_replace_bits(val, GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE,
> +			       GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
> +	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
> +
> +	dw_pcie_dbi_ro_wr_en(pci);
> +	dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_SPACEMIT);
> +	dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, PCI_DEVICE_ID_SPACEMIT_K3);
> +	dw_pcie_dbi_ro_wr_dis(pci);
> +
> +	/* Finally, as a workaround, disable ASPM L1 */
> +	k1_pcie_disable_aspm_l1(k1);
> +
> +	return 0;
> +}
> +
> +static int k3_pcie_msi_host_init(struct dw_pcie_rp *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	u32 val;
> +
> +	dw_pcie_dbi_ro_wr_en(pci);
> +
> +	val = dw_pcie_readl_dbi(pci, COHERENCY_CONTROL_3_OFF);
> +	val |= u32_replace_bits(val, K3_CACHE_MSTR_AWCACHE_BEHAVIOR,
> +				K3_CACHE_MSTR_AWCACHE_MODE);
> +	dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, val);
> +
> +	dw_pcie_dbi_ro_wr_dis(pci);
> +
> +	return 0;
> +}
> +
> +static const struct dw_pcie_host_ops k3_pcie_host_ops = {
> +	.init		= k3_pcie_init,
> +	.deinit		= k1_pcie_deinit,
> +	.msi_init	= k3_pcie_msi_host_init,
> +};
> +
> +static const struct dw_pcie_ops k3_pcie_ops = {
> +	.link_up	= k1_pcie_link_up,
> +	.start_link	= k1_pcie_start_link,
> +	.stop_link	= k1_pcie_stop_link,
> +};
> +
> +static void k3_pcie_clear_irq_status(struct k1_pcie *k1,
> +				     u32 *status0, u32 *status1, u32 *status2)
> +{
> +	*status0 = readl_relaxed(k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> +	*status1 = readl_relaxed(k1->link + INTR_STATUS);
> +	*status2 = readl_relaxed(k1->link + K3_ADDR_INTR_STATUS1);
> +
> +	writel_relaxed(*status0, k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> +	writel_relaxed(*status1, k1->link + INTR_STATUS);
> +	writel_relaxed(*status2, k1->link + K3_ADDR_INTR_STATUS1);
> +}
> +
> +static int k3_pcie_parse_port(struct k1_pcie *k1)
> +{
> +	struct device *dev = k1->pci.dev;
> +	u32 status0, status1, status2;
> +	int i;
> +
> +	k1->phy = devm_kmalloc_array(dev, K3_MAX_PHY_NUMBER, sizeof(*k1->phy),
> +				     GFP_KERNEL);
> +	if (!k1->phy)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < K3_MAX_PHY_NUMBER; i++) {
> +		k1->phy[i] = devm_of_phy_get_by_index(dev, dev->of_node, i);
> +		if (IS_ERR(k1->phy[i])) {
> +			if (PTR_ERR(k1->phy[i]) == -ENODEV)
> +				break;
> +
> +			return PTR_ERR(k1->phy[i]);
> +		}
> +	}
> +
> +	k1->phy_count = i;
> +	if (k1->phy_count == 0)
> +		return -EINVAL;
> +
> +	k3_pcie_clear_irq_status(k1, &status0, &status1, &status2);
> +
> +	return 0;
> +}

This function should iterate over the Root Port nodes defined in DT.

- Mani

-- 
????????? ????????


From rostedt at goodmis.org  Tue Jun  9 07:21:20 2026
From: rostedt at goodmis.org (Steven Rostedt)
Date: Tue, 9 Jun 2026 10:21:20 -0400
Subject: [PATCH v2 1/8] scripts/sorttable: Handle RISC-V patchable
 ftrace entries
In-Reply-To: <6753385b-c2ab-4ed0-9400-78ce967450ba@linux.alibaba.com>
References: <20260527123530.2593918-1-wanghan@linux.alibaba.com>
	<20260528082310.1994388-2-wanghan@linux.alibaba.com>
	<0a913398-3d0c-472e-89c4-062052eae04d@linux.alibaba.com>
	<20260601095746.70c01d24@fedora>
	<6753385b-c2ab-4ed0-9400-78ce967450ba@linux.alibaba.com>
Message-ID: <20260609102120.359f3c4c@fedora>

On Wed, 3 Jun 2026 10:10:44 +0800
Shuai Xue <xueshuai at linux.alibaba.com> wrote:

> It's a pure comment cosmetic, not worth a respin on its own. But for the

I don't know. I've respinned for better comments before.

> rest of the feedback on this series (the frame-record metadata contract
> in patch 2 and the dead state->regs field / Call Trace output change in
> patch 6) are the ones actually worth a new version.
> 
> Just to get the routing straight: are you planning to pick this one up
> through the tracing tree on its own?
> 
> It feels like a good candidate for that -- it's an independent
> regression fix (Fixes: 0ca1724b56af) that breaks *all* RISC-V dynamic
> ftrace, not just livepatch, so it shouldn't have to wait on the rest of
> the livepatch series.

As it affects RISCV and I don't have a RISCV to test, I would feel more
comfortable with it going through a RISCV tree that can test the patch.

Feel free to add:

Reviewed-by: Steven Rostedt <rostedt at goodmis.org>

-- Steve


From sunilvl at oss.qualcomm.com  Tue Jun  9 07:30:34 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Tue, 9 Jun 2026 20:00:34 +0530
Subject: [PATCH v4 09/10] riscv: Select HAVE_ACPI_APEI required for RAS
In-Reply-To: <20260513084325.2176952-10-himanshu.chauhan@oss.qualcomm.com>
References: <20260513084325.2176952-1-himanshu.chauhan@oss.qualcomm.com> <20260513084325.2176952-10-himanshu.chauhan@oss.qualcomm.com>
Message-ID: <CAB19ukGeM=v=G10r_tX2SC603Tej5Q6nFOCddcPF8BaKwxFxrg@mail.gmail.com>

On Wed, May 13, 2026 at 2:14?PM Himanshu Chauhan
<himanshu.chauhan at oss.qualcomm.com> wrote:
>
> Select the HAVE_ACPI_APEI option so that APEI GHES config options
> are visible.
>
> Signed-off-by: Himanshu Chauhan <himanshu.chauhan at oss.qualcomm.com>
> ---
>  arch/riscv/Kconfig | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index d235396c4514..b94b19fb4249 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -187,6 +187,7 @@ config RISCV
>         select HAVE_MOVE_PUD
>         select HAVE_PAGE_SIZE_4KB
>         select HAVE_PCI
> +       select HAVE_ACPI_APEI if ACPI
>         select HAVE_PERF_EVENTS
>         select HAVE_PERF_REGS
>         select HAVE_PERF_USER_STACK_DUMP
>
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From sunilvl at oss.qualcomm.com  Tue Jun  9 07:45:51 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Tue, 9 Jun 2026 20:15:51 +0530
Subject: [PATCH v2 1/6] ACPI: RISC-V: Fix riscv_acpi_irq_get_dep() loop termination
In-Reply-To: <aifahCtdj8GpHN/v@lpieralisi>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-1-23ffa16b6ebb@kernel.org>
 <CAB19ukFFwm3ehzkBFr+oXRjA7VK_4_=XHFSuqdEpbVqUz8Do4Q@mail.gmail.com> <aifahCtdj8GpHN/v@lpieralisi>
Message-ID: <CAB19ukHAAHp5kmm+5KBDqtn969h3V4LBr2put9hJSWphPS8jmw@mail.gmail.com>

On Tue, Jun 9, 2026 at 2:49?PM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
>
> On Mon, Jun 08, 2026 at 09:54:28PM +0530, Sunil V L wrote:
> > Hi Lorenzo,
> >
> > On Wed, Jun 3, 2026 at 1:51?PM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
> > >
[...]
> > Do these fixes need the Fixes tag?
>
> I can add a Fixes: tag but I wanted first some help testing them, it
> is code perusal that got me there.
>
Oh, yes. I tested these changes on the RISC-V virt platform.

So for RISC-V testing,

Tested-by: Sunil V L <sunilvl at oss.qualcomm.com>

> > Otherwise, LGTM.
> > Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>
>
> Thanks,
> Lorenzo


From andriy.shevchenko at linux.intel.com  Tue Jun  9 07:49:23 2026
From: andriy.shevchenko at linux.intel.com (Andy Shevchenko)
Date: Tue, 9 Jun 2026 17:49:23 +0300
Subject: [PATCH v2 5/5] PCI: spacemit-k1: Add Spacemit K3 PCIe host
 controller support
In-Reply-To: <wztjdv4t5cn7djj3jyvheest7rn5nr2g3efzwods2fz3yy5wn2@hbl644sd6fst>
References: <20260517014841.254085-1-inochiama@gmail.com>
 <20260517014841.254085-6-inochiama@gmail.com>
 <wztjdv4t5cn7djj3jyvheest7rn5nr2g3efzwods2fz3yy5wn2@hbl644sd6fst>
Message-ID: <aign88JV3k_wn2HK@ashevche-desk.local>

On Tue, Jun 09, 2026 at 07:48:12PM +0530, Manivannan Sadhasivam wrote:
> On Sun, May 17, 2026 at 09:48:40AM +0800, Inochi Amaoto wrote:
> > The PCIe controller on Spacemit K3 is almost a standard Synopsys
> > DesignWare PCIe IP with extra link and reset control. Unlike
> > the PCIe controller on K1, this controller supports external MSI
> > interrupt controller and can use multiple PHYs at the same time.
> > 
> > Add driver to support PCIe controller on Spacemit K3 PCIe.

...

> > +static int k3_pcie_enable_phy(struct k1_pcie *pcie)
> > +{
> > +	int i, ret;

No need to have i signed.

> > +
> > +	for (i = 0; i < pcie->phy_count; i++) {
> > +		ret = phy_init(pcie->phy[i]);
> > +		if (ret)
> > +			goto err_phy;
> > +	}
> > +
> > +	return 0;
> > +
> > +err_phy:
> > +	while (--i >= 0)

	while (i--)

is shorter form of the same.

> > +		phy_exit(pcie->phy[i]);
> > +

...

> > +	regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> > +			PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT);
> > +	usleep_range(1000, 2000);

fsleep(1 * USEC_PER_MSEC)

> > +	regmap_clear_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC, PCIE_PERSTN_OUT);
> > +
> > +	msleep(PCIE_T_PVPERL_MS);

...

> > +	int i;

Why is 'i' signed?

-- 
With Best Regards,
Andy Shevchenko




From conor at kernel.org  Tue Jun  9 09:08:49 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 9 Jun 2026 17:08:49 +0100
Subject: [PATCH v3 1/3] dt-bindings: riscv: clarify Svadu boot-time
 behavior
In-Reply-To: <20260609130021.99899-2-cuiyunhui@bytedance.com>
References: <20260609130021.99899-1-cuiyunhui@bytedance.com>
 <20260609130021.99899-2-cuiyunhui@bytedance.com>
Message-ID: <20260609-washboard-fantasize-ddf0a9752df8@spud>

On Tue, Jun 09, 2026 at 09:00:18PM +0800, Yunhui Cui wrote:
> Clarify that systems which advertise only Svadu have hardware PTE A/D
> updating enabled at boot, while systems advertising both Svade and Svadu
> must enable Svadu explicitly with SBI FWFT.
> 
> Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
> ---
>  Documentation/devicetree/bindings/riscv/extensions.yaml | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
> index 2b0a8a93bb214..b09888e9988de 100644
> --- a/Documentation/devicetree/bindings/riscv/extensions.yaml
> +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
> @@ -294,10 +294,10 @@ properties:
>                 of the PTE A/D bits or page faults when they need updated.
>              2) Only Svade present in DT => Supervisor must assume Svade to be
>                 always enabled.
> -            3) Only Svadu present in DT => Supervisor must assume Svadu to be
> -               always enabled.
> +            3) Only Svadu present in DT => Supervisor must assume Svadu is
> +               enabled at boot.

Commit message is missing an explanation of why this behaviour change is
not problematic. Although, to be honest, I am not sure what the changed text
actually means. If only Svadu is present, then the hardware doesn't support
Svade, and therefore Svadu would never be anything other than enabled so
changing the wording to specify "at boot" seems less clear?

>              4) Both Svade and Svadu present in DT => Supervisor must assume
> -               Svadu turned-off at boot time. To use Svadu, supervisor must
> +               Svadu is disabled at boot time. To use Svadu, supervisor must

This change doesn't actually do anything, "turned-off" and "disabled"
are the same thing - although the latter is more desirable wording I
think. I have no problems with this portion of the patch.

>                 explicitly enable it using the SBI FWFT extension.
>  
>          - const: svadu
> -- 
> 2.39.5
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260609/09599316/attachment.sig>

From elder at riscstar.com  Tue Jun  9 09:11:14 2026
From: elder at riscstar.com (Alex Elder)
Date: Tue, 9 Jun 2026 11:11:14 -0500
Subject: [PATCH v2 2/5] PCI: spacemit-k1: Add multiple PHY handles support
In-Reply-To: <20260517014841.254085-3-inochiama@gmail.com>
References: <20260517014841.254085-1-inochiama@gmail.com>
 <20260517014841.254085-3-inochiama@gmail.com>
Message-ID: <433e917b-16e3-4744-a614-6372ef22825c@riscstar.com>

On 5/16/26 8:48 PM, Inochi Amaoto wrote:
> The PCIe controller on Spacemit K3 may use multiple PHYs at the
> same time. The feature is not support by the current driver.
> So extend the PHY definition to support multiple PHY handles.
> 
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> ---
>   drivers/pci/controller/dwc/pcie-spacemit-k1.c | 16 ++++++++++++----
>   1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index 1b519d49dcc0..7f6f1df31cd8 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -51,7 +51,8 @@
>   
>   struct k1_pcie {
>   	struct dw_pcie pci;
> -	struct phy *phy;
> +	struct phy **phy;

I haven't looked further at this series yet, but do you have
any interest in making this a flexible array of pointers
(counted_by(phy_count))?

> +	int phy_count;
>   	void __iomem *link;
>   	struct regmap *pmu;	/* Errors ignored; MMIO-backed regmap */
>   	u32 pmu_off;
> @@ -171,7 +172,7 @@ static int k1_pcie_init(struct dw_pcie_rp *pp)
>   	 */
>   	regmap_set_bits(k1->pmu, reset_ctrl, DEVICE_TYPE_RC | PCIE_AUX_PWR_DET);
>   
> -	ret = phy_init(k1->phy);
> +	ret = phy_init(k1->phy[0]);

If you're going to have an array you should probably put in place
a loop to initialize all phy_count elements of the array here
(as is done for phy_exit(), below).

>   	if (ret) {
>   		k1_pcie_disable_resources(k1);
>   
> @@ -191,12 +192,14 @@ static void k1_pcie_deinit(struct dw_pcie_rp *pp)
>   {
>   	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
>   	struct k1_pcie *k1 = to_k1_pcie(pci);
> +	int i;
>   
>   	/* Assert fundamental reset (drive PERST# low) */
>   	regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CLK_RESET_CONTROL,
>   			PCIE_RC_PERST);
>   
> -	phy_exit(k1->phy);
> +	for (i = 0; i < k1->phy_count; i++)
> +		phy_exit(k1->phy[i]);
>   
>   	k1_pcie_disable_resources(k1);
>   }
> @@ -277,7 +280,12 @@ static int k1_pcie_parse_port(struct k1_pcie *k1)
>   	if (IS_ERR(phy))
>   		return PTR_ERR(phy);

Andy said something different about this.

But it seems to me you are intentionally allocating an
*array* of PHY pointers, which happens to have only one entry.
But your objective is that you want to allocate an array of
them so you can support more than just one PHY, right?

> -	k1->phy = phy;
> +	k1->phy = devm_kmalloc_array(dev, 1, sizeof(*k1->phy), GFP_KERNEL);

Probably should use the kzalloc variant.

> +	if (!k1->phy)
> +		return -ENOMEM;
> +
> +	k1->phy[0] = phy;

I think what's wrong is the above assignment.

If you are truly allocating an array of PHY *pointers*,
then you need to also allocate the phy structure that
each entry in the array points to.

The above assignment is erroneously assigning the first entry in the
array to point to the array, and not a new entry.

					-Alex


> +	k1->phy_count = 1;
>   
>   	return 0;
>   }



From elder at riscstar.com  Tue Jun  9 09:11:20 2026
From: elder at riscstar.com (Alex Elder)
Date: Tue, 9 Jun 2026 11:11:20 -0500
Subject: [PATCH v2 4/5] dt-bindings: PCI: spacemit: Introduce Spacemit K3
 PCIe host controller
In-Reply-To: <kwan2ci7umcckod2623tt2ebwaz6v7ypczz3bqmhfxc6awrkfc@jrjf73wzehcc>
References: <20260517014841.254085-1-inochiama@gmail.com>
 <20260517014841.254085-5-inochiama@gmail.com>
 <kwan2ci7umcckod2623tt2ebwaz6v7ypczz3bqmhfxc6awrkfc@jrjf73wzehcc>
Message-ID: <8010bb91-77e1-42b4-9f19-d9e70e385d00@riscstar.com>

On 6/9/26 9:03 AM, Manivannan Sadhasivam wrote:
> On Sun, May 17, 2026 at 09:48:39AM +0800, Inochi Amaoto wrote:
>> Add binding support for the PCIe controller on the SpacemiT K3 SoC.
>> This controller is almost a standard Synopsys DesignWare PCIe IP,
>> with some extra link and reset state control.
>>
>> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> 
> Why can't you reuse the existing spacemit,k1-pcie-host.yaml binding? I see very
> few differences which could be added using conditionals. Also, this binding
> defines the PHY property in the controller node, which is a way backwards as we
> now prefer to define these in Root Port node as spacemit,k1-pcie-host.yaml does.

I agree.  I have another couple of comments below, including several
things that just point out what's the same and what's different.

					-Alex

> 
> - Mani
> 
>> ---
>>   .../bindings/pci/spacemit,k3-pcie-host.yaml   | 135 ++++++++++++++++++
>>   1 file changed, 135 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/pci/spacemit,k3-pcie-host.yaml
>>
>> diff --git a/Documentation/devicetree/bindings/pci/spacemit,k3-pcie-host.yaml b/Documentation/devicetree/bindings/pci/spacemit,k3-pcie-host.yaml
>> new file mode 100644
>> index 000000000000..46147a37a9ce
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/spacemit,k3-pcie-host.yaml
>> @@ -0,0 +1,135 @@
>> +# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
>> +%YAML 1.2
>> +---
>> +$id: http://devicetree.org/schemas/pci/spacemit,k3-pcie-host.yaml#
>> +$schema: http://devicetree.org/meta-schemas/core.yaml#
>> +
>> +title: SpacemiT K3 PCI Express Host Controller
>> +
>> +maintainers:
>> +  - Inochi Amaoto <inochiama at gmail.com>

If you would like to maintain the (common) SpacemiT K1 host
controller binding I'd be OK with that.

>> +
>> +description:
>> +  The SpacemiT K3 SoC PCIe host controller is based on the Synopsys
>> +  DesignWare PCIe IP. The controller uses the external MSI interrupt
>> +  controller.
>> +
>> +allOf:
>> +  - $ref: /schemas/pci/pci-host-bridge.yaml#
>> +  - $ref: /schemas/pci/snps,dw-pcie.yaml#
>> +
>> +properties:
>> +  compatible:
>> +    const: spacemit,k3-pcie
>> +
>> +  reg:
>> +    items:
>> +      - description: DesignWare PCIe registers
>> +      - description: Data Bus Interface (DBI) shadow registers

The above is new (different from K1), as is "dbi2" as its name.

>> +      - description: ATU address space
>> +      - description: PCIe configuration space
>> +      - description: Link control registers
>> +
>> +  reg-names:
>> +    items:
>> +      - const: dbi
>> +      - const: dbi2
>> +      - const: atu
>> +      - const: config
>> +      - const: link
>> +
>> +  clocks:

Clocks and resets are the same as K1.

>> +    items:
>> +      - description: DWC PCIe Data Bus Interface (DBI) clock
>> +      - description: DWC PCIe application AXI-bus master interface clock
>> +      - description: DWC PCIe application AXI-bus slave interface clock
>> +
>> +  clock-names:
>> +    items:
>> +      - const: dbi
>> +      - const: mstr
>> +      - const: slv
>> +
>> +  resets:
>> +    items:
>> +      - description: DWC PCIe Data Bus Interface (DBI) reset
>> +      - description: DWC PCIe application AXI-bus master interface reset
>> +      - description: DWC PCIe application AXI-bus slave interface reset
>> +
>> +  reset-names:
>> +    items:
>> +      - const: dbi
>> +      - const: mstr
>> +      - const: slv
>> +
>> +  msi-parent: true

msi-parent and phys are not present in the K1 binding.

>> +
>> +  phys:
>> +    description:
>> +      PHY phandle from the Combo PHY, the lane number does not depends
>> +      on this, since the number of lanes provided by Combo PHY can be
>> +      1 or 2.
>> +    minItems: 1
>> +    maxItems: 6
>> +
>> +  phy-names:
>> +    minItems: 1
>> +    maxItems: 6
>> +

The following property is the same as K1.

>> +  spacemit,apmu:
>> +    $ref: /schemas/types.yaml#/definitions/phandle-array
>> +    description:
>> +      A phandle that refers to the APMU system controller, whose regmap is
>> +      used in managing resets and link state, along with and offset of its
>> +      reset control register.
>> +    items:
>> +      - items:
>> +          - description: phandle to APMU system controller
>> +          - description: register offset
>> +
>> +required:
>> +  - clocks
>> +  - clock-names
>> +  - resets
>> +  - reset-names
>> +  - msi-parent
>> +  - spacemit,apmu
>> +
>> +unevaluatedProperties: false
>> +
>> +examples:
>> +  - |
>> +    #include <dt-bindings/interrupt-controller/irq.h>
>> +
>> +    soc {
>> +      #address-cells = <2>;
>> +      #size-cells = <2>;
>> +
>> +      pcie at 80000000 {
>> +        compatible = "spacemit,k3-pcie";
>> +        reg = <0x0  0x80000000 0x0 0x00001000>,
>> +              <0x0  0x80100000 0x0 0x00001000>,
>> +              <0x0  0x80300000 0x0 0x00003f20>,
>> +              <0x11 0x00000000 0x0 0x00010000>,
>> +              <0x0  0x82900000 0x0 0x00001000>;
>> +        reg-names = "dbi", "dbi2", "atu", "config", "link";
>> +        device_type = "pci";
>> +        #address-cells = <3>;
>> +        #size-cells = <2>;
>> +        clocks = <&syscon_apmu 89>,
>> +                 <&syscon_apmu 56>,
>> +                 <&syscon_apmu 57>;
>> +        clock-names = "dbi", "mstr", "slv";
>> +        msi-parent = <&simsic>;
>> +        ranges = <0x01000000 0x00 0x00010000 0x11 0x00010000 0x0 0x00100000>,
>> +                 <0x02000000 0x0  0x00110000 0x11 0x00110000 0x0 0x7fef0000>,
>> +                 <0x43000000 0x18 0x00000000 0x18 0x00000000 0x1 0x00000000>;
>> +        resets = <&syscon_apmu 76>,
>> +                 <&syscon_apmu 78>,
>> +                 <&syscon_apmu 77>;
>> +        reset-names = "dbi", "mstr", "slv";
>> +        linux,pci-domain = <0>;
>> +        spacemit,apmu = <&syscon_apmu 0x1f0>;
>> +      };
>> +    };
>> +
>> -- 
>> 2.54.0
>>
> 



From elder at riscstar.com  Tue Jun  9 09:11:24 2026
From: elder at riscstar.com (Alex Elder)
Date: Tue, 9 Jun 2026 11:11:24 -0500
Subject: [PATCH v2 5/5] PCI: spacemit-k1: Add Spacemit K3 PCIe host
 controller support
In-Reply-To: <20260517014841.254085-6-inochiama@gmail.com>
References: <20260517014841.254085-1-inochiama@gmail.com>
 <20260517014841.254085-6-inochiama@gmail.com>
Message-ID: <2dec4fe6-30d8-4949-bdc1-e32508340b87@riscstar.com>

On 5/16/26 8:48 PM, Inochi Amaoto wrote:
> The PCIe controller on Spacemit K3 is almost a standard Synopsys
> DesignWare PCIe IP with extra link and reset control. Unlike
> the PCIe controller on K1, this controller supports external MSI
> interrupt controller and can use multiple PHYs at the same time.
> 
> Add driver to support PCIe controller on Spacemit K3 PCIe.

It seems like you're creating a lot of new code for K3.  In
some cases it's very similar to K1, and it's not clear why it
needs to be different.

I'd much rather see a patch that prepares for K3 support by
doing minor refactoring of the existing code to support K1
in a way that will make adding K3 support more natural.
Then a patch to enable K3 should be simpler (and can focus
on what is truly different).

> 
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> ---
>   drivers/pci/controller/dwc/Kconfig            |   4 +-
>   drivers/pci/controller/dwc/pcie-spacemit-k1.c | 169 ++++++++++++++++++
>   2 files changed, 171 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
> index f2fde13107f2..fae971ecd876 100644
> --- a/drivers/pci/controller/dwc/Kconfig
> +++ b/drivers/pci/controller/dwc/Kconfig
> @@ -439,7 +439,7 @@ config PCIE_SOPHGO_DW
>   	  Sophgo SoCs.
>   
>   config PCIE_SPACEMIT_K1
> -	tristate "SpacemiT K1 PCIe controller (host mode)"
> +	tristate "SpacemiT K1/K3 PCIe controller (host mode)"
>   	depends on ARCH_SPACEMIT || COMPILE_TEST
>   	depends on HAS_IOMEM
>   	select PCIE_DW_HOST
> @@ -447,7 +447,7 @@ config PCIE_SPACEMIT_K1
>   	default ARCH_SPACEMIT
>   	help
>   	  Enables support for the DesignWare based PCIe controller in
> -	  the SpacemiT K1 SoC operating in host mode.  Three controllers
> +	  the SpacemiT K1/K3 SoC operating in host mode. Three controllers
>   	  are available on the K1 SoC; the first of these shares a PHY
>   	  with a USB 3.0 host controller (one or the other can be used).
>   
> diff --git a/drivers/pci/controller/dwc/pcie-spacemit-k1.c b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> index 7f6f1df31cd8..7854d26220a9 100644
> --- a/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> +++ b/drivers/pci/controller/dwc/pcie-spacemit-k1.c
> @@ -23,6 +23,7 @@
>   
>   #define PCI_VENDOR_ID_SPACEMIT		0x201f
>   #define PCI_DEVICE_ID_SPACEMIT_K1	0x0001
> +#define PCI_DEVICE_ID_SPACEMIT_K3	0x0002
>   
>   /* Offsets and field definitions for link management registers */
>   #define K1_PHY_AHB_IRQ_EN			0x0000
> @@ -32,8 +33,20 @@
>   #define SMLH_LINK_UP			BIT(1)
>   #define RDLH_LINK_UP			BIT(12)
>   
> +#define INTR_STATUS				0x0010
> +
>   #define INTR_ENABLE				0x0014
>   #define MSI_CTRL_INT			BIT(11)
> +#define RDLH_LINK_UP_INT		BIT(20)
> +
> +#define K3_PHY_AHB_IRQSTATUS_INTX		0x0008

Can you add INTX support for K1 as well (perhaps in a separate
patch)?

> +#define K3_ADDR_INTR_STATUS1			0x0018
> +
> +#define K3_CACHE_MSTR_AWCACHE_MODE	GENMASK(14, 11)
> +#define K3_CACHE_MSTR_AWCACHE_BEHAVIOR	0xf
> +
> +#define K3_MAX_PHY_NUMBER		6

You used "count" in patch 2 as the field name.

>   
>   /* Some controls require APMU regmap access */
>   #define SYSCON_APMU			"spacemit,apmu"
> @@ -48,6 +61,9 @@
>   
>   #define PCIE_CONTROL_LOGIC			0x0004
>   #define PCIE_SOFT_RESET			BIT(0)
> +#define PCIE_PERSTN_OE			BIT(24)
> +#define PCIE_PERSTN_OUT			BIT(25)
> +#define PCIE_IGNORE_PERSTN		BIT(31)
>   
>   struct k1_pcie {
>   	struct dw_pcie pci;
> @@ -262,6 +278,152 @@ static const struct dw_pcie_ops k1_pcie_ops = {
>   	.stop_link	= k1_pcie_stop_link,
>   };
>   
> +static int k3_pcie_enable_phy(struct k1_pcie *pcie)

Can you just make K1's single PHY be a special case of
having "N" PHYs?  I.e., just set the phy_count for
K1 to be 1, so this loop would work for both K1 and K3?

> +{
> +	int i, ret;
> +
> +	for (i = 0; i < pcie->phy_count; i++) {
> +		ret = phy_init(pcie->phy[i]);
> +		if (ret)
> +			goto err_phy;
> +	}
> +
> +	return 0;
> +
> +err_phy:
> +	while (--i >= 0)
> +		phy_exit(pcie->phy[i]);
> +
> +	return ret;
> +}
> +
> +static int k3_pcie_init(struct dw_pcie_rp *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	struct k1_pcie *k1 = to_k1_pcie(pci);
> +	u32 reset_ctrl = k1->pmu_off + PCIE_CLK_RESET_CONTROL;
> +	u32 val;
> +	int ret;
> +
> +	regmap_clear_bits(k1->pmu, reset_ctrl, LTSSM_EN);

Should the above be done for K1?  Would it hurt?  Handle
both K1 and K3 the same way if possible.

The next two things are identical to k1_pcie_init().  Make
the code common if possible, so it's very obvious what
really needs to be different between the two.

> +
> +	k1_pcie_toggle_soft_reset(k1);

The "k1" prefix is fine for now, but if this driver gets
used for more devices in the future, it might be worth
renaming things to emphasize that it's not K1-specific.

> +	ret = k1_pcie_enable_resources(k1);
> +	if (ret)
> +		return ret;
> +
> +	regmap_set_bits(k1->pmu, reset_ctrl, PCIE_AUX_PWR_DET);
> +	regmap_clear_bits(k1->pmu, reset_ctrl, APP_HOLD_PHY_RST);
> +

You enable the PHY here much earlier than what's done in
the K1 code.  Should the K1 PHY be enabled earlier?
Also, I don't really think there needs to be separate
versions of the code that enables PHYs for K1 and K3.

> +	ret = k3_pcie_enable_phy(k1);
> +	if (ret) {
> +		k1_pcie_disable_resources(k1);
> +		return ret;
> +	}
> +
> +	/* K3: Set IGNORE_PERSTN and drive PERSTN_OE high (assert reset) */
> +	regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> +			PCIE_IGNORE_PERSTN | PCIE_PERSTN_OE | PCIE_PERSTN_OUT);
> +	usleep_range(1000, 2000);
> +	regmap_clear_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC, PCIE_PERSTN_OUT);
> +
> +	msleep(PCIE_T_PVPERL_MS);
> +
> +	/*
> +	 * Put the controller in root complex mode, and indicate that
> +	 * Vaux (3.3v) is present.
> +	 */
> +	regmap_set_bits(k1->pmu, k1->pmu_off + PCIE_CONTROL_LOGIC,
> +			PCIE_PERSTN_OUT | PCIE_PERSTN_OE);
> +
> +	val = dw_pcie_readl_dbi(pci, GEN3_EQ_CONTROL_OFF);
> +	val = u32_replace_bits(val, GEN3_EQ_CONTROL_OFF_PHASE23_EXIT_MODE,
> +			       GEN3_EQ_CONTROL_OFF_PSET_REQ_VEC);
> +	dw_pcie_writel_dbi(pci, GEN3_EQ_CONTROL_OFF, val);
> +

The following block of code (roughly) is done right after
enabling resources in the K1 version of this function.

Maybe the order you do it is better, but in that case,
change the (existing, and soon, common) code to do it
however is best if that's the case.

You should try to factor out the common parts and minimize
what's actually different between the two.

I would also expect that the device ID would be stored in the
platform data rather than having both init functions hard-code
the value here.

I'm going to leave it at that for now.

					-Alex

> +	dw_pcie_dbi_ro_wr_en(pci);
> +	dw_pcie_writew_dbi(pci, PCI_VENDOR_ID, PCI_VENDOR_ID_SPACEMIT);
> +	dw_pcie_writew_dbi(pci, PCI_DEVICE_ID, PCI_DEVICE_ID_SPACEMIT_K3);
> +	dw_pcie_dbi_ro_wr_dis(pci);
> +
> +	/* Finally, as a workaround, disable ASPM L1 */
> +	k1_pcie_disable_aspm_l1(k1);
> +
> +	return 0;
> +}
> +
> +static int k3_pcie_msi_host_init(struct dw_pcie_rp *pp)
> +{
> +	struct dw_pcie *pci = to_dw_pcie_from_pp(pp);
> +	u32 val;
> +
> +	dw_pcie_dbi_ro_wr_en(pci);
> +
> +	val = dw_pcie_readl_dbi(pci, COHERENCY_CONTROL_3_OFF);
> +	val |= u32_replace_bits(val, K3_CACHE_MSTR_AWCACHE_BEHAVIOR,
> +				K3_CACHE_MSTR_AWCACHE_MODE);
> +	dw_pcie_writel_dbi(pci, COHERENCY_CONTROL_3_OFF, val);
> +
> +	dw_pcie_dbi_ro_wr_dis(pci);
> +
> +	return 0;
> +}
> +
> +static const struct dw_pcie_host_ops k3_pcie_host_ops = {
> +	.init		= k3_pcie_init,
> +	.deinit		= k1_pcie_deinit,
> +	.msi_init	= k3_pcie_msi_host_init,
> +};
> +
> +static const struct dw_pcie_ops k3_pcie_ops = {
> +	.link_up	= k1_pcie_link_up,
> +	.start_link	= k1_pcie_start_link,
> +	.stop_link	= k1_pcie_stop_link,
> +};
> +
> +static void k3_pcie_clear_irq_status(struct k1_pcie *k1,
> +				     u32 *status0, u32 *status1, u32 *status2)
> +{
> +	*status0 = readl_relaxed(k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> +	*status1 = readl_relaxed(k1->link + INTR_STATUS);
> +	*status2 = readl_relaxed(k1->link + K3_ADDR_INTR_STATUS1);
> +
> +	writel_relaxed(*status0, k1->link + K3_PHY_AHB_IRQSTATUS_INTX);
> +	writel_relaxed(*status1, k1->link + INTR_STATUS);
> +	writel_relaxed(*status2, k1->link + K3_ADDR_INTR_STATUS1);
> +}
> +
> +static int k3_pcie_parse_port(struct k1_pcie *k1)
> +{
> +	struct device *dev = k1->pci.dev;
> +	u32 status0, status1, status2;
> +	int i;
> +
> +	k1->phy = devm_kmalloc_array(dev, K3_MAX_PHY_NUMBER, sizeof(*k1->phy),
> +				     GFP_KERNEL);
> +	if (!k1->phy)
> +		return -ENOMEM;
> +
> +	for (i = 0; i < K3_MAX_PHY_NUMBER; i++) {
> +		k1->phy[i] = devm_of_phy_get_by_index(dev, dev->of_node, i);
> +		if (IS_ERR(k1->phy[i])) {
> +			if (PTR_ERR(k1->phy[i]) == -ENODEV)
> +				break;
> +
> +			return PTR_ERR(k1->phy[i]);
> +		}
> +	}
> +
> +	k1->phy_count = i;
> +	if (k1->phy_count == 0)
> +		return -EINVAL;
> +
> +	k3_pcie_clear_irq_status(k1, &status0, &status1, &status2);
> +
> +	return 0;
> +}
> +
>   static int k1_pcie_parse_port(struct k1_pcie *k1)
>   {
>   	struct device *dev = k1->pci.dev;
> @@ -363,8 +525,15 @@ static const struct k1_pcie_device_data k1_pcie_device_data = {
>   	.parse_port	= k1_pcie_parse_port,
>   };
>   
> +static const struct k1_pcie_device_data k3_pcie_device_data = {
> +	.host_ops	= &k3_pcie_host_ops,
> +	.ops		= &k3_pcie_ops,
> +	.parse_port	= k3_pcie_parse_port,
> +};
> +
>   static const struct of_device_id k1_pcie_of_match_table[] = {
>   	{ .compatible = "spacemit,k1-pcie", .data = &k1_pcie_device_data},
> +	{ .compatible = "spacemit,k3-pcie", .data = &k3_pcie_device_data},
>   	{ }
>   };
>   



From elder at riscstar.com  Tue Jun  9 09:11:27 2026
From: elder at riscstar.com (Alex Elder)
Date: Tue, 9 Jun 2026 11:11:27 -0500
Subject: [PATCH v2 5/5] PCI: spacemit-k1: Add Spacemit K3 PCIe host
 controller support
In-Reply-To: <wztjdv4t5cn7djj3jyvheest7rn5nr2g3efzwods2fz3yy5wn2@hbl644sd6fst>
References: <20260517014841.254085-1-inochiama@gmail.com>
 <20260517014841.254085-6-inochiama@gmail.com>
 <wztjdv4t5cn7djj3jyvheest7rn5nr2g3efzwods2fz3yy5wn2@hbl644sd6fst>
Message-ID: <b025f81e-e3a5-4b55-a6b4-cbd9731fe0df@riscstar.com>

On 6/9/26 9:18 AM, Manivannan Sadhasivam wrote:
> On Sun, May 17, 2026 at 09:48:40AM +0800, Inochi Amaoto wrote:
>> The PCIe controller on Spacemit K3 is almost a standard Synopsys
>> DesignWare PCIe IP with extra link and reset control. Unlike
>> the PCIe controller on K1, this controller supports external MSI
>> interrupt controller and can use multiple PHYs at the same time.
>>
>> Add driver to support PCIe controller on Spacemit K3 PCIe.
>>
>> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
>> ---
>>   drivers/pci/controller/dwc/Kconfig            |   4 +-
>>   drivers/pci/controller/dwc/pcie-spacemit-k1.c | 169 ++++++++++++++++++
>>   2 files changed, 171 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig
>> index f2fde13107f2..fae971ecd876 100644
>> --- a/drivers/pci/controller/dwc/Kconfig
>> +++ b/drivers/pci/controller/dwc/Kconfig
>> @@ -439,7 +439,7 @@ config PCIE_SOPHGO_DW
>>   	  Sophgo SoCs.
>>   
>>   config PCIE_SPACEMIT_K1
>> -	tristate "SpacemiT K1 PCIe controller (host mode)"
>> +	tristate "SpacemiT K1/K3 PCIe controller (host mode)"
> 
> Can you just say 'SpacemiT PCIe controller (host mode)"? I believe I asked Alex
> while adding K1 support and he said this driver might not support future IP
> revisions, but here we are.

(Sorry if I said that in error.)  Will this be K1 and K3 only?
If so what you say is fine, but I agree with Mani, if it's going
to also form the basis of K5 (or whatever) just make it "SpacemiT".
And probably change the Kconfig symbol to PCIE_SPACEMIT.

					-Alex

>>   	depends on ARCH_SPACEMIT || COMPILE_TEST
>>   	depends on HAS_IOMEM
>>   	select PCIE_DW_HOST
>> @@ -447,7 +447,7 @@ config PCIE_SPACEMIT_K1
>>   	default ARCH_SPACEMIT
>>   	help
>>   	  Enables support for the DesignWare based PCIe controller in
>> -	  the SpacemiT K1 SoC operating in host mode.  Three controllers
>> +	  the SpacemiT K1/K3 SoC operating in host mode. Three controllers
>>   	  are available on the K1 SoC; the first of these shares a PHY
>>   	  with a USB 3.0 host controller (one or the other can be used).
>>   . . .


From kernel at rembrandt.dev  Tue Jun  9 11:24:46 2026
From: kernel at rembrandt.dev (Andrew Rembrandt)
Date: Tue, 9 Jun 2026 20:24:46 +0200
Subject: [PATCH] riscv: dts: spacemit: k3-pico-itx: Fix non-functional
 ethernet TX timing
In-Reply-To: <aiemGajqcQeY9avz@inochi.infowork>
References: <20260608182358.170489-1-kernel@rembrandt.dev>
 <aiemGajqcQeY9avz@inochi.infowork>
Message-ID: <aihYftGNcpUd4UUR@mcmanus>

On Tue, Jun 09, 2026 at 01:37:56 pm Inochi Amaoto wrote:
> You should set tx-internal-delay-ps of the phy instead of
> the controller. This is a phy in "rgmii-id" mode.
Thanks for the review. I don't think that works on this board, but
please let me know if I'm missing something.

The PHY is a Realtek RTL8211F. Its driver only toggles the chip's fixed
~2ns delay on/off from phy-mode, and per the datasheet that's a hardware
limit, not a driver one -- the RTL8211F has no tunable delay, so a ps
value on the PHY node has nothing to act on.

The only configurable delay element on K3 is the SoC RGMII delay line,
and dwmac-spacemit programs it from tx-/rx-internal-delay-ps read off
the controller node (spacemit_dwmac_probe()), so that is where the
property has to live to take effect. This is the MAC "fine tuning ...
values expected here are small" case described in
Documentation/devicetree/bindings/net/ethernet-controller.yaml: the
RTL8211F supplies the fixed ~2ns via rgmii-id and the MAC adds a 400ps
trim on top. Ideally the PHY would own the delay, but as Andrew Lunn
noted reviewing dwmac-meson8b, that requires the PHY to implement a
configurable delay, which not all do.

The already-merged k1-bananapi-f3 does the same thing: eth1 combines
phy-mode = "rgmii-id" with tx-internal-delay-ps = <250> on the
controller node (via the K1 EMAC rather than dwmac, but the same DT
pattern).

Would you be OK keeping it on the controller given the above? For v2 I
can add an explicit rx-internal-delay-ps = <0> to match the other
SpacemiT boards (k1-bananapi-f3 included) and spell this reasoning out
in the commit message.

Thanks,
Andrew


From jsun at junsun.net  Tue Jun  9 11:32:50 2026
From: jsun at junsun.net (Jun Sun)
Date: Tue,  9 Jun 2026 11:32:50 -0700
Subject: [PATCH] riscv: cpufeature: remove _RO from use_hcontext for KVM=m
Message-ID: <20260609183250.41892-1-jsun@junsun.net>

use_hcontext is in __ro_after_init but only referenced from KVM's
__jump_table. With KVM=m, jump_label_init_ro() never sees it, so
it is never sealed. Module load then tries to write to the RO key
in jump_label_add_module() and oopses.
---
 arch/riscv/kernel/cpufeature.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 903e27cf908f..3a68d20156e8 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -49,7 +49,7 @@ u32 thead_vlenb_of;
 atomic_t hcontext_disable;
 atomic_t scontext_disable;
 
-DEFINE_STATIC_KEY_FALSE_RO(use_hcontext);
+DEFINE_STATIC_KEY_FALSE(use_hcontext);
 EXPORT_SYMBOL(use_hcontext);
 
 DEFINE_STATIC_KEY_FALSE_RO(use_scontext);
-- 
2.34.1



From jsun at junsun.net  Tue Jun  9 11:37:24 2026
From: jsun at junsun.net (Jun Sun)
Date: Tue,  9 Jun 2026 11:37:24 -0700
Subject: [PATCH] KVM: riscv: aia: use lr.d/sc.d on RV64 in imsic_mrif_atomic_rmw
Message-ID: <20260609183724.41974-1-jsun@junsun.net>

imsic_mrif_atomic_rmw() uses lr.w.aq/sc.w.rl (32-bit) on an
`unsigned long *ptr`. On RV64 this drops the upper 32 bits of every
guest EIE/EIP write, so MSIs to EIIDs >= 32 are silently lost in AIA
EMUL mode. Gate on CONFIG_32BIT and use lr.d.aq/sc.d.rl on RV64.

Signed-off-by: Jun Sun <jsun at junsun.net>
---
 arch/riscv/kvm/aia_imsic.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/riscv/kvm/aia_imsic.c b/arch/riscv/kvm/aia_imsic.c
index 11422cb95a64..933292683a05 100644
--- a/arch/riscv/kvm/aia_imsic.c
+++ b/arch/riscv/kvm/aia_imsic.c
@@ -221,10 +221,17 @@ static unsigned long imsic_mrif_atomic_rmw(struct imsic_mrif *mrif,
 	unsigned long old_val = 0, tmp = 0;
 
 	__asm__ __volatile__ (
+#ifdef CONFIG_32BIT
 		"0:	lr.w.aq   %1, %0\n"
 		"	and       %2, %1, %3\n"
 		"	or        %2, %2, %4\n"
 		"	sc.w.rl   %2, %2, %0\n"
+#else
+		"0:	lr.d.aq   %1, %0\n"
+		"	and       %2, %1, %3\n"
+		"	or        %2, %2, %4\n"
+		"	sc.d.rl   %2, %2, %0\n"
+#endif
 		"	bnez      %2, 0b"
 		: "+A" (*ptr), "+r" (old_val), "+r" (tmp)
 		: "r" (~wr_mask), "r" (new_val & wr_mask)
-- 
2.34.1



From jsun at junsun.net  Tue Jun  9 11:39:21 2026
From: jsun at junsun.net (Jun Sun)
Date: Tue,  9 Jun 2026 11:39:21 -0700
Subject: [PATCH] KVM: riscv: mirror VSTIMECMP into t->next_cycles in sstc path
Message-ID: <20260609183921.42043-1-jsun@junsun.net>

update_vstimecmp writes the new target to the hardware-visible VSTIMECMP
CSR (via NACL shmem) but did not also update t->next_cycles.  Between
the SBI set_timer handler and the next guest entry, preemption can fire
(at preempt_enable after sync_interrupts, or via schedule() in
kvm_xfer_to_guest_mode_handle_work / kvm_riscv_check_vcpu_requests).
When the vCPU is reloaded, kvm_arch_vcpu_load -> kvm_riscv_vcpu_timer_restore
writes ncsr_write(VSTIMECMP, t->next_cycles), which clobbers the fresh
shmem value with a stale t->next_cycles from a prior iteration.  The
guest then resumes with VSTIMECMP set to an old far-future value;
hardware never asserts VSTIP; the guest's timer ISR never runs; boot
wedges with riscv-timer counter frozen.

Without the fix AOSP/cuttlefish stalls on K3 + crosvm: guest /proc/interrupts
riscv-timer counter frozen indefinitely while /proc/uptime keeps climbing.
With the fix AOSP/cuttlefish boots up fine.

Mirror the value into t->next_cycles next to the ncsr_write, matching
what kvm_riscv_vcpu_update_hrtimer already does for the non-sstc path.
---
 arch/riscv/kvm/vcpu_timer.c | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/arch/riscv/kvm/vcpu_timer.c b/arch/riscv/kvm/vcpu_timer.c
index 85a7262115e1..4e31a6a341c5 100644
--- a/arch/riscv/kvm/vcpu_timer.c
+++ b/arch/riscv/kvm/vcpu_timer.c
@@ -71,6 +71,15 @@ static int kvm_riscv_vcpu_timer_cancel(struct kvm_vcpu_timer *t)
 
 static int kvm_riscv_vcpu_update_vstimecmp(struct kvm_vcpu *vcpu, u64 ncycles)
 {
+	/*
+	 * Mirror kvm_riscv_vcpu_update_hrtimer (the non-sstc path):
+	 * update t->next_cycles, and then set hw CSR_VSTIMECMP.
+	 * Otherwise, a race condition with preemption can cause
+	 * CSR_VSTIMECMP to end up holding a stale value
+	 * (kvm_riscv_vcpu_timer_restore writes the old t->next_cycles
+	 * back into VSTIMECMP shmem on sched-in).
+	 */
+	vcpu->arch.timer.next_cycles = ncycles;
 #if defined(CONFIG_32BIT)
 	ncsr_write(CSR_VSTIMECMP, ncycles & 0xFFFFFFFF);
 	ncsr_write(CSR_VSTIMECMPH, ncycles >> 32);
-- 
2.34.1



From jsun at junsun.net  Tue Jun  9 11:41:42 2026
From: jsun at junsun.net (Jun Sun)
Date: Tue,  9 Jun 2026 11:41:42 -0700
Subject: [PATCH] KVM: aia: skip silicon ID cap in EMUL mode
Message-ID: <20260609184142.42125-1-jsun@junsun.net>

EMUL mode uses swfile MRIF in software, not the silicon vsfile, so
the per-vsfile ID limit (kvm_riscv_aia_max_ids) shouldn't gate
the maximum IDs userspace can request. Allow up to KVM_DEV_RISCV_AIA_IDS_MAX
in EMUL mode; HWACCEL/AUTO still enforce the silicon cap.
---
 arch/riscv/kvm/aia_device.c | 23 +++++++++++++++++++----
 1 file changed, 19 insertions(+), 4 deletions(-)

diff --git a/arch/riscv/kvm/aia_device.c b/arch/riscv/kvm/aia_device.c
index b195a93add1c..575f860e1dad 100644
--- a/arch/riscv/kvm/aia_device.c
+++ b/arch/riscv/kvm/aia_device.c
@@ -82,8 +82,16 @@ static int aia_config(struct kvm *kvm, unsigned long type,
 			if ((*nr < KVM_DEV_RISCV_AIA_IDS_MIN) ||
 			    (*nr >= KVM_DEV_RISCV_AIA_IDS_MAX) ||
 			    ((*nr & KVM_DEV_RISCV_AIA_IDS_MIN) !=
-			     KVM_DEV_RISCV_AIA_IDS_MIN) ||
-			    (kvm_riscv_aia_max_ids <= *nr))
+			     KVM_DEV_RISCV_AIA_IDS_MIN))
+				return -EINVAL;
+			/*
+			 * kvm_riscv_aia_max_ids reflects the per-vsfile
+			 * silicon limit, which only applies in HWACCEL
+			 * mode.  EMUL uses swfile, and AUTO is reconciled
+			 * later during init, so neither gates here.
+			 */
+			if (aia->mode == KVM_DEV_RISCV_AIA_MODE_HWACCEL &&
+			    kvm_riscv_aia_max_ids <= *nr)
 				return -EINVAL;
 			aia->nr_ids = *nr;
 		} else
@@ -91,8 +99,15 @@ static int aia_config(struct kvm *kvm, unsigned long type,
 		break;
 	case KVM_DEV_RISCV_AIA_CONFIG_SRCS:
 		if (write) {
-			if ((*nr >= KVM_DEV_RISCV_AIA_SRCS_MAX) ||
-			    (*nr >= kvm_riscv_aia_max_ids))
+			if (*nr >= KVM_DEV_RISCV_AIA_SRCS_MAX)
+				return -EINVAL;
+			/*
+			 * Same rationale as CONFIG_IDS: the silicon
+			 * per-vsfile cap only applies in HWACCEL mode.
+			 * EMUL uses swfile; AUTO is reconciled at init.
+			 */
+			if (aia->mode == KVM_DEV_RISCV_AIA_MODE_HWACCEL &&
+			    *nr >= kvm_riscv_aia_max_ids)
 				return -EINVAL;
 			aia->nr_sources = *nr;
 		} else
-- 
2.34.1



From docular.xu at gmail.com  Tue Jun  9 11:55:59 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Tue, 9 Jun 2026 14:55:59 -0400
Subject: [PATCH 1/2] dt-bindings: dmaengine: Add SpacemiT K1 PDMA request
 numbers
In-Reply-To: <20260608-dazzling-hacksaw-dbe84766ec76@spud>
References: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>
 <20260607-b4-k1-pdma-req-macros-v1-1-5b2a3955007c@gmail.com>
 <20260608-dazzling-hacksaw-dbe84766ec76@spud>
Message-ID: <qxcpvj3eseclgonwuwx2szn2tj4uxci27mvpqwotj6uaiyj65p@7sx5tyzbfs2g>

Hi, Conor

On 2026-06-08 18:33, Conor Dooley wrote:
>On Sun, Jun 07, 2026 at 01:41:30PM -0400, Guodong Xu wrote:
>> Add a dt-bindings header that gives symbolic names to the SpacemiT K1
>> PDMA request lines of the non-secure peripherals. Device trees can use
>> these K1_PDMA_* macros instead of magic numbers.
>>
>> Point the spacemit,k1-pdma binding's #dma-cells description at the new
>> header.
>>
>> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
>> ---
>>  .../devicetree/bindings/dma/spacemit,k1-pdma.yaml  |  4 +-
>>  include/dt-bindings/dma/spacemit,k1-pdma.h         | 56 ++++++++++++++++++++++
>>  2 files changed, 59 insertions(+), 1 deletion(-)
>>
>> diff --git a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
>> index ec06235baf5ca..0d4ac9849e27b 100644
>> --- a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
>> +++ b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
>> @@ -35,7 +35,9 @@ properties:
>>    '#dma-cells':
>>      const: 1
>>      description:
>> -      The DMA request number for the peripheral device.
>> +      The single cell is the DMA request number for the peripheral device.
>> +      See <dt-bindings/dma/spacemit,k1-pdma.h> for the list of valid request
>> +      numbers.
>>
>>  required:
>>    - compatible
>> diff --git a/include/dt-bindings/dma/spacemit,k1-pdma.h b/include/dt-bindings/dma/spacemit,k1-pdma.h
>
>Why does this need to be in a binding when there is no use of this in
>the driver? May as well be a header, particularly if these are numbers

Thanks for the review. You are correct that these are not referenced in the
driver. My change to k1-pdma.yaml should be dropped.

>with a set meaning that are lifted from the TRM, rather than made up
>numbers to make a driver work. The former seems likely, given you're
>indexing from 3 not 0.

Yes, it is defined in the K1 manual [1], see 9.4.3 DMA Connectivity &
Assignments

Link: https://www.spacemit.com/community/document/info?lang=en&nodepath=hardware/key_stone/k1/k1_docs/k1_usermanual/9.Top_System.md [1]

I will fix that in v2.

BR,
Guodong

>
>> new file mode 100644
>> index 0000000000000..491976516550a
>> --- /dev/null
>> +++ b/include/dt-bindings/dma/spacemit,k1-pdma.h
>> @@ -0,0 +1,56 @@
>> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
>> +/*
>> + * This header provides DMA request number for non-secure peripherals of
>> + * SpacemiT K1 PDMA.
>> + *
>> + * Copyright (c) 2026 Guodong Xu <docular.xu at gmail.com>
>> + */
>> +
>> +#ifndef _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
>> +#define _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
>> +
>> +#define K1_PDMA_UART0_TX	3
>> +#define K1_PDMA_UART0_RX	4
>> +#define K1_PDMA_UART2_TX	5
>> +#define K1_PDMA_UART2_RX	6
>> +#define K1_PDMA_UART3_TX	7
>> +#define K1_PDMA_UART3_RX	8
>> +#define K1_PDMA_UART4_TX	9
>> +#define K1_PDMA_UART4_RX	10
>> +#define K1_PDMA_I2C0_TX		11
>> +#define K1_PDMA_I2C0_RX		12
>> +#define K1_PDMA_I2C1_TX		13
>> +#define K1_PDMA_I2C1_RX		14
>> +#define K1_PDMA_I2C2_TX		15
>> +#define K1_PDMA_I2C2_RX		16
>> +#define K1_PDMA_I2C4_TX		17
>> +#define K1_PDMA_I2C4_RX		18
>> +#define K1_PDMA_SPI3_TX		19
>> +#define K1_PDMA_SPI3_RX		20
>> +#define K1_PDMA_I2S0_TX		21
>> +#define K1_PDMA_I2S0_RX		22
>> +#define K1_PDMA_I2S1_TX		23
>> +#define K1_PDMA_I2S1_RX		24
>> +#define K1_PDMA_UART5_TX	25
>> +#define K1_PDMA_UART5_RX	26
>> +#define K1_PDMA_UART6_TX	27
>> +#define K1_PDMA_UART6_RX	28
>> +#define K1_PDMA_UART7_TX	29
>> +#define K1_PDMA_UART7_RX	30
>> +#define K1_PDMA_UART8_TX	31
>> +#define K1_PDMA_UART8_RX	32
>> +#define K1_PDMA_UART9_TX	33
>> +#define K1_PDMA_UART9_RX	34
>> +#define K1_PDMA_I2C5_TX		35
>> +#define K1_PDMA_I2C5_RX		36
>> +#define K1_PDMA_I2C6_TX		37
>> +#define K1_PDMA_I2C6_RX		38
>> +#define K1_PDMA_I2C7_TX		39
>> +#define K1_PDMA_I2C7_RX		40
>> +#define K1_PDMA_I2C8_TX		41
>> +#define K1_PDMA_I2C8_RX		42
>> +#define K1_PDMA_CAN0_RX		43
>> +#define K1_PDMA_QSPI_RX		44
>> +#define K1_PDMA_QSPI_TX		45
>> +
>> +#endif /* _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_ */
>>
>> --
>> 2.43.0
>>




From docular.xu at gmail.com  Tue Jun  9 12:46:37 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Tue, 09 Jun 2026 15:46:37 -0400
Subject: [PATCH v2 0/2] dt-bindings: Add SpacemiT K1 PDMA request-number
 header and use it in DT
Message-ID: <20260609-b4-k1-pdma-req-macros-v2-0-5d5d7b997b54@gmail.com>

Currently, K1 device trees specify PDMA peripheral requests as raw numbers.
Add a dt-bindings header naming those request lines and convert the current
user (the K1 SPI3 node) to the new K1_PDMA_* macros.

Patch 1 adds include/dt-bindings/dma/spacemit,k1-pdma.h with the
  K1_PDMA_* request-number macros.
Patch 2 updates the current pdma user (currently spi3) in k1.dtsi to
  use these request number macros.

This patchset is based on dt-for-next of spacemit linux tree. The
request number defined in Patch 1 comes from SpacemiT K1 User Manual
[1], Chapter 9.4.3 DMA Connectivity & Assignments.

[1]: https://www.spacemit.com/community/document/info?lang=en&nodepath=hardware/key_stone/k1/k1_docs/k1_usermanual/9.Top_System.md

Changes in v2:
- Drop the #dma-cells description change in spacemit,k1-pdma.yaml; the request
  numbers are hardware-fixed and unused by the driver (Conor)
- Link to v1: https://patch.msgid.link/20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c at gmail.com

BR,
Guodong Xu

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
Guodong Xu (2):
      dt-bindings: dmaengine: Add SpacemiT K1 PDMA request numbers
      riscv: dts: spacemit: Use symbolic PDMA request numbers on K1

 arch/riscv/boot/dts/spacemit/k1.dtsi       |  3 +-
 include/dt-bindings/dma/spacemit,k1-pdma.h | 56 ++++++++++++++++++++++++++++++
 2 files changed, 58 insertions(+), 1 deletion(-)
---
base-commit: 793cc54475b49b5b558902b5c13e4bfe66530a50
change-id: 20260607-b4-k1-pdma-req-macros-8d276d0126df

Best regards,
--  
Guodong Xu <docular.xu at gmail.com>



From docular.xu at gmail.com  Tue Jun  9 12:46:38 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Tue, 09 Jun 2026 15:46:38 -0400
Subject: [PATCH v2 1/2] dt-bindings: dmaengine: Add SpacemiT K1 PDMA
 request numbers
In-Reply-To: <20260609-b4-k1-pdma-req-macros-v2-0-5d5d7b997b54@gmail.com>
References: <20260609-b4-k1-pdma-req-macros-v2-0-5d5d7b997b54@gmail.com>
Message-ID: <20260609-b4-k1-pdma-req-macros-v2-1-5d5d7b997b54@gmail.com>

Add a dt-bindings header that gives symbolic names to the SpacemiT K1
PDMA request lines of the non-secure peripherals. Device trees can use
these K1_PDMA_* macros instead of magic numbers.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
V2: Drop the #dma-cells description change in spacemit,k1-pdma.yaml; the
    request numbers are hardware-fixed and unused by the driver.
---
 include/dt-bindings/dma/spacemit,k1-pdma.h | 56 ++++++++++++++++++++++++++++++
 1 file changed, 56 insertions(+)

diff --git a/include/dt-bindings/dma/spacemit,k1-pdma.h b/include/dt-bindings/dma/spacemit,k1-pdma.h
new file mode 100644
index 0000000000000..491976516550a
--- /dev/null
+++ b/include/dt-bindings/dma/spacemit,k1-pdma.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * This header provides DMA request number for non-secure peripherals of
+ * SpacemiT K1 PDMA.
+ *
+ * Copyright (c) 2026 Guodong Xu <docular.xu at gmail.com>
+ */
+
+#ifndef _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
+#define _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
+
+#define K1_PDMA_UART0_TX	3
+#define K1_PDMA_UART0_RX	4
+#define K1_PDMA_UART2_TX	5
+#define K1_PDMA_UART2_RX	6
+#define K1_PDMA_UART3_TX	7
+#define K1_PDMA_UART3_RX	8
+#define K1_PDMA_UART4_TX	9
+#define K1_PDMA_UART4_RX	10
+#define K1_PDMA_I2C0_TX		11
+#define K1_PDMA_I2C0_RX		12
+#define K1_PDMA_I2C1_TX		13
+#define K1_PDMA_I2C1_RX		14
+#define K1_PDMA_I2C2_TX		15
+#define K1_PDMA_I2C2_RX		16
+#define K1_PDMA_I2C4_TX		17
+#define K1_PDMA_I2C4_RX		18
+#define K1_PDMA_SPI3_TX		19
+#define K1_PDMA_SPI3_RX		20
+#define K1_PDMA_I2S0_TX		21
+#define K1_PDMA_I2S0_RX		22
+#define K1_PDMA_I2S1_TX		23
+#define K1_PDMA_I2S1_RX		24
+#define K1_PDMA_UART5_TX	25
+#define K1_PDMA_UART5_RX	26
+#define K1_PDMA_UART6_TX	27
+#define K1_PDMA_UART6_RX	28
+#define K1_PDMA_UART7_TX	29
+#define K1_PDMA_UART7_RX	30
+#define K1_PDMA_UART8_TX	31
+#define K1_PDMA_UART8_RX	32
+#define K1_PDMA_UART9_TX	33
+#define K1_PDMA_UART9_RX	34
+#define K1_PDMA_I2C5_TX		35
+#define K1_PDMA_I2C5_RX		36
+#define K1_PDMA_I2C6_TX		37
+#define K1_PDMA_I2C6_RX		38
+#define K1_PDMA_I2C7_TX		39
+#define K1_PDMA_I2C7_RX		40
+#define K1_PDMA_I2C8_TX		41
+#define K1_PDMA_I2C8_RX		42
+#define K1_PDMA_CAN0_RX		43
+#define K1_PDMA_QSPI_RX		44
+#define K1_PDMA_QSPI_TX		45
+
+#endif /* _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_ */

-- 
2.43.0



From docular.xu at gmail.com  Tue Jun  9 12:46:39 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Tue, 09 Jun 2026 15:46:39 -0400
Subject: [PATCH v2 2/2] riscv: dts: spacemit: Use symbolic PDMA request
 numbers on K1
In-Reply-To: <20260609-b4-k1-pdma-req-macros-v2-0-5d5d7b997b54@gmail.com>
References: <20260609-b4-k1-pdma-req-macros-v2-0-5d5d7b997b54@gmail.com>
Message-ID: <20260609-b4-k1-pdma-req-macros-v2-2-5d5d7b997b54@gmail.com>

The K1 SPI3 node's "dmas" property hard-codes its PDMA request numbers.
Include <dt-bindings/dma/spacemit,k1-pdma.h> and use the K1_PDMA_SPI3_RX/TX
macros instead, for better code readability and easy for future
maintenance.

No functional change.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
V2: No change.
---
 arch/riscv/boot/dts/spacemit/k1.dtsi | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index 08a0f28d011fe..c413a64d5560c 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -4,6 +4,7 @@
  */
 
 #include <dt-bindings/clock/spacemit,k1-syscon.h>
+#include <dt-bindings/dma/spacemit,k1-pdma.h>
 #include <dt-bindings/phy/phy.h>
 
 /dts-v1/;
@@ -1094,7 +1095,7 @@ spi3: spi at d401c000 {
 				clock-names = "core", "bus";
 				resets = <&syscon_apbc RESET_SSP3>;
 				interrupts = <55>;
-				dmas = <&pdma 20>, <&pdma 19>;
+				dmas = <&pdma K1_PDMA_SPI3_RX>, <&pdma K1_PDMA_SPI3_TX>;
 				dma-names = "rx", "tx";
 				status = "disabled";
 			};

-- 
2.43.0



From conor at kernel.org  Tue Jun  9 12:54:59 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 9 Jun 2026 20:54:59 +0100
Subject: [PATCH 1/2] dt-bindings: dmaengine: Add SpacemiT K1 PDMA request
 numbers
In-Reply-To: <qxcpvj3eseclgonwuwx2szn2tj4uxci27mvpqwotj6uaiyj65p@7sx5tyzbfs2g>
References: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>
 <20260607-b4-k1-pdma-req-macros-v1-1-5b2a3955007c@gmail.com>
 <20260608-dazzling-hacksaw-dbe84766ec76@spud>
 <qxcpvj3eseclgonwuwx2szn2tj4uxci27mvpqwotj6uaiyj65p@7sx5tyzbfs2g>
Message-ID: <20260609-freeload-luckiness-7a143eae62f4@spud>

On Tue, Jun 09, 2026 at 02:55:59PM -0400, Guodong Xu wrote:
> Hi, Conor
> 
> On 2026-06-08 18:33, Conor Dooley wrote:
> > On Sun, Jun 07, 2026 at 01:41:30PM -0400, Guodong Xu wrote:
> > > Add a dt-bindings header that gives symbolic names to the SpacemiT K1
> > > PDMA request lines of the non-secure peripherals. Device trees can use
> > > these K1_PDMA_* macros instead of magic numbers.
> > > 
> > > Point the spacemit,k1-pdma binding's #dma-cells description at the new
> > > header.
> > > 
> > > Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> > > ---
> > >  .../devicetree/bindings/dma/spacemit,k1-pdma.yaml  |  4 +-
> > >  include/dt-bindings/dma/spacemit,k1-pdma.h         | 56 ++++++++++++++++++++++
> > >  2 files changed, 59 insertions(+), 1 deletion(-)
> > > 
> > > diff --git a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
> > > index ec06235baf5ca..0d4ac9849e27b 100644
> > > --- a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
> > > +++ b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
> > > @@ -35,7 +35,9 @@ properties:
> > >    '#dma-cells':
> > >      const: 1
> > >      description:
> > > -      The DMA request number for the peripheral device.
> > > +      The single cell is the DMA request number for the peripheral device.
> > > +      See <dt-bindings/dma/spacemit,k1-pdma.h> for the list of valid request
> > > +      numbers.
> > > 
> > >  required:
> > >    - compatible
> > > diff --git a/include/dt-bindings/dma/spacemit,k1-pdma.h b/include/dt-bindings/dma/spacemit,k1-pdma.h
> > 
> > Why does this need to be in a binding when there is no use of this in
> > the driver? May as well be a header, particularly if these are numbers
> 
> Thanks for the review. You are correct that these are not referenced in the
> driver. My change to k1-pdma.yaml should be dropped.
> 
> > with a set meaning that are lifted from the TRM, rather than made up
> > numbers to make a driver work. The former seems likely, given you're
> > indexing from 3 not 0.
> 
> Yes, it is defined in the K1 manual [1], see 9.4.3 DMA Connectivity &
> Assignments
> 
> Link: https://www.spacemit.com/community/document/info?lang=en&nodepath=hardware/key_stone/k1/k1_docs/k1_usermanual/9.Top_System.md [1]
> 
> I will fix that in v2.

Just in case I wasn't clear (and I think I wasn't), when I said "may as
well be a header" I meant a header in arch/riscv/boot/dts/spacemit.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260609/da842ed2/attachment.sig>

From docular.xu at gmail.com  Tue Jun  9 14:06:24 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Tue, 9 Jun 2026 17:06:24 -0400
Subject: [PATCH 1/2] dt-bindings: dmaengine: Add SpacemiT K1 PDMA request
 numbers
In-Reply-To: <20260609-freeload-luckiness-7a143eae62f4@spud>
References: <20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c@gmail.com>
 <20260607-b4-k1-pdma-req-macros-v1-1-5b2a3955007c@gmail.com>
 <20260608-dazzling-hacksaw-dbe84766ec76@spud>
 <qxcpvj3eseclgonwuwx2szn2tj4uxci27mvpqwotj6uaiyj65p@7sx5tyzbfs2g>
 <20260609-freeload-luckiness-7a143eae62f4@spud>
Message-ID: <6ycdvhpgygnelzp3ot63xtzcnlvac7emngvj7tviiclst4a7km@kjq7oqvecnxx>

On 2026-06-09 20:54, Conor Dooley wrote:
>On Tue, Jun 09, 2026 at 02:55:59PM -0400, Guodong Xu wrote:
>> Hi, Conor
>>
>> On 2026-06-08 18:33, Conor Dooley wrote:
>> > On Sun, Jun 07, 2026 at 01:41:30PM -0400, Guodong Xu wrote:
>> > > Add a dt-bindings header that gives symbolic names to the SpacemiT K1
>> > > PDMA request lines of the non-secure peripherals. Device trees can use
>> > > these K1_PDMA_* macros instead of magic numbers.
>> > >
>> > > Point the spacemit,k1-pdma binding's #dma-cells description at the new
>> > > header.
>> > >
>> > > Signed-off-by: Guodong Xu <docular.xu at gmail.com>
>> > > ---
>> > >  .../devicetree/bindings/dma/spacemit,k1-pdma.yaml  |  4 +-
>> > >  include/dt-bindings/dma/spacemit,k1-pdma.h         | 56 ++++++++++++++++++++++
>> > >  2 files changed, 59 insertions(+), 1 deletion(-)
>> > >
>> > > diff --git a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
>> > > index ec06235baf5ca..0d4ac9849e27b 100644
>> > > --- a/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
>> > > +++ b/Documentation/devicetree/bindings/dma/spacemit,k1-pdma.yaml
>> > > @@ -35,7 +35,9 @@ properties:
>> > >    '#dma-cells':
>> > >      const: 1
>> > >      description:
>> > > -      The DMA request number for the peripheral device.
>> > > +      The single cell is the DMA request number for the peripheral device.
>> > > +      See <dt-bindings/dma/spacemit,k1-pdma.h> for the list of valid request
>> > > +      numbers.
>> > >
>> > >  required:
>> > >    - compatible
>> > > diff --git a/include/dt-bindings/dma/spacemit,k1-pdma.h b/include/dt-bindings/dma/spacemit,k1-pdma.h
>> >
>> > Why does this need to be in a binding when there is no use of this in
>> > the driver? May as well be a header, particularly if these are numbers
>>
>> Thanks for the review. You are correct that these are not referenced in the
>> driver. My change to k1-pdma.yaml should be dropped.
>>
>> > with a set meaning that are lifted from the TRM, rather than made up
>> > numbers to make a driver work. The former seems likely, given you're
>> > indexing from 3 not 0.
>>
>> Yes, it is defined in the K1 manual [1], see 9.4.3 DMA Connectivity &
>> Assignments
>>
>> Link: https://www.spacemit.com/community/document/info?lang=en&nodepath=hardware/key_stone/k1/k1_docs/k1_usermanual/9.Top_System.md [1]
>>
>> I will fix that in v2.
>
>Just in case I wasn't clear (and I think I wasn't), when I said "may as
>well be a header" I meant a header in arch/riscv/boot/dts/spacemit.

Oh, got it. Makes sense. I will move it to
arch/riscv/boot/dts/spacemit/k1-pdma.h

Note that I already sent v2 before reading this, please disregard v2.

I will send v3.

BR,
Guodong


From conor at kernel.org  Tue Jun  9 16:11:19 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 10 Jun 2026 00:11:19 +0100
Subject: [PATCH v2 1/2] dt-bindings: dmaengine: Add SpacemiT K1 PDMA
 request numbers
In-Reply-To: <20260609-b4-k1-pdma-req-macros-v2-1-5d5d7b997b54@gmail.com>
References: <20260609-b4-k1-pdma-req-macros-v2-0-5d5d7b997b54@gmail.com>
 <20260609-b4-k1-pdma-req-macros-v2-1-5d5d7b997b54@gmail.com>
Message-ID: <20260610-atrophy-gullible-938789978f76@spud>

On Tue, Jun 09, 2026 at 03:46:38PM -0400, Guodong Xu wrote:
> Add a dt-bindings header that gives symbolic names to the SpacemiT K1
> PDMA request lines of the non-secure peripherals. Device trees can use
> these K1_PDMA_* macros instead of magic numbers.
> 
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> ---
> V2: Drop the #dma-cells description change in spacemit,k1-pdma.yaml; the
>     request numbers are hardware-fixed and unused by the driver.

Worth noting that while this wasn't the change I wanted, I didn't
express myself clearly and Guodong is going to send a v3 after I
clarified:
https://lore.kernel.org/all/6ycdvhpgygnelzp3ot63xtzcnlvac7emngvj7tviiclst4a7km at kjq7oqvecnxx/

ta,
Conor.

> ---
>  include/dt-bindings/dma/spacemit,k1-pdma.h | 56 ++++++++++++++++++++++++++++++
>  1 file changed, 56 insertions(+)
> 
> diff --git a/include/dt-bindings/dma/spacemit,k1-pdma.h b/include/dt-bindings/dma/spacemit,k1-pdma.h
> new file mode 100644
> index 0000000000000..491976516550a
> --- /dev/null
> +++ b/include/dt-bindings/dma/spacemit,k1-pdma.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * This header provides DMA request number for non-secure peripherals of
> + * SpacemiT K1 PDMA.
> + *
> + * Copyright (c) 2026 Guodong Xu <docular.xu at gmail.com>
> + */
> +
> +#ifndef _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
> +#define _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_
> +
> +#define K1_PDMA_UART0_TX	3
> +#define K1_PDMA_UART0_RX	4
> +#define K1_PDMA_UART2_TX	5
> +#define K1_PDMA_UART2_RX	6
> +#define K1_PDMA_UART3_TX	7
> +#define K1_PDMA_UART3_RX	8
> +#define K1_PDMA_UART4_TX	9
> +#define K1_PDMA_UART4_RX	10
> +#define K1_PDMA_I2C0_TX		11
> +#define K1_PDMA_I2C0_RX		12
> +#define K1_PDMA_I2C1_TX		13
> +#define K1_PDMA_I2C1_RX		14
> +#define K1_PDMA_I2C2_TX		15
> +#define K1_PDMA_I2C2_RX		16
> +#define K1_PDMA_I2C4_TX		17
> +#define K1_PDMA_I2C4_RX		18
> +#define K1_PDMA_SPI3_TX		19
> +#define K1_PDMA_SPI3_RX		20
> +#define K1_PDMA_I2S0_TX		21
> +#define K1_PDMA_I2S0_RX		22
> +#define K1_PDMA_I2S1_TX		23
> +#define K1_PDMA_I2S1_RX		24
> +#define K1_PDMA_UART5_TX	25
> +#define K1_PDMA_UART5_RX	26
> +#define K1_PDMA_UART6_TX	27
> +#define K1_PDMA_UART6_RX	28
> +#define K1_PDMA_UART7_TX	29
> +#define K1_PDMA_UART7_RX	30
> +#define K1_PDMA_UART8_TX	31
> +#define K1_PDMA_UART8_RX	32
> +#define K1_PDMA_UART9_TX	33
> +#define K1_PDMA_UART9_RX	34
> +#define K1_PDMA_I2C5_TX		35
> +#define K1_PDMA_I2C5_RX		36
> +#define K1_PDMA_I2C6_TX		37
> +#define K1_PDMA_I2C6_RX		38
> +#define K1_PDMA_I2C7_TX		39
> +#define K1_PDMA_I2C7_RX		40
> +#define K1_PDMA_I2C8_TX		41
> +#define K1_PDMA_I2C8_RX		42
> +#define K1_PDMA_CAN0_RX		43
> +#define K1_PDMA_QSPI_RX		44
> +#define K1_PDMA_QSPI_TX		45
> +
> +#endif /* _DT_BINDINGS_DMA_SPACEMIT_K1_PDMA_H_ */
> 
> -- 
> 2.43.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260610/5b6b6a3f/attachment.sig>

From inochiama at gmail.com  Tue Jun  9 16:14:56 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Wed, 10 Jun 2026 07:14:56 +0800
Subject: [PATCH] riscv: dts: spacemit: k3-pico-itx: Fix non-functional
 ethernet TX timing
In-Reply-To: <aihYftGNcpUd4UUR@mcmanus>
References: <20260608182358.170489-1-kernel@rembrandt.dev>
 <aiemGajqcQeY9avz@inochi.infowork>
 <aihYftGNcpUd4UUR@mcmanus>
Message-ID: <aiid4Y6x6Dbbwszf@inochi.infowork>

On Tue, Jun 09, 2026 at 08:24:46PM +0200, Andrew Rembrandt wrote:
> On Tue, Jun 09, 2026 at 01:37:56 pm Inochi Amaoto wrote:
> > You should set tx-internal-delay-ps of the phy instead of
> > the controller. This is a phy in "rgmii-id" mode.
> Thanks for the review. I don't think that works on this board, but
> please let me know if I'm missing something.
> 
> The PHY is a Realtek RTL8211F. Its driver only toggles the chip's fixed
> ~2ns delay on/off from phy-mode, and per the datasheet that's a hardware
> limit, not a driver one -- the RTL8211F has no tunable delay, so a ps
> value on the PHY node has nothing to act on.
> 
> The only configurable delay element on K3 is the SoC RGMII delay line,
> and dwmac-spacemit programs it from tx-/rx-internal-delay-ps read off
> the controller node (spacemit_dwmac_probe()), so that is where the
> property has to live to take effect. This is the MAC "fine tuning ...
> values expected here are small" case described in
> Documentation/devicetree/bindings/net/ethernet-controller.yaml: the
> RTL8211F supplies the fixed ~2ns via rgmii-id and the MAC adds a 400ps
> trim on top. Ideally the PHY would own the delay, but as Andrew Lunn
> noted reviewing dwmac-meson8b, that requires the PHY to implement a
> configurable delay, which not all do.
> 
> The already-merged k1-bananapi-f3 does the same thing: eth1 combines
> phy-mode = "rgmii-id" with tx-internal-delay-ps = <250> on the
> controller node (via the K1 EMAC rather than dwmac, but the same DT
> pattern).
> 
> Would you be OK keeping it on the controller given the above? 

Yes, it is good for me.


> For v2 I can add an explicit rx-internal-delay-ps = <0> to match 
> the other SpacemiT boards (k1-bananapi-f3 included) and spell this
> reasoning out in the commit message.
> 

Do not do this, just leave the rx-internal-delay-ps untouched.

For this patch

Reviewed-by: Inochi Amaoto <inochiama at gmail.com>

Regards,
Inochi.


From nathan at kernel.org  Tue Jun  9 16:28:56 2026
From: nathan at kernel.org (Nathan Chancellor)
Date: Tue, 09 Jun 2026 16:28:56 -0700
Subject: [PATCH v2 00/16] Bump minimum version of LLVM for building the
 kernel to 17.0.1
In-Reply-To: <20260517-bump-minimum-supported-llvm-version-to-17-v2-0-b3b8cda46bdd@kernel.org>
References: <20260517-bump-minimum-supported-llvm-version-to-17-v2-0-b3b8cda46bdd@kernel.org>
Message-ID: <178104773630.2704789.17858317658280322569.b4-ty@b4>

On Sun, 17 May 2026 13:05:03 -1000, Nathan Chancellor wrote:
> Bump minimum version of LLVM for building the kernel to 17.0.1
> 
> The current minimum version of LLVM for building the kernel is 15.0.0.
> However, there are two deficiencies compared to GCC that were fixed in
> LLVM 17 that are starting to become more noticeable.
> 
> The first was a bug in LLVM's scope checker [1], where all labels in a
> function were validated as potential targets of an asm goto statement,
> even if they were not listed in the asm goto statement as targets. This
> becomes particularly problematic when the cleanup attribute is used, as
> 
> [...]

Applied to

  https://git.kernel.org/pub/scm/linux/kernel/git/kbuild/linux.git kbuild-next

Thanks!

[01/16] kbuild: Bump minimum version of LLVM for building the kernel to 17.0.1
        https://git.kernel.org/kbuild/c/ce3267a39a92b
[02/16] security/Kconfig.hardening: Remove tautological condition from CC_HAS_ZERO_CALL_USED_REGS
        https://git.kernel.org/kbuild/c/813fe686e90b4
[03/16] security/Kconfig.hardening: Remove tautological condition from FORTIFY_SOURCE
        https://git.kernel.org/kbuild/c/8ad2017578c99
[04/16] security/Kconfig.hardening: Remove tautological condition from CC_HAS_RANDSTRUCT
        https://git.kernel.org/kbuild/c/9331258bc129a
[05/16] arch/Kconfig: Remove tautological conditions from HAS_LTO_CLANG
        https://git.kernel.org/kbuild/c/2189cb1a80f06
[06/16] arch/Kconfig: Remove tautological condition from AUTOFDO_CLANG
        https://git.kernel.org/kbuild/c/de0bf1e138fcd
[07/16] ARM: Drop tautological ld.lld conditions from ARCH_MULTI_V4{,T}
        https://git.kernel.org/kbuild/c/48d229b6a48ae
[08/16] riscv: Remove tautological condition from selection of ARCH_SUPPORTS_CFI
        https://git.kernel.org/kbuild/c/62c4af8689511
[09/16] riscv: Drop tautological condition from TOOLCHAIN_NEEDS_OLD_ISA_SPEC
        https://git.kernel.org/kbuild/c/7e279976cf2a2
[10/16] scripts/Makefile.warn: Drop -Wformat handling for clang < 16
        https://git.kernel.org/kbuild/c/2a35c63c6bc42
[11/16] x86/build: Drop unnecessary '-ffreestanding' addition to KBUILD_CFLAGS
        https://git.kernel.org/kbuild/c/7b3281fcb43c5
[12/16] x86/module: Revert "Deal with GOT based stack cookie load on Clang < 17"
        https://git.kernel.org/kbuild/c/12b7bf92bddd4
[13/16] x86/entry/vdso32: Remove conditional omission of '.cfi_offset eflags'
        https://git.kernel.org/kbuild/c/4e7af20d0d104
[14/16] kbuild: Remove check for broken scoping with clang < 17 in CC_HAS_ASM_GOTO_OUTPUT
        https://git.kernel.org/kbuild/c/f3de78cb19d12
[15/16] compiler-clang.h: Remove __cleanup -Wunused-variable workaround
        https://git.kernel.org/kbuild/c/c69eaa687667e
[16/16] compiler-clang.h: Drop explicit version number from "all" diagnostic macro
        https://git.kernel.org/kbuild/c/c919893eabb43

Please look out for regression or issue reports or other follow up
comments, as they may result in the patch/series getting dropped or
reverted. Patches applied to an "unstable" branch are accepted pending
wider testing in -next and any post-commit review; they will generally
be moved to the main branch in a week if no issues are found.

Best regards,
-- 
Cheers,
Nathan




From lizhi2 at eswincomputing.com  Tue Jun  9 18:27:26 2026
From: lizhi2 at eswincomputing.com (lizhi2 at eswincomputing.com)
Date: Wed, 10 Jun 2026 09:27:26 +0800
Subject: [PATCH net-next v8 0/6] net: stmmac: eic7700: add eth1 variant support and update delay bindings
Message-ID: <20260610012727.848-1-lizhi2@eswincomputing.com>

From: Zhi Li <lizhi2 at eswincomputing.com>

v7 -> v8:
  - eth0-related fixes were moved into separate series [1], [2]:
    - All eth0-related fixes have been removed from this series to avoid mixing
      MAC variants and RX timing logic in a single review context.
    - Reference:
      [1]https://lore.kernel.org/lkml/20260602014528.2076-1-lizhi2 at eswincomputing.com/
      [2]https://lore.kernel.org/lkml/20260518021919.404-1-lizhi2 at eswincomputing.com/

  - Update cover letter and overall series scope description:
    - Replace previous wording "EIC7700 eth1 RX sampling timing fix"
      with a more accurate description:
        - Add eth1 MAC variant support.
        - Update RGMII delay binding model.
    - This reflects the structural nature of the series rather than a pure
      bug fix.

  -  Split DT bindings changes into two patches:
    - patch1:
        - Relax RGMII internal delay constraints.
        - Change rx/tx internal delay from enum-based model to range-based
          model.
        - Mark delay properties as optional.
    - patch2:
        - Introduce EIC7700 eth1 MAC variant compatible string
          "eswin,eic7700-qos-eth-clk-inversion".
        - Model silicon-specific RX clock inversion requirement via SoC
          variant instead of board-level properties.

    - Due to this restructuring:
        - Patch structure and commit messages have changed significantly
          compared to v7.
        - The previously received Acked-by from Conor Dooley is not
          carried forward because the binding patches were substantially
          reworked and split.

  - Split driver changes into two patches. No functional changes to eth1
    compared to v7:
    - patch 3:
        - Make rx-internal-delay-ps and tx-internal-delay-ps optional.
        - Remove mandatory DT property requirement in probe path.
        - Allow zero-delay default when properties are absent.
    - patch 4:
        - Add support for eth1 MAC variant using compatible-specific
          match data.
        - Introduce RX clock inversion handling for eth1 at runtime.
        - Apply speed-dependent configuration via fix_mac_speed()
          callback.

  - Note:
    - These patches (5/6 and 6/6) are included only to facilitate review
      of the overall Ethernet integration across bindings, driver, and
      device tree.
      A cleaned-up, upstream-ready DTS series will be submitted separately
      once all dependencies and final hardware integration are completed.

  - Link to v7:
    https://lore.kernel.org/lkml/20260427072353.1114-1-lizhi2 at eswincomputing.com/

v6 -> v7:
  - Address checkpatch.pl --strict warnings for DTS changes:
    - Split DT binding documentation and DTS board description into separate patches
    - Fix DTS style issues reported by checkpatch:
      - Reduce line length where applicable
      - Add required description for rgmii-rxid

  - DTS changes in this series are split into:
    - Patch 3/4: syscon binding update (documentation / reference only)
    - Patch 4/4: board DTS changes (architecture overview only)

    These patches (3/4 and 4/4) are provided to facilitate review of the overall
    Ethernet integration across binding, driver, and device tree, and are not
    intended as final upstream submission in their current form.

    A cleaned-up, upstream-ready DTS series will be submitted separately once
    all dependencies and final hardware integration are completed.

  - Note:
    - Clock-related bindings referenced in earlier revisions are now already merged
      into net-next, so dtbs_check warnings related to clock are no longer present
      and are not relevant to this revision.

  - No functional changes in the stmmac driver or binding semantics in this revision.

  - Link to v6:
    https://lore.kernel.org/lkml/20260423085501.760-1-lizhi2 at eswincomputing.com/

v5 -> v6:
  - Update DTS/DTSI descriptions to fix invalid phandle references reported by DTC:
    - Add missing GMAC provider nodes required for proper hardware description:
      - HSP power domain: GMAC nodes moved under this domain to reflect
        hardware power hierarchy.
      - Clock nodes: added to provide clk phandles referenced by GMAC.
      - Reset nodes: added to provide reset phandles referenced by GMAC.
      - Pinctrl nodes: defines pinctrl settings for GMAC signals
        (pinctrl_gpio106, pinctrl_gpio111).
    - Move GMAC nodes under the correct HSP power domain.
    - Ensure DTS builds without dtc errors and all phandle references
      (clk/reset/pinctrl/power-domain) are valid.
    - This update does not change runtime behavior; it only improves DTS
      consistency and resolves issues reported by dtc.

  - Note:
    - The patch 3/3 for DTS changes in this series provide an overview of the GMAC
      integration and its dependencies, as discussed previously:
      https://lore.kernel.org/lkml/64bf6b40-b947-4ffa-8d48-4d6341931327 at lunn.ch/

    - It is **not intended for upstream inclusion** in its current form,
      and is provided solely for architecture overview and integration
      context.

    - A fully cleaned and upstream-ready DTS series will be submitted
      separately once all related components (pinctrl, clock, power-domain,
      etc.) are finalized.

  - dtbs_check has been run on top of net-next for reference purposes.
    Remaining warnings are expected due to missing EIC7700 clock bindings[1]
    in net-next and do not reflect issues in the DTS design itself.

  - One remaining warning:
    - eswin,eic7700-clock

  - The clock binding has already been applied to upstream and is present
    in mainline, but not yet available in net-next.

  - The syscon binding is extended in this series to include the
    eswin,eic7700-syscfg compatible.

  - Any further refinement of the syscfg binding will be handled in
    separate patches if needed.

  - Dependencies:
    - [1]EIC7700 clock binding:
      https://lore.kernel.org/lkml/20260303080637.2100-1-dongxuyang at eswincomputing.com/
      (already applied to upstream)

  - Link to v5:
    https://lore.kernel.org/lkml/20260324073017.376-1-lizhi2 at eswincomputing.com/

v4 -> v5:
  - eswin,eic7700-eth.yaml:
    - Add Acked-by from Conor Dooley
    - No functional changes

  - Update dwmac-eic7700.c:
    - Disable clocks on the error path to fix a clock leak in
      eic7700_dwmac_init() when regmap_set_bits() fails
      (reported by Simon Horman <horms at kernel.org>)

  - Link to v4:
    https://lore.kernel.org/lkml/20260313075234.1567-1-lizhi2 at eswincomputing.com/

v3 -> v4:
  - Update eswin,eic7700-eth.yaml:
    - Improve commit message in dt-bindings patch to clarify the
      hardware difference of the eth1 MAC and why a new compatible
      string is required.
    - Move the newly added eswin,hsp-sp-csr item to the end of the list
      to avoid inserting entries in the middle of the binding schema.
    - Simplify the compatible schema by replacing the previous oneOf
      construct with an enum.

  - Update dwmac-eic7700.c:
    - Fix build issues.
    - Adjust code to match the updated binding definition.

  - Update DTS/DTSI descriptions:
    - Move SoC-level descriptions to the .dtsi file.
    - Keep board-specific configuration in the .dts file.

  - Link to v3:
    https://lore.kernel.org/lkml/20260303061525.846-1-lizhi2 at eswincomputing.com/

v2 -> v3:
  - Update eswin,eic7700-eth.yaml:
    - Extend rx-internal-delay-ps and tx-internal-delay-ps range
      from 0-2400 to 0-2540 to match the full 7-bit hardware delay
      field (127 * 20 ps).
    - Add "multipleOf: 20" constraint to reflect the 20 ps hardware
      step size.
    - Make rx-internal-delay-ps and tx-internal-delay-ps optional.
      A well-designed board should not require internal delay tuning.
    - Remove rx-internal-delay-ps and tx-internal-delay-ps from the
      example to avoid encouraging blind copy into board DTs.

  - Update dwmac-eic7700.c:
    - Treat rx-internal-delay-ps and tx-internal-delay-ps as optional
      DT properties.
    - Apply delay configuration only when properties are present.
    - Keep TX/RX delay registers cleared by default to ensure a
      deterministic state when no delay is specified.

  - Describe Ethernet configuration for the HiFive Premier P550 board:
    - Add GMAC controller nodes for the HiFive Premier P550 board
      to describe the on-board Ethernet configuration.

      The Ethernet controller depends on clock, reset, pinctrl
      and HSP subsystem providers which are currently under
      upstream review. These dependent nodes will be submitted
      separately once the corresponding drivers are merged.

      Due to these missing dependencies, dt-binding-check may
      report warnings or failures for this series.

  - No functional changes to RX clock inversion logic.

  - Link to v2:
    https://lore.kernel.org/lkml/20260209094628.886-1-lizhi2 at eswincomputing.com/

  - This series is based on the EIC7700 clock support series:
    https://lore.kernel.org/all/20260210095008.726-1-dongxuyang at eswincomputing.com/
    The clock series is currently under review.

v1 -> v2:
  - Update eswin,eic7700-eth.yaml:
    - Drop the vendor-specific properties eswin,rx-clk-invert and
      eswin,tx-clk-invert.
    - Introduce a distinct compatible string
      "eswin,eic7700-qos-eth-clk-inversion" to describe MAC instances that
      require internal RGMII clock inversion.
      This models the SoC-specific hardware difference directly via the
      compatible string and avoids per-board configuration properties.
    - Change rx-internal-delay-ps and tx-internal-delay-ps from enum to
      minimum/maximum to reflect the actual delay range (0-2400 ps)
    - Add reference to High-Speed Subsystem documentation in eswin,hsp-sp-csr
      description. The HSP CSR block is described in Chapter 10
      ("High-Speed Interface") of the EIC7700X SoC Technical Reference Manual,
      Part 4 (EIC7700X_SoC_Technical_Reference_Manual_Part4.pdf):
      https://github.com/eswincomputing/EIC7700X-SoC-Technical-Reference-Manual/releases

  - Update dwmac-eic7700.c:
    - Remove handling of eswin,rx-clk-invert and eswin,tx-clk-invert
      properties.
    - Select RX clock inversion based on the new
      "eswin,eic7700-qos-eth-clk-inversion" compatible string, using
      match data to apply the required configuration for affected MAC
      instances (eth1).

  - Link to v1:
    https://lore.kernel.org/lkml/20260109080601.1262-1-lizhi2 at eswincomputing.com/

Zhi Li (6):
  dt-bindings: ethernet: eswin: relax internal delay model to
    range-based constraints
  dt-bindings: ethernet: eswin: add EIC7700 eth1 RX clock inversion
    variant
  net: stmmac: eic7700: make RGMII delay properties optional
  net: stmmac: eic7700: add support for eth1 clock inversion variant
  dt-bindings: mfd: syscon: add ESWIN EIC7700 compatible
  riscv: dts: eswin: eic7700-hifive-premier-p550: enable Ethernet
    controller

 .../devicetree/bindings/mfd/syscon.yaml       |   2 +
 .../bindings/net/eswin,eic7700-eth.yaml       |  74 ++++--
 .../dts/eswin/eic7700-hifive-premier-p550.dts | 240 ++++++++++++++++++
 arch/riscv/boot/dts/eswin/eic7700.dtsi        | 105 ++++++++
 .../ethernet/stmicro/stmmac/dwmac-eic7700.c   | 113 ++++++++-
 5 files changed, 507 insertions(+), 27 deletions(-)

-- 
2.25.1



From lizhi2 at eswincomputing.com  Tue Jun  9 18:28:49 2026
From: lizhi2 at eswincomputing.com (lizhi2 at eswincomputing.com)
Date: Wed, 10 Jun 2026 09:28:49 +0800
Subject: [PATCH net-next v8 1/6] dt-bindings: ethernet: eswin: relax internal delay model to range-based constraints
In-Reply-To: <20260610012727.848-1-lizhi2@eswincomputing.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
Message-ID: <20260610012849.874-1-lizhi2@eswincomputing.com>

From: Zhi Li <lizhi2 at eswincomputing.com>

Relax internal delay constraints for EIC7700 Ethernet binding.

Replace fixed enumeration of rx-internal-delay-ps and tx-internal-delay-ps
with a range-based definition (0-2540 ps, 20 ps steps) to reflect actual
hardware capability.

Mark rx/tx internal delay properties as optional, as they are board-
specific tuning parameters rather than mandatory configuration.

Update the device tree example to align with the relaxed constraint model
and remove delay properties from the example to avoid implying they are
required.

No functional change to existing DT users.

Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
---
 .../bindings/net/eswin,eic7700-eth.yaml       | 25 ++++++++++---------
 1 file changed, 13 insertions(+), 12 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml b/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
index 65882ff79d8d..4e02fedae5c6 100644
--- a/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
+++ b/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
@@ -63,10 +63,14 @@ properties:
       - const: stmmaceth
 
   rx-internal-delay-ps:
-    enum: [0, 200, 600, 1200, 1600, 1800, 2000, 2200, 2400]
+    minimum: 0
+    maximum: 2540
+    multipleOf: 20
 
   tx-internal-delay-ps:
-    enum: [0, 200, 600, 1200, 1600, 1800, 2000, 2200, 2400]
+    minimum: 0
+    maximum: 2540
+    multipleOf: 20
 
   eswin,hsp-sp-csr:
     description:
@@ -105,8 +109,6 @@ required:
   - phy-mode
   - resets
   - reset-names
-  - rx-internal-delay-ps
-  - tx-internal-delay-ps
   - eswin,hsp-sp-csr
 
 unevaluatedProperties: false
@@ -116,23 +118,22 @@ examples:
     ethernet at 50400000 {
         compatible = "eswin,eic7700-qos-eth", "snps,dwmac-5.20";
         reg = <0x50400000 0x10000>;
-        clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
-                <&d0_clock 193>;
-        clock-names = "axi", "cfg", "stmmaceth", "tx";
         interrupt-parent = <&plic>;
         interrupts = <61>;
         interrupt-names = "macirq";
-        phy-mode = "rgmii-id";
-        phy-handle = <&phy0>;
+        clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
+                <&d0_clock 193>;
+        clock-names = "axi", "cfg", "stmmaceth", "tx";
         resets = <&reset 95>;
         reset-names = "stmmaceth";
-        rx-internal-delay-ps = <200>;
-        tx-internal-delay-ps = <200>;
         eswin,hsp-sp-csr = <&hsp_sp_csr 0x100 0x108 0x118 0x114 0x11c>;
-        snps,axi-config = <&stmmac_axi_setup>;
+        phy-handle = <&phy0>;
+        phy-mode = "rgmii-id";
         snps,aal;
         snps,fixed-burst;
         snps,tso;
+        snps,axi-config = <&stmmac_axi_setup>;
+
         stmmac_axi_setup: stmmac-axi-config {
             snps,blen = <0 0 0 0 16 8 4>;
             snps,rd_osr_lmt = <2>;
-- 
2.25.1



From lizhi2 at eswincomputing.com  Tue Jun  9 18:29:07 2026
From: lizhi2 at eswincomputing.com (lizhi2 at eswincomputing.com)
Date: Wed, 10 Jun 2026 09:29:07 +0800
Subject: [PATCH net-next v8 2/6] dt-bindings: ethernet: eswin: add EIC7700 eth1 RX clock inversion variant
In-Reply-To: <20260610012727.848-1-lizhi2@eswincomputing.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
Message-ID: <20260610012907.894-1-lizhi2@eswincomputing.com>

From: Zhi Li <lizhi2 at eswincomputing.com>

The EIC7700 SoC integrates two GMAC instances. The eth1 MAC exhibits
different RX clock sampling characteristics due to silicon-inherent
timing behavior.

The eth1 MAC has a fixed, non-configurable RX clock-to-data skew at the
MAC input in the order of 4-5 ns. This cannot be compensated solely by
the standard MAC internal delay configuration and PHY delay, and RX clock
inversion is required at 1000Mbps for correct sampling.

The eth1 TX path also includes a fixed silicon-inherent delay of
approximately 2 ns. This delay is always present and cannot be disabled.
It is therefore part of the effective transmit timing observed on the
wire.

For the eth1 variant, the valid tx-internal-delay-ps values include
this fixed delay component. Consequently, the effective range becomes
2000-4540 ps (approximately 2000 ps fixed delay plus 0-2540 ps
programmable delay).

Introduce a dedicated compatible string
"eswin,eic7700-qos-eth-clk-inversion" to represent the eth1 variant,
allowing the driver to apply RX clock inversion only when required by
hardware variant selection.

This keeps SoC-level differentiation without exposing silicon-fixed skew
as configurable device tree parameters.

Add per-compatible tx-internal-delay-ps constraints using a oneOf
schema partition:
- eswin,eic7700-qos-eth: 0-2540 ps
- eswin,eic7700-qos-eth-clk-inversion: 2000-4540 ps

No functional change for existing "eswin,eic7700-qos-eth" users.

Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
---
 .../bindings/net/eswin,eic7700-eth.yaml       | 55 +++++++++++++++++--
 1 file changed, 49 insertions(+), 6 deletions(-)

diff --git a/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml b/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
index 4e02fedae5c6..8cb7545c56e8 100644
--- a/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
+++ b/Documentation/devicetree/bindings/net/eswin,eic7700-eth.yaml
@@ -20,16 +20,38 @@ select:
       contains:
         enum:
           - eswin,eic7700-qos-eth
+          - eswin,eic7700-qos-eth-clk-inversion
   required:
     - compatible
 
 allOf:
   - $ref: snps,dwmac.yaml#
 
+oneOf:
+  - properties:
+      compatible:
+        contains:
+          const: eswin,eic7700-qos-eth
+      tx-internal-delay-ps:
+        minimum: 0
+        maximum: 2540
+        multipleOf: 20
+
+  - properties:
+      compatible:
+        contains:
+          const: eswin,eic7700-qos-eth-clk-inversion
+      tx-internal-delay-ps:
+        minimum: 2000
+        maximum: 4540
+        multipleOf: 20
+
 properties:
   compatible:
     items:
-      - const: eswin,eic7700-qos-eth
+      - enum:
+          - eswin,eic7700-qos-eth
+          - eswin,eic7700-qos-eth-clk-inversion
       - const: snps,dwmac-5.20
 
   reg:
@@ -67,11 +89,6 @@ properties:
     maximum: 2540
     multipleOf: 20
 
-  tx-internal-delay-ps:
-    minimum: 0
-    maximum: 2540
-    multipleOf: 20
-
   eswin,hsp-sp-csr:
     description:
       HSP CSR is to control and get status of different high-speed peripherals
@@ -140,3 +157,29 @@ examples:
             snps,wr_osr_lmt = <2>;
         };
     };
+
+    ethernet at 50410000 {
+        compatible = "eswin,eic7700-qos-eth-clk-inversion", "snps,dwmac-5.20";
+        reg = <0x50410000 0x10000>;
+        interrupt-parent = <&plic>;
+        interrupts = <70>;
+        interrupt-names = "macirq";
+        clocks = <&d0_clock 186>, <&d0_clock 171>, <&d0_clock 40>,
+                <&d0_clock 194>;
+        clock-names = "axi", "cfg", "stmmaceth", "tx";
+        resets = <&reset 94>;
+        reset-names = "stmmaceth";
+        eswin,hsp-sp-csr = <&hsp_sp_csr 0x200 0x208 0x218 0x214 0x21c>;
+        phy-handle = <&gmac1_phy0>;
+        phy-mode = "rgmii-id";
+        snps,aal;
+        snps,fixed-burst;
+        snps,tso;
+        snps,axi-config = <&stmmac_axi_setup_gmac1>;
+
+        stmmac_axi_setup_gmac1: stmmac-axi-config {
+            snps,blen = <0 0 0 0 16 8 4>;
+            snps,rd_osr_lmt = <2>;
+            snps,wr_osr_lmt = <2>;
+        };
+    };
-- 
2.25.1



From lizhi2 at eswincomputing.com  Tue Jun  9 18:29:37 2026
From: lizhi2 at eswincomputing.com (lizhi2 at eswincomputing.com)
Date: Wed, 10 Jun 2026 09:29:37 +0800
Subject: [PATCH net-next v8 3/6] net: stmmac: eic7700: make RGMII delay properties optional
In-Reply-To: <20260610012727.848-1-lizhi2@eswincomputing.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
Message-ID: <20260610012937.911-1-lizhi2@eswincomputing.com>

From: Zhi Li <lizhi2 at eswincomputing.com>

Make rx-internal-delay-ps and tx-internal-delay-ps optional in the
EIC7700 DWMAC driver.

The driver previously required both properties to be present and would
fail probe when they were missing. This restricts valid hardware
configurations where RGMII timing is instead provided by the PHY or
board design.

Update the driver to treat missing delay properties as zero delay,
allowing systems without explicit MAC-side delay tuning to operate
correctly.

This aligns the driver behavior with the updated device tree binding
and provides a safe default configuration when MAC-side delay
programming is not required.

Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
---
 drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
index 4ac979d874d6..ec99b597aeaf 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
@@ -165,9 +165,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
 		dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
 		dwc_priv->eth_clk_dly_param |=
 				 FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
-	} else {
-		return dev_err_probe(&pdev->dev, -EINVAL,
-			"missing required property rx-internal-delay-ps\n");
 	}
 
 	/* Read tx-internal-delay-ps and update tx_clk delay */
@@ -187,9 +184,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
 		dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
 		dwc_priv->eth_clk_dly_param |=
 				 FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
-	} else {
-		return dev_err_probe(&pdev->dev, -EINVAL,
-			"missing required property tx-internal-delay-ps\n");
 	}
 
 	dwc_priv->eic7700_hsp_regmap =
-- 
2.25.1



From lizhi2 at eswincomputing.com  Tue Jun  9 18:31:48 2026
From: lizhi2 at eswincomputing.com (lizhi2 at eswincomputing.com)
Date: Wed, 10 Jun 2026 09:31:48 +0800
Subject: [PATCH net-next v8 4/6] net: stmmac: eic7700: add support for eth1 clock inversion variant
In-Reply-To: <20260610012727.848-1-lizhi2@eswincomputing.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
Message-ID: <20260610013149.938-1-lizhi2@eswincomputing.com>

From: Zhi Li <lizhi2 at eswincomputing.com>

The eth1 MAC exhibits silicon-inherent RX and TX timing behavior that
differs from the eth0 implementation.

At 1000Mbps, RX sampling requires clock inversion due to a fixed MAC
input skew that cannot be compensated by standard RGMII delay settings.

The TX path includes a fixed ~2ns internal delay introduced by the MAC
silicon. This delay is always present and is already accounted for in
the device tree tx-internal-delay-ps property as part of the effective
output timing.

The tx-internal-delay-ps property describes the effective delay seen at
the MAC output. Since the hardware register controls only the
programmable portion of the delay, the driver subtracts the fixed
silicon-inherent component before programming the delay register.

Use compatible-specific match data to identify the eth1 variant and
apply RX clock inversion only at 1000Mbps.

The PHY interface mode is adjusted via phy_fix_phy_mode_for_mac_delays()
to avoid double-application of RGMII delays when MAC-side delays are
already present.

Link speed dependency means RX sampling configuration is applied in the
fix_mac_speed callback after negotiation.

No behavior changes for the existing eth0 controller.

Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
---
 .../ethernet/stmicro/stmmac/dwmac-eic7700.c   | 107 +++++++++++++++++-
 1 file changed, 101 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
index ec99b597aeaf..34a394a20570 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
@@ -29,10 +29,14 @@
 /*
  * TX/RX Clock Delay Bit Masks:
  * - TX Delay: bits [14:8] ? TX_CLK delay (unit: 0.02ns per bit)
+ * - TX Invert : bit  [15]
  * - RX Delay: bits [30:24] ? RX_CLK delay (unit: 0.02ns per bit)
+ * - RX Invert : bit  [31]
  */
 #define EIC7700_ETH_TX_ADJ_DELAY	GENMASK(14, 8)
 #define EIC7700_ETH_RX_ADJ_DELAY	GENMASK(30, 24)
+#define EIC7700_ETH_TX_INV_DELAY	BIT(15)
+#define EIC7700_ETH_RX_INV_DELAY	BIT(31)
 
 #define EIC7700_MAX_DELAY_STEPS		0x7F
 #define EIC7700_DELAY_STEP_PS		20
@@ -43,7 +47,14 @@ static const char * const eic7700_clk_names[] = {
 	"tx", "axi", "cfg",
 };
 
+struct eic7700_dwmac_data {
+	bool rgmii_rx_clk_invert;
+	bool has_internal_tx_delay;
+	u32 tx_clk_inherent_skew_ps;
+};
+
 struct eic7700_qos_priv {
+	struct device *dev;
 	struct plat_stmmacenet_data *plat_dat;
 	struct regmap *eic7700_hsp_regmap;
 	u32 eth_axi_lp_ctrl_offset;
@@ -54,6 +65,7 @@ struct eic7700_qos_priv {
 	u32 eth_clk_dly_param;
 	bool has_txd_offset;
 	bool has_rxd_offset;
+	bool eth_rx_clk_inv;
 };
 
 static int eic7700_clks_config(void *priv, bool enabled)
@@ -97,9 +109,6 @@ static int eic7700_dwmac_init(struct device *dev, void *priv)
 	if (dwc->has_rxd_offset)
 		regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_rxd_offset, 0);
 
-	regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_clk_offset,
-		     dwc->eth_clk_dly_param);
-
 	return 0;
 }
 
@@ -126,8 +135,38 @@ static int eic7700_dwmac_resume(struct device *dev, void *priv)
 	return ret;
 }
 
+/*
+ * eth1 requires RX clock inversion at 1000Mbps due to silicon-inherent
+ * RX sampling skew at MAC input.
+ *
+ * The configuration is updated in fix_mac_speed() because the required
+ * sampling behavior depends on the negotiated link speed.
+ */
+static void eic7700_dwmac_fix_speed(void *priv, phy_interface_t interface,
+				    int speed, unsigned int mode)
+{
+	struct eic7700_qos_priv *dwc = (struct eic7700_qos_priv *)priv;
+	u32 dly_param = dwc->eth_clk_dly_param;
+
+	switch (speed) {
+	case SPEED_1000:
+		if (dwc->eth_rx_clk_inv)
+			dly_param |= EIC7700_ETH_RX_INV_DELAY;
+		break;
+	case SPEED_100:
+	case SPEED_10:
+		break;
+	default:
+		dev_warn(dwc->dev, "unsupported speed %u\n", speed);
+		return;
+	}
+
+	regmap_write(dwc->eic7700_hsp_regmap, dwc->eth_clk_offset, dly_param);
+}
+
 static int eic7700_dwmac_probe(struct platform_device *pdev)
 {
+	const struct eic7700_dwmac_data *data;
 	struct plat_stmmacenet_data *plat_dat;
 	struct stmmac_resources stmmac_res;
 	struct eic7700_qos_priv *dwc_priv;
@@ -148,6 +187,30 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
 	if (!dwc_priv)
 		return -ENOMEM;
 
+	dwc_priv->dev = &pdev->dev;
+
+	data = device_get_match_data(&pdev->dev);
+	if (!data)
+		return dev_err_probe(&pdev->dev,
+				     -EINVAL, "no match data found\n");
+
+	dwc_priv->eth_rx_clk_inv = data->rgmii_rx_clk_invert;
+	/*
+	 * The MAC silicon unconditionally adds ~2 ns TX delay; prevent
+	 * the PHY from also adding TX delay to avoid doubling it.
+	 *
+	 * DT specifies rgmii-id (TX from MAC silicon, RX from PHY);
+	 * override to rgmii-rxid so the PHY only adds its RX delay.
+	 */
+	if (data->has_internal_tx_delay) {
+		plat_dat->phy_interface =
+				 phy_fix_phy_mode_for_mac_delays(plat_dat->phy_interface,
+								 true, false);
+		if (plat_dat->phy_interface == PHY_INTERFACE_MODE_NA)
+			return dev_err_probe(&pdev->dev, -EINVAL,
+				"phy interface mode is NA\n");
+	}
+
 	/* Read rx-internal-delay-ps and update rx_clk delay */
 	if (!of_property_read_u32(pdev->dev.of_node,
 				  "rx-internal-delay-ps", &delay_ps)) {
@@ -167,7 +230,13 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
 				 FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
 	}
 
-	/* Read tx-internal-delay-ps and update tx_clk delay */
+	/* Read tx-internal-delay-ps and update tx_clk delay.
+	 *
+	 * For eswin,eic7700-qos-eth-clk-inversion, the DT property describes
+	 * the effective TX delay at the MAC output, including the inherent
+	 * silicon delay. Subtract the fixed component to obtain the
+	 * programmable delay value.
+	 */
 	if (!of_property_read_u32(pdev->dev.of_node,
 				  "tx-internal-delay-ps", &delay_ps)) {
 		if (delay_ps % EIC7700_DELAY_STEP_PS)
@@ -175,9 +244,16 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
 				"tx delay must be multiple of %dps\n",
 				EIC7700_DELAY_STEP_PS);
 
+		if (delay_ps < data->tx_clk_inherent_skew_ps)
+			return dev_err_probe(&pdev->dev, -EINVAL,
+				"tx delay %ups below inherent skew %ups\n",
+				delay_ps, data->tx_clk_inherent_skew_ps);
+
+		delay_ps -= data->tx_clk_inherent_skew_ps;
+
 		if (delay_ps > EIC7700_MAX_DELAY_PS)
 			return dev_err_probe(&pdev->dev, -EINVAL,
-				"tx delay out of range\n");
+				"tx delay out of programmable range\n");
 
 		val = delay_ps / EIC7700_DELAY_STEP_PS;
 
@@ -254,12 +330,31 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
 	plat_dat->exit = eic7700_dwmac_exit;
 	plat_dat->suspend = eic7700_dwmac_suspend;
 	plat_dat->resume = eic7700_dwmac_resume;
+	plat_dat->fix_mac_speed = eic7700_dwmac_fix_speed;
 
 	return devm_stmmac_pltfr_probe(pdev, plat_dat, &stmmac_res);
 }
 
+static const struct eic7700_dwmac_data eic7700_dwmac_data = {
+	.rgmii_rx_clk_invert = false,
+	.has_internal_tx_delay = false,
+	.tx_clk_inherent_skew_ps = 0,
+};
+
+static const struct eic7700_dwmac_data eic7700_dwmac_data_clk_inversion = {
+	.rgmii_rx_clk_invert = true,
+	.has_internal_tx_delay = true,
+	.tx_clk_inherent_skew_ps = 2000,
+};
+
 static const struct of_device_id eic7700_dwmac_match[] = {
-	{ .compatible = "eswin,eic7700-qos-eth" },
+	{	.compatible = "eswin,eic7700-qos-eth",
+		.data = &eic7700_dwmac_data,
+	},
+	{
+		.compatible = "eswin,eic7700-qos-eth-clk-inversion",
+		.data = &eic7700_dwmac_data_clk_inversion,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(of, eic7700_dwmac_match);
-- 
2.25.1



From lizhi2 at eswincomputing.com  Tue Jun  9 18:32:03 2026
From: lizhi2 at eswincomputing.com (lizhi2 at eswincomputing.com)
Date: Wed, 10 Jun 2026 09:32:03 +0800
Subject: [PATCH net-next v8 5/6] dt-bindings: mfd: syscon: add ESWIN EIC7700 compatible
In-Reply-To: <20260610012727.848-1-lizhi2@eswincomputing.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
Message-ID: <20260610013203.955-1-lizhi2@eswincomputing.com>

From: Zhi Li <lizhi2 at eswincomputing.com>

Document ESWIN EIC7700 SoC compatible for syscon registers.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
---
 Documentation/devicetree/bindings/mfd/syscon.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
index e22867088063..7d3365601249 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
@@ -62,6 +62,7 @@ select:
           - cirrus,ep7209-syscon3
           - cnxt,cx92755-uc
           - econet,en751221-chip-scu
+          - eswin,eic7700-syscfg
           - freecom,fsg-cs2-system-controller
           - fsl,imx93-aonmix-ns-syscfg
           - fsl,imx93-wakeupmix-syscfg
@@ -175,6 +176,7 @@ properties:
               - cirrus,ep7209-syscon3
               - cnxt,cx92755-uc
               - econet,en751221-chip-scu
+              - eswin,eic7700-syscfg
               - freecom,fsg-cs2-system-controller
               - fsl,imx93-aonmix-ns-syscfg
               - fsl,imx93-wakeupmix-syscfg
-- 
2.25.1



From lizhi2 at eswincomputing.com  Tue Jun  9 18:32:23 2026
From: lizhi2 at eswincomputing.com (lizhi2 at eswincomputing.com)
Date: Wed, 10 Jun 2026 09:32:23 +0800
Subject: [PATCH net-next v8 6/6] riscv: dts: eswin: eic7700-hifive-premier-p550: enable Ethernet controller
In-Reply-To: <20260610012727.848-1-lizhi2@eswincomputing.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
Message-ID: <20260610013223.972-1-lizhi2@eswincomputing.com>

From: Zhi Li <lizhi2 at eswincomputing.com>

Enable the on-board Gigabit Ethernet controller on the
HiFive Premier P550 development board.

Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
---
 .../dts/eswin/eic7700-hifive-premier-p550.dts | 240 ++++++++++++++++++
 arch/riscv/boot/dts/eswin/eic7700.dtsi        | 105 ++++++++
 2 files changed, 345 insertions(+)

diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
index 131ed1fc6b2e..edd91b04e251 100644
--- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
+++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
@@ -13,11 +13,251 @@ / {
 
 	aliases {
 		serial0 = &uart0;
+		ethernet0 = &gmac0;
+		ethernet1 = &gmac1;
 	};
 
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	vcc_1v8: vcc1v8 {
+		 compatible = "regulator-fixed";
+		 regulator-name = "vcc1v8";
+		 regulator-always-on;
+		 regulator-boot-on;
+		 regulator-min-microvolt = <1800000>;
+		 regulator-max-microvolt = <1800000>;
+	 };
+};
+
+&xtal24m {
+	clock-frequency = <24000000>;
+	clock-output-names = "xtal24m";
+};
+
+&pinctrl {
+	status = "okay";
+	vrgmii-supply = <&vcc_1v8>;
+
+	pinctrl_gpio0: gpio0-grp {
+		gpio0-pins {
+			pins = "gpio0";
+			function = "gpio";
+			input-enable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio5: gpio5-grp {
+		gpio5-pins {
+			pins = "gpio5";
+			function = "gpio";
+			input-enable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio11: gpio11-grp {
+		gpio11-pins {
+			pins = "gpio11";
+			function = "gpio";
+			input-enable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio14: gpio14-grp {
+		gpio14-pins {
+			pins = "mode_set1";
+			function = "gpio";
+			input-disable;
+			bias-pull-up;
+		};
+	};
+
+	pinctrl_gpio15: gpio15-grp {
+		gpio15-pins {
+			pins = "mode_set2";
+			function = "gpio";
+			input-enable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio28: gpio28-grp {
+		gpio28-pins {
+			pins = "gpio28";
+			function = "gpio";
+			input-enable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio43: gpio43-grp {
+		gpio43-pins {
+			pins = "usb1_pwren";
+			function = "gpio";
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio71: gpio71-grp {
+		gpio71-pins {
+			pins = "mipi_csi0_xhs";
+			function = "gpio";
+			input-disable;
+			bias-pull-up;
+		};
+	};
+
+	pinctrl_gpio74: gpio74-grp {
+		gpio74-pins {
+			pins = "mipi_csi1_xhs";
+			function = "gpio";
+			input-disable;
+			bias-pull-up;
+		};
+	};
+
+	pinctrl_gpio76: gpio76-grp {
+		gpio76-pins {
+			pins = "mipi_csi2_xvs";
+			function = "gpio";
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio77: gpio77-grp {
+		gpio77-pins {
+			pins = "mipi_csi2_xhs";
+			function = "gpio";
+			input-disable;
+			bias-pull-up;
+		};
+	};
+
+	pinctrl_gpio79: gpio79-grp {
+		gpio79-pins {
+			pins = "mipi_csi3_xvs";
+			function = "gpio";
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio80: gpio80-grp {
+		gpio80-pins {
+			pins = "mipi_csi3_xhs";
+			function = "gpio";
+			input-disable;
+			bias-pull-up;
+		};
+	};
+
+	pinctrl_gpio82: gpio82-grp {
+		gpio82-pins {
+			pins = "mipi_csi4_xvs";
+			function = "gpio";
+			input-disable;
+			bias-pull-up;
+		};
+	};
+
+	pinctrl_gpio84: gpio84-grp {
+		gpio84-pins {
+			pins = "mipi_csi4_mclk";
+			function = "gpio";
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio85: gpio85-grp {
+		gpio85-pins {
+			pins = "mipi_csi5_xvs";
+			function = "gpio";
+			input-disable;
+			bias-pull-up;
+		};
+	};
+
+	pinctrl_gpio94: gpio94-grp {
+		gpio94-pins {
+			pins = "s_mode";
+			function = "gpio";
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio106: gpio106-grp {
+		gpio106-pins {
+			pins = "gpio106";
+			function = "gpio";
+			input-disable;
+			bias-disable;
+		};
+	};
+
+	pinctrl_gpio111: gpio111-grp {
+		gpio111-pins {
+			pins = "gpio111";
+			function = "gpio";
+			input-disable;
+			bias-disable;
+		};
+	};
+};
+
+&gmac0 {
+	phy-handle = <&gmac0_phy0>;
+	phy-mode = "rgmii-id";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio106>;
+	rx-internal-delay-ps = <20>;
+	tx-internal-delay-ps = <100>;
+	status = "okay";
+};
+
+&gmac0_mdio {
+	gmac0_phy0: ethernet-phy at 0 {
+		compatible = "ethernet-phy-id001c.c916";
+		reg = <0>;
+		reset-gpios = <&gpioD 10 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <80000>;
+	};
+};
+
+&gmac1 {
+	phy-handle = <&gmac1_phy0>;
+	/*
+	 * The MAC silicon unconditionally introduces an ~2 ns TX clock-to-data
+	 * skew (MAC-side TX internal delay). The PHY provides the standard
+	 * ~2 ns RX internal delay. The driver additionally inverts the RX
+	 * clock at 1000 Mb/s to correct a silicon RX sampling timing issue.
+	 * phy-mode is "rgmii-id": TX delay from the MAC silicon, RX delay
+	 * from the PHY.
+	 */
+	phy-mode = "rgmii-id";
+	pinctrl-names = "default";
+	pinctrl-0 = <&pinctrl_gpio111>;
+	rx-internal-delay-ps = <200>;
+	tx-internal-delay-ps = <2200>;
+	status = "okay";
+};
+
+&gmac1_mdio {
+	gmac1_phy0: ethernet-phy at 0 {
+		compatible = "ethernet-phy-id001c.c916";
+		reg = <0>;
+		reset-gpios = <&gpioD 15 GPIO_ACTIVE_LOW>;
+		reset-assert-us = <10000>;
+		reset-deassert-us = <80000>;
+	};
 };
 
 &uart0 {
diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
index c3ed93008bca..c77bc8b1b7bc 100644
--- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
+++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
@@ -5,6 +5,9 @@
 
 /dts-v1/;
 
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/reset/eswin,eic7700-reset.h>
+
 / {
 	#address-cells = <2>;
 	#size-cells = <2>;
@@ -202,6 +205,11 @@ pmu {
 				<0x00000000 0x0000000f 0xfffffffc 0x000000ff 0x00000078>;
 	};
 
+	xtal24m: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		ranges;
@@ -245,6 +253,85 @@ plic: interrupt-controller at c000000 {
 			#interrupt-cells = <1>;
 		};
 
+		hsp_power_domain: bus at 50400000 {
+			compatible = "simple-pm-bus";
+			ranges;
+			clocks = <&clk 171>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			hsp_sp_csr: hsp-sp-top-csr at 50440000 {
+				compatible = "eswin,eic7700-syscfg", "syscon";
+				reg = <0x0 0x50440000 0x0 0x2000>;
+			};
+
+			gmac0: ethernet at 50400000 {
+				compatible = "eswin,eic7700-qos-eth",
+					     "snps,dwmac-5.20";
+				reg = <0x0 0x50400000 0x0 0x10000>;
+				interrupts = <61>;
+				interrupt-names = "macirq";
+				clocks = <&clk 186>,
+					 <&clk 171>,
+					 <&clk 40>,
+					 <&clk 193>;
+				clock-names = "axi", "cfg", "stmmaceth", "tx";
+				resets = <&reset EIC7700_RESET_HSP_ETH0_ARST>;
+				reset-names = "stmmaceth";
+				eswin,hsp-sp-csr = <&hsp_sp_csr 0x100 0x108 0x118 0x114 0x11c>;
+				snps,aal;
+				snps,fixed-burst;
+				snps,tso;
+				snps,axi-config = <&stmmac_axi_setup_gmac0>;
+				status = "disabled";
+
+				gmac0_mdio: mdio {
+					compatible = "snps,dwmac-mdio";
+					#address-cells = <1>;
+					#size-cells = <0>;
+				};
+
+				stmmac_axi_setup_gmac0: stmmac-axi-config {
+					snps,blen = <0 0 0 0 16 8 4>;
+					snps,rd_osr_lmt = <2>;
+					snps,wr_osr_lmt = <2>;
+				};
+			};
+
+			gmac1: ethernet at 50410000 {
+				compatible = "eswin,eic7700-qos-eth-clk-inversion",
+					     "snps,dwmac-5.20";
+				reg = <0x0 0x50410000 0x0 0x10000>;
+				interrupts = <70>;
+				interrupt-names = "macirq";
+				clocks = <&clk 186>,
+					 <&clk 171>,
+					 <&clk 40>,
+					 <&clk 194>;
+				clock-names = "axi", "cfg", "stmmaceth", "tx";
+				resets = <&reset EIC7700_RESET_HSP_ETH1_ARST>;
+				reset-names = "stmmaceth";
+				eswin,hsp-sp-csr = <&hsp_sp_csr 0x200 0x208 0x218 0x214 0x21c>;
+				snps,aal;
+				snps,fixed-burst;
+				snps,tso;
+				snps,axi-config = <&stmmac_axi_setup_gmac1>;
+				status = "disabled";
+
+				gmac1_mdio: mdio {
+					compatible = "snps,dwmac-mdio";
+					#address-cells = <1>;
+					#size-cells = <0>;
+				};
+
+				stmmac_axi_setup_gmac1: stmmac-axi-config {
+					snps,blen = <0 0 0 0 16 8 4>;
+					snps,rd_osr_lmt = <2>;
+					snps,wr_osr_lmt = <2>;
+				};
+			};
+		};
+
 		uart0: serial at 50900000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x0 0x50900000 0x0 0x10000>;
@@ -341,5 +428,23 @@ gpioD: gpio-port at 3 {
 				#gpio-cells = <2>;
 			};
 		};
+
+		pinctrl: pinctrl at 51600080 {
+			compatible = "eswin,eic7700-pinctrl";
+			reg = <0x0 0x51600080 0x0 0x1fff80>;
+		};
+
+		clk: clock-controller at 51828000 {
+			compatible = "eswin,eic7700-clock";
+			reg = <0x0 0x51828000 0x0 0x300>;
+			clocks = <&xtal24m>;
+			#clock-cells = <1>;
+		};
+
+		reset: reset-controller at 51828300 {
+			compatible = "eswin,eic7700-reset";
+			reg = <0x0 0x51828300 0x0 0x200>;
+			#reset-cells = <1>;
+		};
 	};
 };
-- 
2.25.1



From cuiyunhui at bytedance.com  Tue Jun  9 19:03:01 2026
From: cuiyunhui at bytedance.com (yunhui cui)
Date: Wed, 10 Jun 2026 10:03:01 +0800
Subject: [External] Re: [PATCH v3 1/3] dt-bindings: riscv: clarify Svadu
 boot-time behavior
In-Reply-To: <20260609-washboard-fantasize-ddf0a9752df8@spud>
References: <20260609130021.99899-1-cuiyunhui@bytedance.com>
 <20260609130021.99899-2-cuiyunhui@bytedance.com> <20260609-washboard-fantasize-ddf0a9752df8@spud>
Message-ID: <CAEEQ3w=C_z8awtevLhceTgqLW79ONzKTm5MRJeoSTLB9q_CeiQ@mail.gmail.com>

Hi Conor,

On Wed, Jun 10, 2026 at 12:09?AM Conor Dooley <conor at kernel.org> wrote:
>
> On Tue, Jun 09, 2026 at 09:00:18PM +0800, Yunhui Cui wrote:
> > Clarify that systems which advertise only Svadu have hardware PTE A/D
> > updating enabled at boot, while systems advertising both Svade and Svadu
> > must enable Svadu explicitly with SBI FWFT.
> >
> > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> > Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
> > ---
> >  Documentation/devicetree/bindings/riscv/extensions.yaml | 6 +++---
> >  1 file changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
> > index 2b0a8a93bb214..b09888e9988de 100644
> > --- a/Documentation/devicetree/bindings/riscv/extensions.yaml
> > +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
> > @@ -294,10 +294,10 @@ properties:
> >                 of the PTE A/D bits or page faults when they need updated.
> >              2) Only Svade present in DT => Supervisor must assume Svade to be
> >                 always enabled.
> > -            3) Only Svadu present in DT => Supervisor must assume Svadu to be
> > -               always enabled.
> > +            3) Only Svadu present in DT => Supervisor must assume Svadu is
> > +               enabled at boot.
>
> Commit message is missing an explanation of why this behaviour change is
> not problematic. Although, to be honest, I am not sure what the changed text
> actually means. If only Svadu is present, then the hardware doesn't support
> Svade, and therefore Svadu would never be anything other than enabled so
> changing the wording to specify "at boot" seems less clear?

The "enabled at boot" wording came from Andrew's feedback on the previous
version: "always" is a sensitive term here because ADUE is writable when
Svadu is implemented, and ADUE=0 behaves as though Svade were implemented.

Would this wording work?

3) Only Svadu present in DT => Supervisor must assume hardware PTE A/D
    updating is enabled by default.

>
> >              4) Both Svade and Svadu present in DT => Supervisor must assume
> > -               Svadu turned-off at boot time. To use Svadu, supervisor must
> > +               Svadu is disabled at boot time. To use Svadu, supervisor must
>
> This change doesn't actually do anything, "turned-off" and "disabled"
> are the same thing - although the latter is more desirable wording I
> think. I have no problems with this portion of the patch.
>
> >                 explicitly enable it using the SBI FWFT extension.
> >
> >          - const: svadu
> > --
> > 2.39.5
> >

Thanks,
Yunhui


From fustini at kernel.org  Tue Jun  9 21:33:22 2026
From: fustini at kernel.org (Drew Fustini)
Date: Tue, 9 Jun 2026 21:33:22 -0700
Subject: [PATCH 02/12] clk: thead: th1520-ap: add support for MISC subsys
 clocks
In-Reply-To: <aievi0s-3SO8hV6a@thelio>
References: <20260507081710.4090814-1-zhengxingda@iscas.ac.cn>
 <20260507081710.4090814-3-zhengxingda@iscas.ac.cn>
 <aier9XppLeCkJydw@thelio>
 <93b867c1b7f5526cc25cb04f838432cd752f5981.camel@icenowy.me>
 <aievi0s-3SO8hV6a@thelio>
Message-ID: <aijpEqzJ7fM7rGMH@thelio>

On Mon, Jun 08, 2026 at 11:15:39PM -0700, Drew Fustini wrote:
> On Tue, Jun 09, 2026 at 02:01:43PM +0800, Icenowy Zheng wrote:
> > ? 2026-06-08?? 23:00 -0700?Drew Fustini???
> > > On Thu, May 07, 2026 at 04:17:00PM +0800, Icenowy Zheng wrote:
> > > > The TH1520 SoC contains a MISC_SUBSYS clock controller, which
> > > > allows
> > > > controlling of USB related clocks and MMC/SD controller AHB bus
> > > > clocks.
> > > > 
> > > > Add support for this clock controller, in order to enable USB
> > > > support.
> > > > 
> > > > Signed-off-by: Icenowy Zheng <zhengxingda at iscas.ac.cn>
> > > > ---
> > > > ?drivers/clk/thead/clk-th1520-ap.c | 64
> > > > +++++++++++++++++++++++++++++++
> > > > ?1 file changed, 64 insertions(+)
> > > > 
> > > > diff --git a/drivers/clk/thead/clk-th1520-ap.c
> > > > b/drivers/clk/thead/clk-th1520-ap.c
> > > > index 3a6847f1c950f..24f785f0b329a 100644
> > > > --- a/drivers/clk/thead/clk-th1520-ap.c
> > > > +++ b/drivers/clk/thead/clk-th1520-ap.c
> > > [...]
> > > > @@ -1609,6 +1663,12 @@ static int th1520_clk_probe(struct
> > > > platform_device *pdev)
> > > > ?			return ret;
> > > > ?	}
> > > > ?
> > > > +	if (plat_data == &th1520_ap_platdata) {
> > > > +		ret = devm_clk_hw_register(dev,
> > > > &usb_suspend_div_clk.hw);
> > > > +		if (ret)
> > > > +			return ret;
> > > > +	}
> > > 
> > > Should usb_suspend_div_clk.hw instead be registered under
> > > 'if (plat_data == &th1520_ap_platdata)'?
> > 
> > Do you mean misc_platdata?
> > 
> > Yes, this is an copy-n-paste error that deserves a fix.
> 
> Hah, yes, I also had a typo :)

Assuming that gets fixed in the next rev:

Reviewed-by: Drew Fusini <fustini at kernel.org>


From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Wed Jun 10 01:22:13 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Wed, 10 Jun 2026 10:22:13 +0200
Subject: [PATCH v8 1/3] dt-bindings: timer: mips,p8700-gcru
In-Reply-To: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>
References: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>
Message-ID: <20260610-riscv-time-mmio-v8-1-a865206675c6@htecgroup.com>

From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>

Add dt-bindings for the GCR.U memory mapped timer device for RISC-V
platforms. The GCR.U memory region contains shadow copies of the RISC-V
mtime register and the hrtime Global Configuration Register.

Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../devicetree/bindings/timer/mips,p8700-gcru.yaml | 38 ++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/Documentation/devicetree/bindings/timer/mips,p8700-gcru.yaml b/Documentation/devicetree/bindings/timer/mips,p8700-gcru.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..3498255762cce6b3f491292d340d9639bb573e6d
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/mips,p8700-gcru.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/mips,p8700-gcru.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GCR.U timer device for the MIPS P8700 platform
+
+maintainers:
+  - Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
+
+description:
+  The GCR.U memory region contains memory mapped shadow copies of
+  mtime and hrtime Global Configuration Registers,
+  which software can choose to make accessible from user mode.
+
+properties:
+  compatible:
+    const: mips,p8700-gcru
+
+  reg:
+    items:
+      - description: Read-only shadow copy of the RISC-V mtime register.
+      - description: Read-only shadow copy of the P8700 high resolution timer register.
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    timer at 1617f000 {
+        compatible = "mips,p8700-gcru";
+        reg = <0x1617f050 0x8>,
+              <0x1617f090 0x8>;
+    };

-- 
2.43.0




From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Wed Jun 10 01:22:15 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Wed, 10 Jun 2026 10:22:15 +0200
Subject: [PATCH v8 3/3] riscv: clocksource: Add p8700-gcru driver
In-Reply-To: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>
References: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>
Message-ID: <20260610-riscv-time-mmio-v8-3-a865206675c6@htecgroup.com>

From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>

Add a clocksource driver for the P8700 GCRU.

Initialization uses helper functions
provided by clocksource/mmio.c and timer-of.c.

Since the GCRU does not support any kind of interrupts,
the default RISC-V clockevent implementation should suffice.

Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
---
 drivers/clocksource/Kconfig       |  9 ++++++++
 drivers/clocksource/Makefile      |  1 +
 drivers/clocksource/timer-p8700.c | 47 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index ffcd23668763fe7707a4e917bf240caadbb09a8c..a775a301f3f08ca97699e46aaf3ccfaf99734e6b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -672,6 +672,15 @@ config CLINT_TIMER
 	  This option enables the CLINT timer for RISC-V systems.  The CLINT
 	  driver is usually used for NoMMU RISC-V systems.
 
+config P8700_TIMER
+	bool "MIPS P8700 timer driver"
+	depends on GENERIC_SCHED_CLOCK && RISCV && RISCV_SBI && 64BIT
+	select CLKSRC_MMIO
+	select TIMER_PROBE
+	select TIMER_OF
+	help
+	  Enables support for MIPS P8700 timer driver.
+
 config CSKY_MP_TIMER
 	bool "SMP Timer for the C-SKY platform" if COMPILE_TEST
 	depends on CSKY
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index ec4452ee958f1a814c708aeba6412bea61d24892..fae9a58d6c8663a7c857b9ab7fdae05782b3551c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -95,3 +95,4 @@ obj-$(CONFIG_CLKSRC_LOONGSON1_PWM)	+= timer-loongson1-pwm.o
 obj-$(CONFIG_EP93XX_TIMER)		+= timer-ep93xx.o
 obj-$(CONFIG_RALINK_TIMER)		+= timer-ralink.o
 obj-$(CONFIG_NXP_STM_TIMER)		+= timer-nxp-stm.o
+obj-$(CONFIG_P8700_TIMER)		+= timer-p8700.o
diff --git a/drivers/clocksource/timer-p8700.c b/drivers/clocksource/timer-p8700.c
new file mode 100644
index 0000000000000000000000000000000000000000..dd20b4e72fcdd77a6b33775f286d0945c2a2b659
--- /dev/null
+++ b/drivers/clocksource/timer-p8700.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 MIPS.
+ */
+
+#include <linux/sched_clock.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+
+#include "timer-of.h"
+
+static struct timer_of gcru_of = { .flags = TIMER_OF_BASE };
+static u64 __iomem *p8700_time_val __ro_after_init;
+
+static u64 notrace p8700_timer_sched_read(void)
+{
+	return (u64)readq_relaxed(p8700_time_val);
+}
+
+static int __init p8700_timer_init(struct device_node *node)
+{
+	int error = 0;
+
+	error = timer_of_init(node, &gcru_of);
+	if (error)
+		return error;
+
+	p8700_time_val = timer_of_base(&gcru_of);
+	/* Now init the mmio timer with the address we got from DT */
+	error = clocksource_mmio_init(p8700_time_val, "mips,p8700-gcru",
+				      riscv_timebase, 450, 64,
+				      clocksource_mmio_readq_up);
+	if (error) {
+		timer_of_cleanup(&gcru_of);
+		return error;
+	}
+
+	/* Sched clock */
+	sched_clock_register(p8700_timer_sched_read, 64, riscv_timebase);
+
+	return error;
+}
+
+TIMER_OF_DECLARE(p8700_timer, "mips,p8700-gcru", p8700_timer_init);

-- 
2.43.0




From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Wed Jun 10 01:22:14 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Wed, 10 Jun 2026 10:22:14 +0200
Subject: [PATCH v8 2/3] riscv: clocksource: Add readq options to
 clocksource mmio
In-Reply-To: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>
References: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>
Message-ID: <20260610-riscv-time-mmio-v8-2-a865206675c6@htecgroup.com>

From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>

Add read functions for 64-bit register size to the generic
mmio clocksource, covering both up and down counters.

Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
---
 drivers/clocksource/mmio.c  | 14 ++++++++++++++
 include/linux/clocksource.h |  4 ++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c
index 9de75153183124cc8997c6ab61d0c01d9b2637bc..f3b6f7e93ffbf0ed68e56c58c3d9f711d2193caa 100644
--- a/drivers/clocksource/mmio.c
+++ b/drivers/clocksource/mmio.c
@@ -17,6 +17,20 @@ static inline struct clocksource_mmio *to_mmio_clksrc(struct clocksource *c)
 	return container_of(c, struct clocksource_mmio, clksrc);
 }
 
+#if defined(CONFIG_64BIT) && defined(readq_relaxed)
+
+u64 clocksource_mmio_readq_up(struct clocksource *c)
+{
+	return (u64)readq_relaxed(to_mmio_clksrc(c)->reg);
+}
+
+u64 clocksource_mmio_readq_down(struct clocksource *c)
+{
+	return ~(u64)readq_relaxed(to_mmio_clksrc(c)->reg) & c->mask;
+}
+
+#endif
+
 u64 clocksource_mmio_readl_up(struct clocksource *c)
 {
 	return (u64)readl_relaxed(to_mmio_clksrc(c)->reg);
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 65b7c41471c390463770c2da13694e58e83b84ea..39e0df5a0ab52cbb7016b53a4d7500f2697e2797 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -276,6 +276,10 @@ static inline void clocksource_arch_init(struct clocksource *cs) { }
 
 extern int timekeeping_notify(struct clocksource *clock);
 
+#if defined(CONFIG_64BIT) && defined(readq_relaxed)
+extern u64 clocksource_mmio_readq_up(struct clocksource *c);
+extern u64 clocksource_mmio_readq_down(struct clocksource *c);
+#endif
 extern u64 clocksource_mmio_readl_up(struct clocksource *);
 extern u64 clocksource_mmio_readl_down(struct clocksource *);
 extern u64 clocksource_mmio_readw_up(struct clocksource *);

-- 
2.43.0




From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Wed Jun 10 01:22:12 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Wed, 10 Jun 2026 10:22:12 +0200
Subject: [PATCH v8 0/3] riscv: Use GCR.U timer device as clocksource
Message-ID: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>

This series adds bindings for the GCR.U timer device and corresponding
driver support. Accessing the memory mapped shadow of the mtime register
in the GCR.U region should be faster
than trapping to M mode each time the timer needs to be read.
The timer device does not implement any interrupts, therefore the
timer-riscv clockevent implementation should suffice.

We tested the patchset both on QEMU and the Boston board with the P8700 bitfile:
- v7, v8 testing:
  - Coremark and timer kselftests on QEMU emulating an 8 core CPU
  - Coremark and timer kselftests on the Boston board with a single core CPU.

Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
Signed-off-by: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Signed-off-by: Chao-ying Fu <cfu at mips.com>
---
Changes in v8:
- Make the 64 bit timer mmio reads and the main timer driver depend on CONFIG_64BIT
- Add timer_of_cleanup to the driver code
- Link to v7: https://lore.kernel.org/r/20260311-riscv-time-mmio-v7-0-016845a0f808 at htecgroup.com

Changes in v7:
- Replace the previous implementation with a new timer driver for mips,p8700-gcru
- Add a patch for 64bit reads for timer mmio
- Link to v6: https://lore.kernel.org/r/20250806-riscv-time-mmio-v6-0-2df0e8219998 at htecgroup.com

Changes in v6:
- Rename mti,gcru to mips,p8700-gcru
- Link to v5: https://lore.kernel.org/r/20250711-riscv-time-mmio-v5-0-9ed1f825ad5e at htecgroup.com

Changes in v5:
- Fixed build issues on 32-bit RISC-V and sparse warnings
- Remove clint_time_val and clint.h, replace with riscv_time_val
- Depend on RISCV_TIMER in Kconfig

Changes in v4:
- Remove "select" from mti,gcru.yaml.
- Refactor the driver to use function pointers instead of static keys.

Previous versions:
v1: https://lore.kernel.org/lkml/20241227150056.191794-1-arikalo at gmail.com/#t
v2: https://lore.kernel.org/linux-riscv/20250409143816.15802-1-aleksa.paunovic at htecgroup.com/
v3: https://lore.kernel.org/linux-riscv/DU0PR09MB61968695A2A3146EE83B7708F6BA2 at DU0PR09MB6196.eurprd09.prod.outlook.com/
v4: https://lore.kernel.org/r/20250514-riscv-time-mmio-v4-0-cb0cf2922d66 at htecgroup.com
v5: https://lore.kernel.org/r/20250711-riscv-time-mmio-v5-0-9ed1f825ad5e at htecgroup.com
v6: https://lore.kernel.org/r/20250806-riscv-time-mmio-v6-0-2df0e8219998 at htecgroup.com
v7: https://lore.kernel.org/r/20260311-riscv-time-mmio-v7-0-016845a0f808 at htecgroup.com

---
Aleksa Paunovic (3):
      dt-bindings: timer: mips,p8700-gcru
      riscv: clocksource: Add readq options to clocksource mmio
      riscv: clocksource: Add p8700-gcru driver

 .../devicetree/bindings/timer/mips,p8700-gcru.yaml | 38 +++++++++++++++++
 drivers/clocksource/Kconfig                        |  9 +++++
 drivers/clocksource/Makefile                       |  1 +
 drivers/clocksource/mmio.c                         | 14 +++++++
 drivers/clocksource/timer-p8700.c                  | 47 ++++++++++++++++++++++
 include/linux/clocksource.h                        |  4 ++
 6 files changed, 113 insertions(+)
---
base-commit: ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
change-id: 20250424-riscv-time-mmio-5628e0fca8af

Best regards,
-- 
Aleksa Paunovic <aleksa.paunovic at htecgroup.com>




From maxime.chevallier at bootlin.com  Wed Jun 10 01:26:50 2026
From: maxime.chevallier at bootlin.com (Maxime Chevallier)
Date: Wed, 10 Jun 2026 10:26:50 +0200
Subject: [PATCH net-next v8 3/6] net: stmmac: eic7700: make RGMII delay
 properties optional
In-Reply-To: <20260610012937.911-1-lizhi2@eswincomputing.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
 <20260610012937.911-1-lizhi2@eswincomputing.com>
Message-ID: <eaa645fc-be06-4a15-8c2f-6e82129c4715@bootlin.com>

Hi,

On 6/10/26 03:29, lizhi2 at eswincomputing.com wrote:
> From: Zhi Li <lizhi2 at eswincomputing.com>
> 
> Make rx-internal-delay-ps and tx-internal-delay-ps optional in the
> EIC7700 DWMAC driver.
> 
> The driver previously required both properties to be present and would
> fail probe when they were missing. This restricts valid hardware
> configurations where RGMII timing is instead provided by the PHY or
> board design.
> 
> Update the driver to treat missing delay properties as zero delay,
> allowing systems without explicit MAC-side delay tuning to operate
> correctly.
> 
> This aligns the driver behavior with the updated device tree binding
> and provides a safe default configuration when MAC-side delay
> programming is not required.
> 
> Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
> ---
>  drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c | 6 ------
>  1 file changed, 6 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> index 4ac979d874d6..ec99b597aeaf 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> @@ -165,9 +165,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
>  		dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
>  		dwc_priv->eth_clk_dly_param |=
>  				 FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
> -	} else {
> -		return dev_err_probe(&pdev->dev, -EINVAL,
> -			"missing required property rx-internal-delay-ps\n");
>  	}
>  
>  	/* Read tx-internal-delay-ps and update tx_clk delay */
> @@ -187,9 +184,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
>  		dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
>  		dwc_priv->eth_clk_dly_param |=
>  				 FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
> -	} else {
> -		return dev_err_probe(&pdev->dev, -EINVAL,
> -			"missing required property tx-internal-delay-ps\n");
>  	}

I think then you need to handle RGMII, RGMII_ID, RGMII_RXID and RGMII_TXID,
by using default delays for these (usually around 2ns), as here all delays
will be set to 0, regardless of the RGMII mode in use.


Maxime

>  
>  	dwc_priv->eic7700_hsp_regmap =



From kernel at rembrandt.dev  Wed Jun 10 02:05:14 2026
From: kernel at rembrandt.dev (Andrew Rembrandt)
Date: Wed, 10 Jun 2026 11:05:14 +0200
Subject: [PATCH] riscv: dts: spacemit: k3-pico-itx: Fix non-functional
 ethernet TX timing
In-Reply-To: <aiid4Y6x6Dbbwszf@inochi.infowork>
References: <20260608182358.170489-1-kernel@rembrandt.dev>
 <aiemGajqcQeY9avz@inochi.infowork>
 <aihYftGNcpUd4UUR@mcmanus>
 <aiid4Y6x6Dbbwszf@inochi.infowork>
Message-ID: <aikmOfazxdrhpty7@mcmanus>

On Wed, Jun 10, 2026 at 07:14:56 am Inochi Amaoto wrote:
> Do not do this, just leave the rx-internal-delay-ps untouched.

Sounds good, I'll leave v1 as-is. Many thanks for the review.

Regards,

Andrew


From fangyu.yu at linux.alibaba.com  Wed Jun 10 02:39:22 2026
From: fangyu.yu at linux.alibaba.com (fangyu.yu at linux.alibaba.com)
Date: Wed, 10 Jun 2026 17:39:22 +0800
Subject: [PATCH] RISC-V: KVM: Avoid redundant page-table allocations in ioremap topup
Message-ID: <20260610093922.51617-1-fangyu.yu@linux.alibaba.com>

From: Fangyu Yu <fangyu.yu at linux.alibaba.com>

kvm_riscv_mmu_ioremap() currently tops up its on-stack page-table
cache via kvm_mmu_topup_memory_cache(), which allocates up to
KVM_ARCH_NR_OBJS_PER_MEMORY_CACHE (32) objects per topup.

ioremap only consumes non-leaf page-table pages, at most
pgd_levels - 1 (1 to 4) per call, and for contiguous mappings
within the same huge page the non-leaf pages are allocated once
and reused by subsequent pages. Topping up to 32 objects therefore
triggers many unnecessary GFP_KERNEL_ACCOUNT allocations on every
call, all of which are freed when the function returns. In hot
paths (such as vCPU migration), this creates avoidable allocator
churn and wastes CPU cycles.

Use __kvm_mmu_topup_memory_cache() with a capacity of pgd_levels so
the on-stack cache is sized to the maximum demand of a single
mapping. This removes the redundant allocations and reduces per-call
overhead without changing behavior.

Signed-off-by: Fangyu Yu <fangyu.yu at linux.alibaba.com>
---
 arch/riscv/kvm/mmu.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/kvm/mmu.c b/arch/riscv/kvm/mmu.c
index 2d3def024270..873a5dde4b92 100644
--- a/arch/riscv/kvm/mmu.c
+++ b/arch/riscv/kvm/mmu.c
@@ -39,6 +39,7 @@ int kvm_riscv_mmu_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa,
 	pgprot_t prot;
 	unsigned long pfn;
 	phys_addr_t addr, end;
+	unsigned long pgd_levels = kvm->arch.pgd_levels;
 	struct kvm_mmu_memory_cache pcache = {
 		.gfp_custom = (in_atomic) ? GFP_ATOMIC | __GFP_ACCOUNT : 0,
 		.gfp_zero = __GFP_ZERO,
@@ -61,7 +62,7 @@ int kvm_riscv_mmu_ioremap(struct kvm *kvm, gpa_t gpa, phys_addr_t hpa,
 		if (!writable)
 			map.pte = pte_wrprotect(map.pte);
 
-		ret = kvm_mmu_topup_memory_cache(&pcache, kvm->arch.pgd_levels);
+		ret = __kvm_mmu_topup_memory_cache(&pcache, pgd_levels, pgd_levels);
 		if (ret)
 			goto out;
 
-- 
2.50.1



From chenyou910331 at gmail.com  Wed Jun 10 04:11:21 2026
From: chenyou910331 at gmail.com (Chen-Yu Yeh)
Date: Wed, 10 Jun 2026 19:11:21 +0800
Subject: [PATCH 2/2] riscv: dts: sophgo: Add Milk-V Duo 256M board support
In-Reply-To: <20260610111136.1514155-1-chenyou910331@gmail.com>
References: <20260610111136.1514155-1-chenyou910331@gmail.com>
Message-ID: <20260610111136.1514155-2-chenyou910331@gmail.com>

The Milk-V Duo 256M is a small form factor development board based on
the Sophgo SG2002 SoC.

This patch adds basic device tree support for the board, including:
- UART console
- SD/MMC controller
- USB host
- Onboard blue status LED (connected to PWR_GPIO[2] / porte 2)

Tested on actual Milk-V Duo 256M hardware, verified boot to shell and
heartbeat LED functionality.

Signed-off-by: Chen-Yu Yeh <chenyou910331 at gmail.com>
---
 arch/riscv/boot/dts/sophgo/Makefile           |   2 +
 .../boot/dts/sophgo/sg2002-milkv-duo256m.dts  | 119 ++++++++++++++++++
 2 files changed, 121 insertions(+)
 create mode 100644 arch/riscv/boot/dts/sophgo/sg2002-milkv-duo256m.dts

diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile
index 6f65526d4193..e49c8233ae1f 100644
--- a/arch/riscv/boot/dts/sophgo/Makefile
+++ b/arch/riscv/boot/dts/sophgo/Makefile
@@ -2,7 +2,9 @@
 dtb-$(CONFIG_ARCH_SOPHGO) += cv1800b-milkv-duo.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += cv1812h-huashan-pi.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2002-licheerv-nano-b.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += sg2002-milkv-duo256m.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-evb-v1.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-evb-v2.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2044-sophgo-srd3-10.dtb
+
diff --git a/arch/riscv/boot/dts/sophgo/sg2002-milkv-duo256m.dts b/arch/riscv/boot/dts/sophgo/sg2002-milkv-duo256m.dts
new file mode 100644
index 000000000000..882fba441396
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/sg2002-milkv-duo256m.dts
@@ -0,0 +1,119 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2023 Jisheng Zhang <jszhang at kernel.org>
+ */
+
+/dts-v1/;
+
+#include "sg2002.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Milk-V Duo 256M";
+	compatible = "milkv,duo256m", "sophgo,sg2002";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	leds {
+		compatible = "gpio-leds";
+
+		led-blue {
+			label = "milkv:blue:status";
+			gpios = <&porte 2 GPIO_ACTIVE_HIGH>;
+			linux,default-trigger = "heartbeat";
+			default-state = "on";
+		};
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		coprocessor_rtos: region at 83f40000 {
+			reg = <0x83f40000 0xc0000>;
+			no-map;
+		};
+	};
+};
+
+&osc {
+	clock-frequency = <25000000>;
+};
+
+&pinctrl {
+	uart0_cfg: uart0-cfg {
+		uart0-pins {
+			pinmux = <PINMUX(PIN_UART0_TX, 0)>,
+				 <PINMUX(PIN_UART0_RX, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+
+	sdhci0_cfg: sdhci0-cfg {
+		sdhci0-clk-pins {
+			pinmux = <PINMUX(PIN_SD0_CLK, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <16100>;
+			power-source = <3300>;
+		};
+
+		sdhci0-cmd-pins {
+			pinmux = <PINMUX(PIN_SD0_CMD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		sdhci0-data-pins {
+			pinmux = <PINMUX(PIN_SD0_D0, 0)>,
+				 <PINMUX(PIN_SD0_D1, 0)>,
+				 <PINMUX(PIN_SD0_D2, 0)>,
+				 <PINMUX(PIN_SD0_D3, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		sdhci0-cd-pins {
+			pinmux = <PINMUX(PIN_SD0_CD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+};
+
+&sdhci0 {
+	pinctrl-0 = <&sdhci0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+	bus-width = <4>;
+	no-1-8-v;
+	no-mmc;
+	no-sdio;
+	disable-wp;
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usb {
+	dr_mode = "host";
+	status = "okay";
+};
-- 
2.43.0



From chenyou910331 at gmail.com  Wed Jun 10 05:10:10 2026
From: chenyou910331 at gmail.com (Chen-Yu Yeh)
Date: Wed, 10 Jun 2026 20:10:10 +0800
Subject: [PATCH v2 2/2] riscv: dts: sophgo: Add Milk-V Duo 256M board support
In-Reply-To: <20260610121026.1517621-1-chenyou910331@gmail.com>
References: <20260610121026.1517621-1-chenyou910331@gmail.com>
Message-ID: <20260610121026.1517621-2-chenyou910331@gmail.com>

The Milk-V Duo 256M is a small form factor development board based on
the Sophgo SG2002 SoC.

This patch adds basic device tree support for the board, including:
- UART console
- SD/MMC controller
- USB host
- Onboard blue status LED (connected to PWR_GPIO[2] / porte 2)

Tested on actual Milk-V Duo 256M hardware, verified boot to shell and
heartbeat LED functionality.

Signed-off-by: Chen-Yu Yeh <chenyou910331 at gmail.com>
---
Changes since v1:
- Removed the leds node because &porte is not yet supported in cv180x.dtsi,
  which would cause a dtc compilation error.
- Retained the &usb node because it is already defined in cv180x.dtsi.
- Cleaned up the trailing blank line in the Makefile.

 arch/riscv/boot/dts/sophgo/Makefile           |   3 +-
 .../boot/dts/sophgo/sg2002-milkv-duo256m.dts  | 108 ++++++++++++++++++
 2 files changed, 110 insertions(+), 1 deletion(-)
 create mode 100644 arch/riscv/boot/dts/sophgo/sg2002-milkv-duo256m.dts

diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile
index 6f65526d4193..f9415c30a2c5 100644
--- a/arch/riscv/boot/dts/sophgo/Makefile
+++ b/arch/riscv/boot/dts/sophgo/Makefile
@@ -2,7 +2,8 @@
 dtb-$(CONFIG_ARCH_SOPHGO) += cv1800b-milkv-duo.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += cv1812h-huashan-pi.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2002-licheerv-nano-b.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += sg2002-milkv-duo256m.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-evb-v1.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-evb-v2.dtb
-dtb-$(CONFIG_ARCH_SOPHGO) += sg2044-sophgo-srd3-10.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += sg2044-sophgo-srd3-10.dtb
\ No newline at end of file
diff --git a/arch/riscv/boot/dts/sophgo/sg2002-milkv-duo256m.dts b/arch/riscv/boot/dts/sophgo/sg2002-milkv-duo256m.dts
new file mode 100644
index 000000000000..4cf441ab3790
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/sg2002-milkv-duo256m.dts
@@ -0,0 +1,108 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (C) 2023 Jisheng Zhang <jszhang at kernel.org>
+ */
+
+/dts-v1/;
+
+#include "sg2002.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+	model = "Milk-V Duo 256M";
+	compatible = "milkv,duo256m", "sophgo,sg2002";
+
+	aliases {
+		serial0 = &uart0;
+		serial1 = &uart1;
+		serial2 = &uart2;
+		serial3 = &uart3;
+		serial4 = &uart4;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	reserved-memory {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+
+		coprocessor_rtos: region at 83f40000 {
+			reg = <0x83f40000 0xc0000>;
+			no-map;
+		};
+	};
+};
+
+&osc {
+	clock-frequency = <25000000>;
+};
+
+&pinctrl {
+	uart0_cfg: uart0-cfg {
+		uart0-pins {
+			pinmux = <PINMUX(PIN_UART0_TX, 0)>,
+				 <PINMUX(PIN_UART0_RX, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+
+	sdhci0_cfg: sdhci0-cfg {
+		sdhci0-clk-pins {
+			pinmux = <PINMUX(PIN_SD0_CLK, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <16100>;
+			power-source = <3300>;
+		};
+
+		sdhci0-cmd-pins {
+			pinmux = <PINMUX(PIN_SD0_CMD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		sdhci0-data-pins {
+			pinmux = <PINMUX(PIN_SD0_D0, 0)>,
+				 <PINMUX(PIN_SD0_D1, 0)>,
+				 <PINMUX(PIN_SD0_D2, 0)>,
+				 <PINMUX(PIN_SD0_D3, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		sdhci0-cd-pins {
+			pinmux = <PINMUX(PIN_SD0_CD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+};
+
+&sdhci0 {
+	pinctrl-0 = <&sdhci0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+	bus-width = <4>;
+	no-1-8-v;
+	no-mmc;
+	no-sdio;
+	disable-wp;
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&usb {
+	dr_mode = "host";
+	status = "okay";
+};
-- 
2.43.0



From dlan at kernel.org  Wed Jun 10 05:34:32 2026
From: dlan at kernel.org (Yixun Lan)
Date: Wed, 10 Jun 2026 12:34:32 +0000
Subject: [PATCH] riscv: dts: spacemit: k3: Enable SD card support
Message-ID: <20260610-07-k3-enable-sd-v1-1-196ae29bd091@kernel.org>

Add the device tree node of SDHCI-0 controller which found on CoM260-IFX
board, it's currenty used for Micro SD card slot, and one GPIO pin is
configured as card insertion/removal detection pin, the slot use 4-bit
data bus, and up support to SDR104 speed mode.

Signed-off-by: Yixun Lan <dlan at kernel.org>
---
 arch/riscv/boot/dts/spacemit/k3-com260-ifx.dts | 18 +++++++++++
 arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi   | 44 ++++++++++++++++++++++++++
 arch/riscv/boot/dts/spacemit/k3.dtsi           | 13 ++++++++
 3 files changed, 75 insertions(+)

diff --git a/arch/riscv/boot/dts/spacemit/k3-com260-ifx.dts b/arch/riscv/boot/dts/spacemit/k3-com260-ifx.dts
index 238bb03d0e9e..e7f76cd24b90 100644
--- a/arch/riscv/boot/dts/spacemit/k3-com260-ifx.dts
+++ b/arch/riscv/boot/dts/spacemit/k3-com260-ifx.dts
@@ -19,3 +19,21 @@ chosen {
 		stdout-path = "serial0:115200n8";
 	};
 };
+
+&sdhci0 {
+	pinctrl-names = "default","uhs";
+	pinctrl-0 = <&mmc1_cfg>;
+	pinctrl-1 = <&mmc1_uhs_cfg>;
+	bus-width = <4>;
+	cd-gpios = <&gpio K3_GPIO(4) GPIO_ACTIVE_HIGH>;
+	no-mmc;
+	no-sdio;
+	disable-wp;
+	cap-sd-highspeed;
+	vmmc-supply = <&aldo4>;
+	vqmmc-supply = <&aldo1>;
+	sd-uhs-sdr25;
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	status = "okay";
+};
diff --git a/arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi b/arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi
index 3ee1471f3798..6b808f890a28 100644
--- a/arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3-pinctrl.dtsi
@@ -689,4 +689,48 @@ uart0-0-pins {
 			drive-strength = <25>;
 		};
 	};
+
+	mmc1_cfg: mmc1-cfg {
+		mmc1-data-cmd-pins {
+			pinmux = <K3_PADCONF(132, 0)>,	/* mmc1 dat3 */
+				 <K3_PADCONF(133, 0)>,	/* mmc1 dat2 */
+				 <K3_PADCONF(134, 0)>,	/* mmc1 dat1 */
+				 <K3_PADCONF(135, 0)>,	/* mmc1 dat0 */
+				 <K3_PADCONF(136, 0)>;	/* mmc1 cmd */
+
+			bias-pull-up = <0>;
+			drive-strength = <25>;
+			power-source = <3300>;
+		};
+
+		mmc1-clk-pins {
+			pinmux = <K3_PADCONF(137, 0)>;	/* mmc1 clk */
+
+			bias-pull-down;
+			drive-strength = <25>;
+			power-source = <3300>;
+		};
+	};
+
+	mmc1_uhs_cfg: mmc1-uhs-cfg {
+		mmc1-uhs-data-cmd-pins {
+			pinmux = <K3_PADCONF(132, 0)>,	/* mmc1 dat3 */
+				 <K3_PADCONF(133, 0)>,	/* mmc1 dat2 */
+				 <K3_PADCONF(134, 0)>,	/* mmc1 dat1 */
+				 <K3_PADCONF(135, 0)>,	/* mmc1 dat0 */
+				 <K3_PADCONF(136, 0)>;	/* mmc1 cmd */
+
+			bias-pull-up = <0>;
+			drive-strength = <21>;
+			power-source = <1800>;
+		};
+
+		mmc1-uhs-clk-pins {
+			pinmux = <K3_PADCONF(137, 0)>;	/* mmc1 clk */
+
+			bias-pull-down;
+			drive-strength = <21>;
+			power-source = <1800>;
+		};
+	};
 };
diff --git a/arch/riscv/boot/dts/spacemit/k3.dtsi b/arch/riscv/boot/dts/spacemit/k3.dtsi
index 19fc9b49668e..dabb0d5e6bad 100644
--- a/arch/riscv/boot/dts/spacemit/k3.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3.dtsi
@@ -1099,6 +1099,19 @@ pll: clock-controller at d4090000 {
 			#clock-cells = <1>;
 		};
 
+		sdhci0: mmc at d4280000 {
+			compatible = "spacemit,k3-sdhci";
+			reg = <0x0 0xd4280000 0x0 0x200>;
+			clocks = <&syscon_apmu CLK_APMU_SDH_AXI>,
+				 <&syscon_apmu CLK_APMU_SDH0>;
+			clock-names = "core", "io";
+			resets = <&syscon_apmu RESET_APMU_SDH_AXI>,
+				 <&syscon_apmu RESET_APMU_SDH0>;
+			reset-names = "axi", "sdh";
+			interrupts = <99 IRQ_TYPE_LEVEL_HIGH>;
+			status = "disabled";
+		};
+
 		syscon_apmu: system-controller at d4282800 {
 			compatible = "spacemit,k3-syscon-apmu";
 			reg = <0x0 0xd4282800 0x0 0x400>;

---
base-commit: 38d5f73d1f5af60d87047b981736b89521e49213
change-id: 20260609-07-k3-enable-sd-e1ddf090e87f

Best regards,
--  
Yixun Lan <dlan at kernel.org>



From josh.milas at gmail.com  Wed Jun 10 05:57:55 2026
From: josh.milas at gmail.com (Joshua Milas)
Date: Wed, 10 Jun 2026 08:57:55 -0400
Subject: [PATCH v5 RESEND 5/5] riscv64: dts: sophgo: add initial Milk-V
 Duo S board support
In-Reply-To: <aiawOUHBcKtMVEZk@sleek>
References: <20260530173347.33533-1-josh.milas@gmail.com>
 <20260530173347.33533-6-josh.milas@gmail.com>
 <DJ0ZYF5C8MMH.2GBBY188VVPSH@mailbox.org>
 <aiawOUHBcKtMVEZk@sleek>
Message-ID: <ailfU9PHrm6MDhdR@sleek>

Hi Shuwei,

I was able to get the wifi chip working. It requires the proper DT and an
updated aic8800-milkv-duo-s driver [1] that has been updated to Linux 7.1.
The next patch will cover the DT part.

[1] https://gitlab.com/DeepHorizons/aic8800-milkv-duo-s

Have a great day,
- Joshua Milas


From pjw at kernel.org  Wed Jun 10 06:54:04 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Wed, 10 Jun 2026 07:54:04 -0600 (MDT)
Subject: [GIT PULL] RISC-V updates for v7.1-rc8
Message-ID: <740336ea-a076-86e0-0fad-2264f0448da2@kernel.org>

Linus,

Please pull these fixes for late v7.1-rc.  The most important fix
is for a performance regression in the RISC-V-specific 
implementation of the checksumming code, related
to when RISC-V systems probe unaligned access performance during boot.  
There is another fix to return -EinVaL when invalid flags are
passed to the CFI landing pad control prctl(); no existing software should 
rely on the previously-incorrect behavior.  Finally there is a fix for a 
warning when dumping core, also CFI-related.   

thanks,

- Paul


The following changes since commit 5200f5f493f79f14bbdc349e402a40dfb32f23c8:

  Linux 7.1-rc4 (2026-05-17 13:59:58 -0700)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux tags/riscv-for-linux-7.1-rc8

for you to fetch changes up to 15b4155138505669d3d43d7692459ee8ea2a86e7:

  riscv: cfi: reject unknown flags in PR_SET_CFI (2026-06-06 20:17:05 -0600)

----------------------------------------------------------------
RISC-V updates for v7.1-rc8

- Fix the implementation of the CFI branch landing pad control
  prctl()s to return -EINVAL if unknown control bits are set, rather
  than silently ignoring the request; and add a kselftest for this
  case

- Fix unaligned access performance testing to happen earlier in boot,
  which fixes a performance regression in the lib/checksum code

- Fix a binfmt_elf warning when dumping core (due to missing
  .core_note_name for CFI registers)

----------------------------------------------------------------
Andreas Schwab (1):
      riscv/ptrace: Use USER_REGSET_NOTE_TYPE for REGSET_CFI

Nam Cao (1):
      riscv: Fix fast_unaligned_access_speed_key not getting initialized

Richard Patel (1):
      riscv: cfi: reject unknown flags in PR_SET_CFI

 arch/riscv/include/asm/usercfi.h             |  1 +
 arch/riscv/kernel/ptrace.c                   |  2 +-
 arch/riscv/kernel/unaligned_access_speed.c   | 15 ++++-----------
 arch/riscv/kernel/usercfi.c                  |  3 +++
 tools/testing/selftests/riscv/cfi/cfitests.c |  6 ++++++
 5 files changed, 15 insertions(+), 12 deletions(-)

vmlinux size differences in bytes (from 5200f5f493f7):
text  data  bss   dec  hex  filename                             
 -12  +120    .  +108  +6c  vmlinux.defconfig.gcc-15             
  -8   +88    .   +80  +50  vmlinux.nosmp_defconfig.gcc-15       
 -20   +64    .   +44  +2c  vmlinux.rv32_defconfig.gcc-15        
 -20   +32    .   +12   +c  vmlinux.rv32_nosmp_defconfig.gcc-15  
 -40   +56    .   +16  +10  vmlinux.nommu_virt_defconfig.gcc-15  
 -20   +24    .    +4   +4  vmlinux.defconfig.clang-20           
  -8   +24    .   +16  +10  vmlinux.nosmp_defconfig.clang-20     
 -36   +64    .   +28  +1c  vmlinux.rv32_defconfig.clang-20      
  -8   +32    .   +24  +18  vmlinux.rv32_nosmp_defconfig.clang-20
 -28    -8    .   -36  -24  vmlinux.nommu_virt_defconfig.clang-20
 -28   +56    .   +28  +1c  vmlinux.defconfig.clang-17           
 -20   +88    .   +68  +44  vmlinux.nosmp_defconfig.clang-17     
 -24  +128    .  +104  +68  vmlinux.rv32_defconfig.clang-17      
 -20  +128    .  +108  +6c  vmlinux.rv32_nosmp_defconfig.clang-17
 -36   +56    .   +20  +14  vmlinux.nommu_virt_defconfig.clang-17
 -16   +56    .   +40  +28  vmlinux.defconfig.gcc-11             
 -24   +56    .   +32  +20  vmlinux.nosmp_defconfig.gcc-11       
 -20   +64    .   +44  +2c  vmlinux.rv32_defconfig.gcc-11        
 -24   +96    .   +72  +48  vmlinux.rv32_nosmp_defconfig.gcc-11  
 -44  +248    .  +204  +cc  vmlinux.nommu_virt_defconfig.gcc-11  


From namcao at linutronix.de  Wed Jun 10 08:56:25 2026
From: namcao at linutronix.de (Nam Cao)
Date: Wed, 10 Jun 2026 17:56:25 +0200
Subject: [PATCH 01/16] riscv: Introduce instruction table generation
In-Reply-To: <20260407-riscv_insn_table-v1-1-54b4736a1e77@gmail.com>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-1-54b4736a1e77@gmail.com>
Message-ID: <878q8m1j9y.fsf@yellow.woof>

Charlie Jenkins via B4 Relay
<devnull+thecharlesjenkins.gmail.com at kernel.org> writes:
> From: Charlie Jenkins <thecharlesjenkins at gmail.com>
>
> Eliminate the need to hand-write riscv instructions by using a shell
> script to autogenerate a header from an instruction table. This is modeled
> after the syscall table infrastructure.
>
> The table is generated externally by riscv-unified-db [1], but is
> in a simple format to make it possible to use other tools or modify
> manually.
>
> [1] https://github.com/riscv-software-src/riscv-unified-db
>
> Signed-off-by: Charlie Jenkins <thecharlesjenkins at gmail.com>

Thanks for the work, I really like the idea. This will make it much
easier to maintain the instruction stuffs.

> +c.ld common,32 011<13|00<0 imm<3=6-5|12-10 xd!1!3!5!7=4-2 xs1=9-7
> +c.ld common,64 011<13|00<0 imm<3=6-5|12-10 xd=4-2 xs1=9-7

Not sure if I confuse something, but the spec says "C.LD is an
RV64C-only instruction". Why do we have 32 here?

> +echo "#define COMMA ," >> $outfile
> +echo "#define SEMICOLON ;" >> $outfile
> +echo "#define SINGLE_ARG(...) __VA_ARGS__" >> $outfile

Aren't these macro unused?

> +echo >> $outfile
> +
> +grep -E "^[a-z\.0-9]+[[:space:]]+" "$infile" | {
> +    while read name base fixed variables; do
> +        echo "/* $name */"
> +
> +        compressed_name=${name##c.*}
	   ^^^^^^^^^^^^^^^
	   this name is misleading

> +        invalid_inst_functions=""
> +        variable_params=""
> +        constraints=""
> +        match=""
> +        mask=""
> +        make=""
> +
> +        # All compressed instructions start with "c."
> +        size=${compressed_name:+32};
> +        size=${size:-16};
> +
> +        # Replace all . with _
> +        formatted_inst_name=$name
> +        while [ ! ${formatted_inst_name##*.*} ]; do
> +            prefix=${formatted_inst_name%.*}
> +            suffix=${formatted_inst_name##*.}
> +            contains_dot=${formatted_inst_name##*.*}
> +            formatted_inst_name=${contains_dot:-${prefix}_${suffix}}
> +        done

Does the simplier
     formatted_inst_name=$(echo $name | tr '.' '_')
work?

> +            echo "static __always_inline ${type}${size} riscv_insn_${formatted_inst_name}_extract_${variable_name}(u${size} ${insn})"
> +            echo "{"
> +            echo "\treturn ${extract};"
> +            echo "}"
> +            echo "static __always_inline void riscv_insn_${formatted_inst_name}_insert_${variable_name}(u${size} *${insn}, ${type}32 ${var})"
> +            echo "{"
> +            echo "\t*_insn &= ${insert_mask# & };"

Why is this required? Isn't this part always zero at this point?

> +            echo "\t*_insn |= ${insert# | };"
> +            echo "}"
> +
> +            if [ "${only_base}" ]; then
> +                invalid_inst_functions="${invalid_inst_functions}static __always_inline ${type}${size} riscv_insn_${formatted_inst_name}_extract_${variable_name}(u${size} ${insn}) {\n\tpanic(\"${name} is not supported on non ${only_base}-bit systems.\");\n}\n"

Instead of panic(), can we do BUILD_BUG() instead?

Nam


From conor at kernel.org  Wed Jun 10 09:52:37 2026
From: conor at kernel.org (Conor Dooley)
Date: Wed, 10 Jun 2026 17:52:37 +0100
Subject: [External] Re: [PATCH v3 1/3] dt-bindings: riscv: clarify Svadu
 boot-time behavior
In-Reply-To: <CAEEQ3w=C_z8awtevLhceTgqLW79ONzKTm5MRJeoSTLB9q_CeiQ@mail.gmail.com>
References: <20260609130021.99899-1-cuiyunhui@bytedance.com>
 <20260609130021.99899-2-cuiyunhui@bytedance.com>
 <20260609-washboard-fantasize-ddf0a9752df8@spud>
 <CAEEQ3w=C_z8awtevLhceTgqLW79ONzKTm5MRJeoSTLB9q_CeiQ@mail.gmail.com>
Message-ID: <20260610-prompter-fever-db3f6a200051@spud>

On Wed, Jun 10, 2026 at 10:03:01AM +0800, yunhui cui wrote:
> Hi Conor,
> 
> On Wed, Jun 10, 2026 at 12:09?AM Conor Dooley <conor at kernel.org> wrote:
> >
> > On Tue, Jun 09, 2026 at 09:00:18PM +0800, Yunhui Cui wrote:
> > > Clarify that systems which advertise only Svadu have hardware PTE A/D
> > > updating enabled at boot, while systems advertising both Svade and Svadu
> > > must enable Svadu explicitly with SBI FWFT.
> > >
> > > Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
> > > Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
> > > ---
> > >  Documentation/devicetree/bindings/riscv/extensions.yaml | 6 +++---
> > >  1 file changed, 3 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
> > > index 2b0a8a93bb214..b09888e9988de 100644
> > > --- a/Documentation/devicetree/bindings/riscv/extensions.yaml
> > > +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
> > > @@ -294,10 +294,10 @@ properties:
> > >                 of the PTE A/D bits or page faults when they need updated.
> > >              2) Only Svade present in DT => Supervisor must assume Svade to be
> > >                 always enabled.
> > > -            3) Only Svadu present in DT => Supervisor must assume Svadu to be
> > > -               always enabled.
> > > +            3) Only Svadu present in DT => Supervisor must assume Svadu is
> > > +               enabled at boot.
> >
> > Commit message is missing an explanation of why this behaviour change is
> > not problematic. Although, to be honest, I am not sure what the changed text
> > actually means. If only Svadu is present, then the hardware doesn't support
> > Svade, and therefore Svadu would never be anything other than enabled so
> > changing the wording to specify "at boot" seems less clear?
> 
> The "enabled at boot" wording came from Andrew's feedback on the previous
> version: "always" is a sensitive term here because ADUE is writable when
> Svadu is implemented, and ADUE=0 behaves as though Svade were implemented.

Whether or not it is writeable, the current wording means that it is not
allowed to be changed. I think that's reasonable because there's nothing
else supported by the hardware so changing it makes no sense.

> Would this wording work?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260610/6fee8c93/attachment.sig>

From pr-tracker-bot at kernel.org  Wed Jun 10 12:22:22 2026
From: pr-tracker-bot at kernel.org (pr-tracker-bot at kernel.org)
Date: Wed, 10 Jun 2026 19:22:22 +0000
Subject: [GIT PULL] RISC-V updates for v7.1-rc8
In-Reply-To: <740336ea-a076-86e0-0fad-2264f0448da2@kernel.org>
References: <740336ea-a076-86e0-0fad-2264f0448da2@kernel.org>
Message-ID: <178111934201.3601381.1773969445054843044.pr-tracker-bot@kernel.org>

The pull request you sent on Wed, 10 Jun 2026 07:54:04 -0600 (MDT):

> git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux tags/riscv-for-linux-7.1-rc8

has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/767622308a1d8b111038fca0059b964da1f6d9c4

Thank you!

-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html


From thecharlesjenkins at gmail.com  Wed Jun 10 18:06:07 2026
From: thecharlesjenkins at gmail.com (Charlie Jenkins)
Date: Wed, 10 Jun 2026 18:06:07 -0700
Subject: [PATCH 01/16] riscv: Introduce instruction table generation
In-Reply-To: <878q8m1j9y.fsf@yellow.woof>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-1-54b4736a1e77@gmail.com>
 <878q8m1j9y.fsf@yellow.woof>
Message-ID: <aioJ_5SIXdGQg55R@blinky>

On Wed, Jun 10, 2026 at 05:56:25PM +0200, Nam Cao wrote:
> Charlie Jenkins via B4 Relay
> <devnull+thecharlesjenkins.gmail.com at kernel.org> writes:
> > From: Charlie Jenkins <thecharlesjenkins at gmail.com>
> >
> > Eliminate the need to hand-write riscv instructions by using a shell
> > script to autogenerate a header from an instruction table. This is modeled
> > after the syscall table infrastructure.
> >
> > The table is generated externally by riscv-unified-db [1], but is
> > in a simple format to make it possible to use other tools or modify
> > manually.
> >
> > [1] https://github.com/riscv-software-src/riscv-unified-db
> >
> > Signed-off-by: Charlie Jenkins <thecharlesjenkins at gmail.com>
> 
> Thanks for the work, I really like the idea. This will make it much
> easier to maintain the instruction stuffs.
> 
> > +c.ld common,32 011<13|00<0 imm<3=6-5|12-10 xd!1!3!5!7=4-2 xs1=9-7
> > +c.ld common,64 011<13|00<0 imm<3=6-5|12-10 xd=4-2 xs1=9-7
> 
> Not sure if I confuse something, but the spec says "C.LD is an
> RV64C-only instruction". Why do we have 32 here?

This is a weird one. The Ziclsd extension introduces it for RV32[1]. All
of the data is generated from the riscv-unified-db and because it is in
the Ziclsd extension, c.ld is included for 32-bit in the c.ld
description [2]. 

[1] https://docs.riscv.org/reference/isa/extensions/zilsd/_attachments/riscv-zilsd.pdf
[2] https://github.com/riscv/riscv-unified-db/blob/main/spec/std/isa/inst/C/c.ld.yaml

> 
> > +echo "#define COMMA ," >> $outfile
> > +echo "#define SEMICOLON ;" >> $outfile
> > +echo "#define SINGLE_ARG(...) __VA_ARGS__" >> $outfile
> 
> Aren't these macro unused?

Yes thanks, I had them for an earlier version and never removed them.

> 
> > +echo >> $outfile
> > +
> > +grep -E "^[a-z\.0-9]+[[:space:]]+" "$infile" | {
> > +    while read name base fixed variables; do
> > +        echo "/* $name */"
> > +
> > +        compressed_name=${name##c.*}
> 	   ^^^^^^^^^^^^^^^
> 	   this name is misleading

That's fair, I can rename it to be something like "compressed_inst"?

> 
> > +        invalid_inst_functions=""
> > +        variable_params=""
> > +        constraints=""
> > +        match=""
> > +        mask=""
> > +        make=""
> > +
> > +        # All compressed instructions start with "c."
> > +        size=${compressed_name:+32};
> > +        size=${size:-16};
> > +
> > +        # Replace all . with _
> > +        formatted_inst_name=$name
> > +        while [ ! ${formatted_inst_name##*.*} ]; do
> > +            prefix=${formatted_inst_name%.*}
> > +            suffix=${formatted_inst_name##*.}
> > +            contains_dot=${formatted_inst_name##*.*}
> > +            formatted_inst_name=${contains_dot:-${prefix}_${suffix}}
> > +        done
> 
> Does the simplier
>      formatted_inst_name=$(echo $name | tr '.' '_')
> work?

That does work, but it dramatically slows down the time. I was trying to
avoid using external programs because this is called on every
compilation and there are a lot of instructions to parse. On my system,
it's about 10x slower to use echo/tr. Taking the time from about 150us
to 1.5ms for each iteration and the total time from around 0.8s to
around 3.5s.

> 
> > +            echo "static __always_inline ${type}${size} riscv_insn_${formatted_inst_name}_extract_${variable_name}(u${size} ${insn})"
> > +            echo "{"
> > +            echo "\treturn ${extract};"
> > +            echo "}"
> > +            echo "static __always_inline void riscv_insn_${formatted_inst_name}_insert_${variable_name}(u${size} *${insn}, ${type}32 ${var})"
> > +            echo "{"
> > +            echo "\t*_insn &= ${insert_mask# & };"
> 
> Why is this required? Isn't this part always zero at this point?
> 
> > +            echo "\t*_insn |= ${insert# | };"
> > +            echo "}"
> > +
> > +            if [ "${only_base}" ]; then
> > +                invalid_inst_functions="${invalid_inst_functions}static __always_inline ${type}${size} riscv_insn_${formatted_inst_name}_extract_${variable_name}(u${size} ${insn}) {\n\tpanic(\"${name} is not supported on non ${only_base}-bit systems.\");\n}\n"
> 
> Instead of panic(), can we do BUILD_BUG() instead?

That's a better solution :)

- Charlie

> 
> Nam


From ruanjinjie at huawei.com  Wed Jun 10 18:30:54 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 11 Jun 2026 09:30:54 +0800
Subject: [PATCH v16 00/10] arm64/riscv: Add support for crashkernel CMA
 reservation
In-Reply-To: <20260608091000.d88d7f5cc1bc4fa17f5774fe@linux-foundation.org>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608091000.d88d7f5cc1bc4fa17f5774fe@linux-foundation.org>
Message-ID: <37f31716-095b-477c-9b0b-946a15275c2e@huawei.com>



On 6/9/2026 12:10 AM, Andrew Morton wrote:
> On Mon, 8 Jun 2026 15:34:49 +0800 Jinjie Ruan <ruanjinjie at huawei.com> wrote:
> 
>> The crash memory allocation, and the exclude of crashk_res, crashk_low_res
>> and crashk_cma memory are almost identical across different architectures,
>> This patch set handle them in crash core in a general way, which eliminate
>> a lot of duplication code.
>>
>> And add support for crashkernel CMA reservation for arm64 and riscv.
> 
> fyi, AI review might have found a bunch of issues in arch-specific
> code, all of them pre-existing.

Hi, Andrew?

As Mike conveyed, Baoquan proposed splitting out the unrelated bug fixes
into a separate patch set, in order to keep v16 from growing excessively.

Link: https://lore.kernel.org/all/ah2Lx7KHI60tzd0v at MiWiFi-R3L-srv/

Best Regards,
Jinjie

> 
> 	https://sashiko.dev/#/patchset/20260608073459.3119290-1-ruanjinjie at huawei.com
> 



From chenwandun1 at gmail.com  Wed Jun 10 19:09:37 2026
From: chenwandun1 at gmail.com (Wandun)
Date: Thu, 11 Jun 2026 10:09:37 +0800
Subject: [PATCH v3 00/11] kdump: reduce vmcore size and capture time
In-Reply-To: <20260527032917.3385849-1-chenwandun1@gmail.com>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
Message-ID: <7ed207fa-4c86-426a-8570-495902ce04c3@gmail.com>



On 5/27/26 11:29, Wandun Chen wrote:
> From: Wandun Chen <chenwandun at lixiang.com>
>
> On SoCs that carve out large firmware-owned reserved memory (GPU
> firmware, DSP, modem, camera ISP, NPU, ...), kdump currently dumps
> those carveouts as part of system RAM even though their contents are
> firmware state that is not useful for kernel crash analysis.
>
> This series introduces an opt-in 'dumpable' flag [1] on struct
> reserved_mem and uses it to filter the elfcorehdr PT_LOAD ranges on
> DT-based architectures (arm64, riscv, loongarch). By default reserved
> regions are treated as non-dumpable; CMA regions are explicitly opted
> in because their pages are returned to the buddy allocator and may
> carry key crash-analysis data.
>
> The series is organized as follows:
> Patches 1-3: Pre-existing fixes and a small prep change.
> Patches 4-5: Restructure to allow appending /memreserve/ entries.
> Patches 6-7: Add a dumpable flag and append /memreserve/ entries.
> Patch 8: Add generic kdump helpers.
> Patches 9-11: Wire the helpers into arm64, riscv and loongarch kdump
>                elfcorehdr preparation.
Hi,

Gentle ping on this series.

Status summary:
-patch 03: respun separately per Rob's suggestion, picked up for 7.2
-patch 06: Acked-by: Marek Szyprowski -patch 09: Acked-by: Will Deacon 
The remaining patches (01, 02, 04, 05, 07, 08, 10, 11) are still 
awaiting review. your feedback would be greately appreciated. I know we 
are at the end of 7.1 -rc cycle, I don't want to rush this series, just 
collecting more feedback, and will send next version based on 7.2-rc1. 
If spliting the series into smaller logical group would make review 
easier, please let me know. Best regards, Wandun
>
> v2 --> v3:
> 1. Fix out-of-bounds issue if device tree lacks /reserved-memory node.[2]
> 2. Fix UAF issue when alloc_reserved_mem_array() fails.
> 3. Add some prepare patches.
>
> v1 --> v2:
> 1. v1 added an opt-out DT property ('linux,no-dump'). Per Rob's
>     feedback [1], v2 drop that property and exclude reserve memory
>     by default.
> 2. Split some prepared patches from the original patches.
> 3. Address coding-style comments on patch 5 from Rob.
>
> [1] https://lore.kernel.org/lkml/20260506144542.GA2072596-robh at kernel.org/
> [2] https://sashiko.dev/#/patchset/20260520091844.592753-1-chenwandun%40lixiang.com?part=4
>
> Wandun Chen (11):
>    of: reserved_mem: handle NULL name in of_reserved_mem_lookup()
>    kexec/crash: provide crash_exclude_mem_range() stub when
>      CONFIG_CRASH_DUMP=n
>    of: reserved_mem: avoid post-init UAF when alloc_reserved_mem_array()
>      fails
>    of: reserved_mem: zero total_reserved_mem_cnt if no valid
>      /reserved-memory entry
>    of: reserved_mem: split alloc_reserved_mem_array() from
>      fdt_scan_reserved_mem_late()
>    of: reserved_mem: add dumpable flag to opt-in vmcore
>    of: reserved_mem: save /memreserve/ entries into the reserved_mem
>      array
>    of: reserved_mem: add kdump helpers to exclude non-dumpable regions
>    arm64: kdump: exclude non-dumpable reserved memory regions from vmcore
>    riscv: kdump: exclude non-dumpable reserved memory regions from vmcore
>    loongarch: kdump: exclude non-dumpable reserved memory regions from
>      vmcore
>
>   arch/arm64/kernel/machine_kexec_file.c     |   6 ++
>   arch/loongarch/kernel/machine_kexec_file.c |   6 ++
>   arch/riscv/kernel/machine_kexec_file.c     |   4 +
>   drivers/of/fdt.c                           |  11 +-
>   drivers/of/of_private.h                    |   3 +
>   drivers/of/of_reserved_mem.c               | 117 +++++++++++++++++++--
>   include/linux/crash_core.h                 |   6 ++
>   include/linux/of_reserved_mem.h            |  15 +++
>   kernel/dma/contiguous.c                    |   1 +
>   9 files changed, 157 insertions(+), 12 deletions(-)
>



From chenwandun1 at gmail.com  Wed Jun 10 20:09:22 2026
From: chenwandun1 at gmail.com (Wandun)
Date: Thu, 11 Jun 2026 11:09:22 +0800
Subject: [PATCH v3 00/11] kdump: reduce vmcore size and capture time
In-Reply-To: <7ed207fa-4c86-426a-8570-495902ce04c3@gmail.com>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <7ed207fa-4c86-426a-8570-495902ce04c3@gmail.com>
Message-ID: <a3993db0-6975-455d-9674-4fd7cfcf80fc@gmail.com>



On 6/11/26 10:09, Wandun wrote:
> 
> 
> On 5/27/26 11:29, Wandun Chen wrote:
>> From: Wandun Chen <chenwandun at lixiang.com>
>>
>> On SoCs that carve out large firmware-owned reserved memory (GPU
>> firmware, DSP, modem, camera ISP, NPU, ...), kdump currently dumps
>> those carveouts as part of system RAM even though their contents are
>> firmware state that is not useful for kernel crash analysis.
>>
>> This series introduces an opt-in 'dumpable' flag [1] on struct
>> reserved_mem and uses it to filter the elfcorehdr PT_LOAD ranges on
>> DT-based architectures (arm64, riscv, loongarch). By default reserved
>> regions are treated as non-dumpable; CMA regions are explicitly opted
>> in because their pages are returned to the buddy allocator and may
>> carry key crash-analysis data.
>>
>> The series is organized as follows:
>> Patches 1-3: Pre-existing fixes and a small prep change.
>> Patches 4-5: Restructure to allow appending /memreserve/ entries.
>> Patches 6-7: Add a dumpable flag and append /memreserve/ entries.
>> Patch 8: Add generic kdump helpers.
>> Patches 9-11: Wire the helpers into arm64, riscv and loongarch kdump
>> ?????????????? elfcorehdr preparation.
> Hi,
> 
> Gentle ping on this series.
> 
> Status summary:
> -patch 03: respun separately per Rob's suggestion, picked up for 7.2
> -patch 06: Acked-by: Marek Szyprowski -patch 09: Acked-by: Will Deacon
> The remaining patches (01, 02, 04, 05, 07, 08, 10, 11) are still
> awaiting review. your feedback would be greately appreciated. I know we
> are at the end of 7.1 -rc cycle, I don't want to rush this series, just
> collecting more feedback, and will send next version based on 7.2-rc1.
> If spliting the series into smaller logical group would make review
> easier, please let me know. Best regards, Wandun

Apologies for the formatting issue in my previous email.
Here is the properly formatted version.

Gentle ping on this series.

Status summary:
- patch 03: respun separately per Rob's suggestion, picked up for 7.2
- patch 06: Acked-by: Marek Szyprowski
- patch 09: Acked-by: Will Deacon

The remaining patches (01, 02, 04, 05, 07, 08, 10, 11) are still
awaiting review. Your feedback would be greatly appreciated.

I know we are at the end of 7.1-rc cycle, I don't want to rush this
series, just collecting more feedback, and will send next version based
on 7.2-rc1.

If splitting the series into smaller logical groups would make review
easier, please let me know.

Best regards,
Wandun


>>
>> v2 --> v3:
>> 1. Fix out-of-bounds issue if device tree lacks /reserved-memory node.[2]
>> 2. Fix UAF issue when alloc_reserved_mem_array() fails.
>> 3. Add some prepare patches.
>>
>> v1 --> v2:
>> 1. v1 added an opt-out DT property ('linux,no-dump'). Per Rob's
>> ??? feedback [1], v2 drop that property and exclude reserve memory
>> ??? by default.
>> 2. Split some prepared patches from the original patches.
>> 3. Address coding-style comments on patch 5 from Rob.
>>
>> [1] https://lore.kernel.org/lkml/20260506144542.GA2072596-
>> robh at kernel.org/
>> [2] https://sashiko.dev/#/patchset/20260520091844.592753-1-
>> chenwandun%40lixiang.com?part=4
>>
>> Wandun Chen (11):
>> ?? of: reserved_mem: handle NULL name in of_reserved_mem_lookup()
>> ?? kexec/crash: provide crash_exclude_mem_range() stub when
>> ???? CONFIG_CRASH_DUMP=n
>> ?? of: reserved_mem: avoid post-init UAF when alloc_reserved_mem_array()
>> ???? fails
>> ?? of: reserved_mem: zero total_reserved_mem_cnt if no valid
>> ???? /reserved-memory entry
>> ?? of: reserved_mem: split alloc_reserved_mem_array() from
>> ???? fdt_scan_reserved_mem_late()
>> ?? of: reserved_mem: add dumpable flag to opt-in vmcore
>> ?? of: reserved_mem: save /memreserve/ entries into the reserved_mem
>> ???? array
>> ?? of: reserved_mem: add kdump helpers to exclude non-dumpable regions
>> ?? arm64: kdump: exclude non-dumpable reserved memory regions from vmcore
>> ?? riscv: kdump: exclude non-dumpable reserved memory regions from vmcore
>> ?? loongarch: kdump: exclude non-dumpable reserved memory regions from
>> ???? vmcore
>>
>> ? arch/arm64/kernel/machine_kexec_file.c???? |?? 6 ++
>> ? arch/loongarch/kernel/machine_kexec_file.c |?? 6 ++
>> ? arch/riscv/kernel/machine_kexec_file.c???? |?? 4 +
>> ? drivers/of/fdt.c?????????????????????????? |? 11 +-
>> ? drivers/of/of_private.h??????????????????? |?? 3 +
>> ? drivers/of/of_reserved_mem.c?????????????? | 117 +++++++++++++++++++--
>> ? include/linux/crash_core.h???????????????? |?? 6 ++
>> ? include/linux/of_reserved_mem.h??????????? |? 15 +++
>> ? kernel/dma/contiguous.c??????????????????? |?? 1 +
>> ? 9 files changed, 157 insertions(+), 12 deletions(-)
>>
> 



From namcao at linutronix.de  Wed Jun 10 22:21:37 2026
From: namcao at linutronix.de (Nam Cao)
Date: Thu, 11 Jun 2026 07:21:37 +0200
Subject: [PATCH 01/16] riscv: Introduce instruction table generation
In-Reply-To: <aioJ_5SIXdGQg55R@blinky>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-1-54b4736a1e77@gmail.com>
 <878q8m1j9y.fsf@yellow.woof> <aioJ_5SIXdGQg55R@blinky>
Message-ID: <87se6tejoe.fsf@yellow.woof>

Charlie Jenkins <thecharlesjenkins at gmail.com> writes:
> This is a weird one. The Ziclsd extension introduces it for RV32[1]. All
> of the data is generated from the riscv-unified-db and because it is in
> the Ziclsd extension, c.ld is included for 32-bit in the c.ld
> description [2]. 

Oh :( We probably should amend the base spec to mention that.

>> > +        compressed_name=${name##c.*}
>> 	   ^^^^^^^^^^^^^^^
>> 	   this name is misleading
>
> That's fair, I can rename it to be something like "compressed_inst"?

My issue is that "compressed_name" indicates that it holds the
compressed variant of the name. But it actually is empty if the
instruction is compressed, otherwise it is the original instruction name.

I am not sure what is a better name. Perhaps just inline this to the
usage below.

Nam


From vkoul at kernel.org  Wed Jun 10 22:51:41 2026
From: vkoul at kernel.org (Vinod Koul)
Date: Thu, 11 Jun 2026 11:21:41 +0530
Subject: (subset) [PATCH v6 0/2] riscv: sophgo: allow DMA multiplexer
 set channel number for DMA controller
In-Reply-To: <20260511063818.463877-1-inochiama@gmail.com>
References: <20260511063818.463877-1-inochiama@gmail.com>
Message-ID: <178115710130.468137.1246445545709441202.b4-ty@kernel.org>


On Mon, 11 May 2026 14:38:15 +0800, Inochi Amaoto wrote:
> As the DMA controller on Sophgo CV1800 series SoC only has 8 channels,
> the SoC provides a dma multiplexer to reuse the DMA channel. However,
> the dma multiplexer also controlls the DMA interrupt multiplexer, which
> means that the dma multiplexer needs to know the channel number.
> 
> Change the DMA phandle args parsing logic so it can use handshake
> number as channel number if necessary.
> 
> [...]

Applied, thanks!

[1/2] dt-bindings: dma: snps,dw-axi-dmac: Add fallback compatible for CV1800B
      commit: 7524fe142b5a772f8421aeee2132cf7e21a00103

Best regards,
-- 
~Vinod




From namcao at linutronix.de  Wed Jun 10 23:08:35 2026
From: namcao at linutronix.de (Nam Cao)
Date: Thu, 11 Jun 2026 08:08:35 +0200
Subject: [PATCH 03/16] riscv: kgdb: Use generated instruction headers
In-Reply-To: <20260407-riscv_insn_table-v1-3-54b4736a1e77@gmail.com>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-3-54b4736a1e77@gmail.com>
Message-ID: <87pl1xehi4.fsf@yellow.woof>

Charlie Jenkins via B4 Relay
<devnull+thecharlesjenkins.gmail.com at kernel.org> writes:
> +#define riscv_insn_branch(_insn, regs_ptr, _opcode, _pc, _comparison, type)     \
> +	({                                                                      \
> +		unsigned long _ret;                                             \
> +		if ((type)riscv_insn_reg_get_val(                               \
> +			    regs_ptr,                                           \
> +			    riscv_insn_##_insn##_extract_xs1(_opcode))          \
> +			    _comparison(type) riscv_insn_reg_get_val(           \
> +				    regs_ptr,                                   \
> +				    riscv_insn_##_insn##_extract_xs2(_opcode))) \
> +			_ret = riscv_insn_##_insn##_extract_imm(_opcode);       \

Should be
		_ret = _pc + riscv_insn_##_insn##_extract_imm(_opcode);

> +		else                                                            \
> +			_ret = _pc + 4;                                         \
> +		_ret;                                                           \
> +	})
> +


From namcao at linutronix.de  Wed Jun 10 23:14:27 2026
From: namcao at linutronix.de (Nam Cao)
Date: Thu, 11 Jun 2026 08:14:27 +0200
Subject: [PATCH 04/16] riscv: kprobes: Use generated instruction headers
In-Reply-To: <20260407-riscv_insn_table-v1-4-54b4736a1e77@gmail.com>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-4-54b4736a1e77@gmail.com>
Message-ID: <87mrx1eh8c.fsf@yellow.woof>

Charlie Jenkins via B4 Relay
<devnull+thecharlesjenkins.gmail.com at kernel.org> writes:
>  bool __kprobes simulate_c_jr(u32 opcode, unsigned long addr, struct pt_regs *regs)
>  {
> -	return simulate_c_jr_jalr(opcode, addr, regs, false);
> +	unsigned long next_addr;
> +	unsigned long *regs_ptr = (unsigned long *)regs;
> +
> +	next_addr = regs_ptr[riscv_insn_c_jr_extract_xs1(opcode)];
> +	instruction_pointer_set(regs, next_addr);
> +
> +	regs->ra = addr + 2;

c.jr does not change ra.

> +	return true;
>  }

We have CONFIG_RISCV_KPROBES_KUNIT now, please try that.

Nam


From namcao at linutronix.de  Wed Jun 10 23:22:41 2026
From: namcao at linutronix.de (Nam Cao)
Date: Thu, 11 Jun 2026 08:22:41 +0200
Subject: [PATCH 04/16] riscv: kprobes: Use generated instruction headers
In-Reply-To: <20260407-riscv_insn_table-v1-4-54b4736a1e77@gmail.com>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-4-54b4736a1e77@gmail.com>
Message-ID: <87jys5egum.fsf@yellow.woof>

Charlie Jenkins via B4 Relay
<devnull+thecharlesjenkins.gmail.com at kernel.org> writes:
> This was again verified by checking all 32-bit values for each of these
> functions and checking that the two version have the same behavior.

Your checking is missing some cases. branch instructions and c.jr are
broken.

Btw, any chance that check can be added as a new kunit test case? I
wrote the CONFIG_RISCV_KPROBES_KUNIT, but that only tests some values.

Nam


From krzk at kernel.org  Wed Jun 10 23:51:57 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 11 Jun 2026 08:51:57 +0200
Subject: [PATCH v8 1/3] dt-bindings: timer: mips,p8700-gcru
In-Reply-To: <20260610-riscv-time-mmio-v8-1-a865206675c6@htecgroup.com>
References: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>
 <20260610-riscv-time-mmio-v8-1-a865206675c6@htecgroup.com>
Message-ID: <5e36909c-caf3-4078-b8ec-a77e385d20cf@kernel.org>

On 10/06/2026 10:22, Aleksa Paunovic via B4 Relay wrote:
> From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
> 
> Add dt-bindings for the GCR.U memory mapped timer device for RISC-V
> platforms. The GCR.U memory region contains shadow copies of the RISC-V
> mtime register and the hrtime Global Configuration Register.
> 
> Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>

You keep ignoring reviews you received (14th May!) and sending same mistake.

Can you address the emails?

NAK for this patch.

Best regards,
Krzysztof


From krzk at kernel.org  Wed Jun 10 23:54:09 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 11 Jun 2026 08:54:09 +0200
Subject: [PATCH v8 1/3] dt-bindings: timer: mips,p8700-gcru
In-Reply-To: <5e36909c-caf3-4078-b8ec-a77e385d20cf@kernel.org>
References: <20260610-riscv-time-mmio-v8-0-a865206675c6@htecgroup.com>
 <20260610-riscv-time-mmio-v8-1-a865206675c6@htecgroup.com>
 <5e36909c-caf3-4078-b8ec-a77e385d20cf@kernel.org>
Message-ID: <eda67f3d-9395-4386-9311-d6f6b1c62304@kernel.org>

On 11/06/2026 08:51, Krzysztof Kozlowski wrote:
> On 10/06/2026 10:22, Aleksa Paunovic via B4 Relay wrote:
>> From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
>>
>> Add dt-bindings for the GCR.U memory mapped timer device for RISC-V
>> platforms. The GCR.U memory region contains shadow copies of the RISC-V
>> mtime register and the hrtime Global Configuration Register.
>>
>> Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
> 
> You keep ignoring reviews you received (14th May!) and sending same mistake.
> 
> Can you address the emails?
> 
> NAK for this patch.

Hm, maybe it's b4 relay issue, so here is the report:

https://lore.kernel.org/all/20260514055333.A29B8C2BCB7 at smtp.kernel.org/

Best regards,
Krzysztof


From e at freeshell.de  Thu Jun 11 00:29:12 2026
From: e at freeshell.de (E Shattow)
Date: Thu, 11 Jun 2026 00:29:12 -0700
Subject: [PATCH] riscv: dts: spacemit: k3-pico-itx: Fix non-functional
 ethernet TX timing
In-Reply-To: <aikmOfazxdrhpty7@mcmanus>
References: <20260608182358.170489-1-kernel@rembrandt.dev>
 <aiemGajqcQeY9avz@inochi.infowork> <aihYftGNcpUd4UUR@mcmanus>
 <aiid4Y6x6Dbbwszf@inochi.infowork> <aikmOfazxdrhpty7@mcmanus>
Message-ID: <77a48b81-7906-4e18-9229-48643a67f402@freeshell.de>

Hi Andrew,

On 6/10/26 02:05, Andrew Rembrandt wrote:
> On Wed, Jun 10, 2026 at 07:14:56 am Inochi Amaoto wrote:
>> Do not do this, just leave the rx-internal-delay-ps untouched.
> 
> Sounds good, I'll leave v1 as-is. Many thanks for the review.
> 
> Regards,
> 
> Andrew
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv

I do not notice any difference with or without this property present,
tested Linux -next with U-Boot modification to devicetree:

load usb 0:1 $fdt_addr_r /dtb/spacemit/k3-pico-itx.dtb
fdt addr $fdt_addr_r
fdt resize
fdt header get filesize totalsize
fdt set /soc/ethernet at cac80000 tx-internal-delay-ps <400>
load usb 0:1 $kernel_addr_r /EFI/BOOT/BOOTRISCV64.EFI
# throwaway use of ping is workaround for broken vendor U-Boot
ping 127.0.0.1; bootefi $kernel_addr_r $fdt_addr_r

Aside, there is still some problem with the driver which does cause it
to fail. This can be reproduced by unloading the module and then loading
the module; built from -next with 'olddefconfig' of debian Kconfig for
kernel 7.1, no patches.

# modprobe -r dwmac_spacemit
# modprobe dwmac_spacemit
[   61.469745] spacemit-dwmac cac80000.ethernet end0: cannot attach to
PHY (error: -ENODEV)

[   91.544646] spacemit-dwmac cac80000.ethernet end0: cannot attach to
PHY (error: -ENODEV)

If not reloading the module then I don't see any difference, traffic
passes (ping 1.1.1.1) with or without your suggested
tx-internal-delay-ps property. Is there a specific test to run to
observe expected difference?

Thanks,

-E


From aleksa.paunovic at htecgroup.com  Thu Jun 11 00:39:08 2026
From: aleksa.paunovic at htecgroup.com (Aleksa Paunovic)
Date: Thu, 11 Jun 2026 07:39:08 +0000
Subject: [PATCH v8 1/3] dt-bindings: timer: mips,p8700-gcru
In-Reply-To: <eda67f3d-9395-4386-9311-d6f6b1c62304@kernel.org>
References: <eda67f3d-9395-4386-9311-d6f6b1c62304@kernel.org>
Message-ID: <ed1e9743-1a8c-409f-9cf7-391719ea68fb@htecgroup.com>

Hi Krzysztof,


On 6/11/26 08:54, Krzysztof Kozlowski wrote:
> On 11/06/2026 08:51, Krzysztof Kozlowski wrote:
>> On 10/06/2026 10:22, Aleksa Paunovic via B4 Relay wrote:
>>> From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
>>>
>>> Add dt-bindings for the GCR.U memory mapped timer device for RISC-V
>>> platforms. The GCR.U memory region contains shadow copies of the RISC-V
>>> mtime register and the hrtime Global Configuration Register.
>>>
>>> Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
>> You keep ignoring reviews you received (14th May!) and sending same mistake.
>>
>> Can you address the emails?
I wasn't really sure what the etiquette was for replying to Sashiko reviews, so I decided to
address the comments for other patches and send a v8 without replying.

As for this patch, the GCR.U itself does start at 0x7F000, but the first?
actual register (mtime) is at 0x7F050 [1].?
I'm not seeing any warnings when running dt_binding_check.

>>
>> NAK for this patch.
> Hm, maybe it's b4 relay issue, so here is the report:
>
> https://lore.kernel.org/all/20260514055333.A29B8C2BCB7 at smtp.kernel.org/
>

It did take a while but I noticed the comments.?
Will have to check more regularly in the future.


Best regards,
Aleksa

[1] https://mips.com/wp-content/uploads/2026/03/MIPS_P8700_P8700-F_Programmers_Reference_Guide_Rev1.86_2-17-2026.pdf#G7.1528502

From krzk at kernel.org  Thu Jun 11 00:50:58 2026
From: krzk at kernel.org (Krzysztof Kozlowski)
Date: Thu, 11 Jun 2026 09:50:58 +0200
Subject: [PATCH v8 1/3] dt-bindings: timer: mips,p8700-gcru
In-Reply-To: <ed1e9743-1a8c-409f-9cf7-391719ea68fb@htecgroup.com>
References: <eda67f3d-9395-4386-9311-d6f6b1c62304@kernel.org>
 <ed1e9743-1a8c-409f-9cf7-391719ea68fb@htecgroup.com>
Message-ID: <a2b5c9b4-5fc0-4507-a221-8695ed9574d8@kernel.org>

On 11/06/2026 09:39, Aleksa Paunovic wrote:
> Hi Krzysztof,
> 
> 
> On 6/11/26 08:54, Krzysztof Kozlowski wrote:
>> On 11/06/2026 08:51, Krzysztof Kozlowski wrote:
>>> On 10/06/2026 10:22, Aleksa Paunovic via B4 Relay wrote:
>>>> From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
>>>>
>>>> Add dt-bindings for the GCR.U memory mapped timer device for RISC-V
>>>> platforms. The GCR.U memory region contains shadow copies of the RISC-V
>>>> mtime register and the hrtime Global Configuration Register.
>>>>
>>>> Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
>>> You keep ignoring reviews you received (14th May!) and sending same mistake.
>>>
>>> Can you address the emails?
> I wasn't really sure what the etiquette was for replying to Sashiko reviews, so I decided to
> address the comments for other patches and send a v8 without replying.
> 
> As for this patch, the GCR.U itself does start at 0x7F000, but the first?
> actual register (mtime) is at 0x7F050 [1].?
> I'm not seeing any warnings when running dt_binding_check.

It's still a warning which you can easily reproduce on W=1 on dts. You
CANNOT have mismatch. If block starts at 0x7f000, first register CANNOT
start at different address or it completely does not matter where the
register is. It's contradictory. The block start address defines
where... does it start.

Best regards,
Krzysztof


From linusw at kernel.org  Thu Jun 11 01:10:27 2026
From: linusw at kernel.org (Linus Walleij)
Date: Thu, 11 Jun 2026 10:10:27 +0200
Subject: [PATCH v3 02/21] pinctrl: pinconf-generic: Add property 'input-debounce-ns'
In-Reply-To: <20260603-sinless-mooing-48a37d3d05ea@spud>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-3-changhuang.liang@starfivetech.com> <20260603-sinless-mooing-48a37d3d05ea@spud>
Message-ID: <CAD++jLkBeDkFAXLMDvEA8LjbBNJCz_ycYNPnDxs26qLTqDhXTQ@mail.gmail.com>

On Wed, Jun 3, 2026 at 5:18?PM Conor Dooley <conor at kernel.org> wrote:

> >       PIN_CONFIG_INPUT_DEBOUNCE,
> > +     PIN_CONFIG_INPUT_DEBOUNCE_NS,
> >       PIN_CONFIG_INPUT_ENABLE,
> >       PIN_CONFIG_INPUT_SCHMITT,
> >       PIN_CONFIG_INPUT_SCHMITT_ENABLE,
>
> Should this grow a mutual exclusion check in parse_fw_cfg()?
> Part of me says yes for consistency, but also as this is a new property
> that's going to have had exclusion in the binding from the start part of
> me says that it is unnecessary to add that.

Given that it already has a mutual exclusivity where it matters
most (in the bindings) I feel it's unnecessary. The only beneficials
would be out-of-tree users and I actively don't care about these
people.

Yours,
Linus Walleij


From linusw at kernel.org  Thu Jun 11 04:37:01 2026
From: linusw at kernel.org (Linus Walleij)
Date: Thu, 11 Jun 2026 13:37:01 +0200
Subject: [PATCH v3 04/21] pinctrl: starfive: Add StarFive JHB100 sys0
 controller driver
In-Reply-To: <20260603055347.66845-5-changhuang.liang@starfivetech.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com> <20260603055347.66845-5-changhuang.liang@starfivetech.com>
Message-ID: <CAD++jL=Qd8ADR_kX2Q7msM4Dd0xFayPGM4ZzB3uv2ufvkuybtQ@mail.gmail.com>

Hi Changhuang,

thanks for your patch!

On Wed, Jun 3, 2026 at 7:54?AM Changhuang Liang
<changhuang.liang at starfivetech.com> wrote:

> Add pinctrl driver for StarFive JHB100 SoC System-0(sys0) pinctrl
> controller.
>
> Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>

This patch adds generic infrastructure "JHB100" that is then used
by several drivers does it not?

Write something about that and some about the design in the
commit message.

> +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c
> @@ -0,0 +1,123 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Pinctrl / GPIO driver for StarFive JHB100 SoC System-0 domain
> + *
> + * Copyright (C) 2024 StarFive Technology Co., Ltd.
> + * Author: Alex Soo <yuklin.soo at starfivetech.com>

Shouldn't this person be in the Signed-off-by?

I guess it's not legally necessary but feels appropriate.

> +static struct config_reg_layout_desc jhb100_sys0_pinctrl_crl_desc[] = {
> +       {
> +               .pin_start                      = 0,
> +               .pin_cnt                        = 4,
> +               .drive_strength_2bit            = { .shift = 0, .width = 2 },
> +               .input_enable                   = { .shift = 2, .width = 1 },
> +               .pull_down                      = { .shift = 3, .width = 1 },
> +               .pull_up                        = { .shift = 4, .width = 1 },
> +               .slew_rate                      = { .shift = 5, .width = 1 },
> +               .schmitt_trigger_select         = { .shift = 6, .width = 1 },
> +               .reserved                       = { .shift = 7, .width = 8 },
> +               .debounce_width                 = { .shift = 15, .width = 17 },
> +       },
> +       {
> +               .pin_start                      = 4,
> +               .pin_cnt                        = 5,
> +               .schmitt_trigger_select         = { .shift = 0, .width = 1 },
> +               .reserved                       = { .shift = 1, .width = 31 },
> +       },
> +       {
> +               .pin_start                      = 9,
> +               .pin_cnt                        = 1,
> +               .drive_strength_2bit            = { .shift = 0, .width = 2 },
> +               .slew_rate                      = { .shift = 2, .width = 1 },
> +               .reserved                       = { .shift = 3, .width = 29 },
> +       },
> +       {
> +               .pin_start                      = 10,
> +               .pin_cnt                        = 1,
> +               .drive_strength_2bit            = { .shift = 0, .width = 2 },
> +               .input_enable                   = { .shift = 2, .width = 1 },
> +               .pull_down                      = { .shift = 3, .width = 1 },
> +               .pull_up                        = { .shift = 4, .width = 1 },
> +               .slew_rate                      = { .shift = 5, .width = 1 },
> +               .schmitt_trigger_select         = { .shift = 6, .width = 1 },
> +               .reserved                       = { .shift = 7, .width = 25 },
> +       },
> +       { 0xff },
> +};

Would it be appropriate to index the different register variants with
a enum with a good name so it is easy to understand which
variant each entry in the array is?

> +#include <linux/string.h>
> +#include <linux/sort.h>

Hm why... I guess I will see.

> +#define JHB100_DEBOUNCE_WIDTH_STAGES_MAX       0x1FFFFU

Is that a GENMASK(16,0)?

Since it seems to have something to do with bitfield widths.

> +/* i2c open-drain pull-up select */
> +#define JHB100_I2C_OPEN_DRAIN_PU_600_OHMS      0
> +#define JHB100_I2C_OPEN_DRAIN_PU_900_OHMS      1
> +#define JHB100_I2C_OPEN_DRAIN_PU_1200_OHMS     2
> +#define JHB100_I2C_OPEN_DRAIN_PU_2000_OHMS     3

Very nice and to the point! It's easy to read and understand drivers
that are writing things out explicitly like this!

> +#define JHB100_NR_GPIOS_PER_BANK               32
(...)
> +static inline struct jhb100_gpio_bank *jhb100_gc_to_bank(struct gpio_chip *gc)
> +{
> +       return container_of(gc, struct jhb100_gpio_bank, gc);
> +}
> +
> +static unsigned int jhb100_gpio_to_pin(struct gpio_chip *gc, unsigned int gpio)
> +{
> +       struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
> +
> +       return bank->id * JHB100_NR_GPIOS_PER_BANK + gpio;
> +}

This usually tells me that GPIO_GENERIC can be used but maybe
this has been discussed before...

> +static const struct pinctrl_ops jhb100_pinctrl_ops = {
> +       .get_groups_count = pinctrl_generic_get_group_count,
> +       .get_group_name   = pinctrl_generic_get_group_name,
> +       .get_group_pins   = pinctrl_generic_get_group_pins,
> +       .dt_node_to_map   = pinctrl_generic_pins_function_dt_node_to_map,
> +       .dt_free_map      = pinctrl_utils_free_map,
> +};

Nice use of the generic helpers!

> +static void jhb100_set_gpioval(struct jhb100_pinctrl *sfp, unsigned int pin,
> +                              unsigned int val)
> +{
> +       const struct jhb100_pinctrl_domain_info *info = sfp->info;
> +       unsigned int offset = 4 * (pin / 32);
> +       unsigned int shift = 1 * (pin % 32);
> +       unsigned int fs_offset = 4 * (pin / 16);
> +       unsigned int fs_shift = 2 * (pin % 16);
> +       u32 func_sel_mask;
> +       u32 dout, doen, fs;
> +       void __iomem *reg_gpio_o;
> +       void __iomem *reg_gpio_oen;
> +       void __iomem *reg_gpio_func_sel;
> +       unsigned long flags;
> +
> +       reg_gpio_o = sfp->base + info->regs->output + offset;
> +       reg_gpio_oen = sfp->base + info->regs->output_en + offset;
> +       reg_gpio_func_sel = sfp->base + info->regs->func_sel.reg + fs_offset;

The part from here:

> +       func_sel_mask = GENMASK(info->regs->func_sel.width_per_pin - 1, 0) << fs_shift;
(...)
> +
> +       raw_spin_lock_irqsave(&sfp->lock, flags);
> +       fs = readl_relaxed(reg_gpio_func_sel);
> +       if (fs & func_sel_mask) {
> +               fs &= ~func_sel_mask;
> +               writel_relaxed(fs, reg_gpio_func_sel);
> +       }

..to here seems to reimplement the shortcut
.gpio_request_enable() in struct pinmux_ops.

Then this:

> +       dout = val << shift;
> +       doen = 0;

> +       dout |= readl_relaxed(reg_gpio_o) & ~BIT(shift);
> +       writel_relaxed(dout, reg_gpio_o);
> +       doen |= readl_relaxed(reg_gpio_oen) & ~BIT(shift);
> +       writel_relaxed(doen, reg_gpio_oen);

Seems more like the actual code that should be here.

> +       raw_spin_unlock_irqrestore(&sfp->lock, flags);

Please use guards for these spinlocks. They make for less
bugs.

guard(raw_spinlock_irqsave)(&sfp->lock);

> +static const struct pinmux_ops jhb100_pinmux_ops = {
> +       .get_functions_count = pinmux_generic_get_function_count,
> +       .get_function_name   = pinmux_generic_get_function_name,
> +       .get_function_groups = pinmux_generic_get_function_groups,
> +       .set_mux             = jhb100_set_mux,
> +};

Implement .gpio_request_enable() (see above) and
.gpio_set_direction() see below.

Maybe also .gpio_disable_free() if you need to deconfigure
stuff when a pin is release from GPIO.

> +static const struct pinconf_ops jhb100_pinconf_ops = {
> +       .pin_config_get         = jhb100_pinconf_get,
> +       .pin_config_set         = jhb100_pinconf_set,
> +       .pin_config_group_get   = jhb100_pinconf_group_get,
> +       .pin_config_group_set   = jhb100_pinconf_group_set,
> +       .is_generic             = true,
> +};

Overall this looks nice, good use of the group config!

> +static int jhb100_gpio_get_direction(struct gpio_chip *gc,
> +                                    unsigned int gpio)
> +{
> +       struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
> +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> +       const struct jhb100_pinctrl_domain_info *info = sfp->info;
> +       unsigned int offset = 4 * bank->id;
> +       u32 doen;
> +       void __iomem *reg_gpio_oen;
> +
> +       reg_gpio_oen = sfp->base + info->regs->output_en + offset;
> +
> +       doen = (readl_relaxed(reg_gpio_oen) & BIT(gpio)) >> gpio;
> +
> +       return doen == GPOEN_ENABLE ? GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
> +}
> +
> +static int jhb100_gpio_direction_input(struct gpio_chip *gc,
> +                                      unsigned int gpio)
> +{
> +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> +       struct device *dev = sfp->dev;
> +       struct config_reg_layout_desc *crl_desc;
> +       unsigned int pin = jhb100_gpio_to_pin(gc, gpio);
> +
> +       crl_desc = get_crl_desc_by_pin(sfp, pin);
> +       if (!crl_desc) {
> +               dev_err(dev, "pin %d can't not found reg layout descriptor\n",
> +                       pin);
> +               return -EINVAL;
> +       }
> +
> +       jhb100_padcfg_rmw(sfp, pin,
> +                         RL_DESC_GENMASK(crl_desc, input_enable) |
> +                         RL_DESC_GENMASK(crl_desc, schmitt_trigger_select),
> +                         RL_DESC_GENMASK(crl_desc, input_enable) |
> +                         RL_DESC_GENMASK(crl_desc, schmitt_trigger_select));

Instead of doing these writes directly into the config registers, implement
.gpio_set_direction() in struct pinmux_ops and call the pinmux
generic back-end.

> +static int jhb100_gpio_direction_output(struct gpio_chip *gc,
> +                                       unsigned int gpio, int value)
> +{
> +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> +       struct device *dev = sfp->dev;
> +       struct config_reg_layout_desc *crl_desc;
> +       unsigned int pin = jhb100_gpio_to_pin(gc, gpio);
> +
> +       jhb100_set_one_pin_mux(sfp, pin, 0,
> +                              value ? GPOUT_HIGH : GPOUT_LOW);
> +
> +       crl_desc = get_crl_desc_by_pin(sfp, pin);
> +       if (!crl_desc) {
> +               dev_err(dev, "pin %d can't not found reg layout descriptor\n",
> +                       pin);
> +               return -EINVAL;
> +       }
> +
> +       jhb100_padcfg_rmw(sfp, pin,
> +                         RL_DESC_GENMASK(crl_desc, input_enable) |
> +                         RL_DESC_GENMASK(crl_desc, schmitt_trigger_select) |
> +                         RL_DESC_GENMASK(crl_desc, pull_down) |
> +                         RL_DESC_GENMASK(crl_desc, pull_up),
> +                         0);

Dito.

> +static int jhb100_gpio_get(struct gpio_chip *gc, unsigned int gpio)
> +{
> +       struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
> +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> +       const struct jhb100_pinctrl_domain_info *info = sfp->info;
> +       unsigned int offset = 4 * bank->id;
> +       u32 doen = 0;
> +       void __iomem *reg_gpio_oen;
> +       void __iomem *reg;
> +       unsigned long flags;
> +
> +       reg_gpio_oen = sfp->base + info->regs->output_en + offset;
> +       reg = sfp->base + info->regs->gpio_status + offset;
> +
> +       raw_spin_lock_irqsave(&sfp->lock, flags);
> +       doen = readl_relaxed(reg_gpio_oen) | BIT(gpio);
> +       writel_relaxed(doen, reg_gpio_oen);
> +       raw_spin_unlock_irqrestore(&sfp->lock, flags);

Why *on* *earth* are you read-modify-writing the output enable
register in the *get* function? Is this a copy-on-paste error??

> +       return !!(readl_relaxed(reg) & BIT(gpio % 32));

Also you never actuall read reg .... ehhhh this is a glaring bug.

> +static int jhb100_gpio_set(struct gpio_chip *gc, unsigned int gpio, int value)
> +{
> +       struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
> +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> +       const struct jhb100_pinctrl_domain_info *info = sfp->info;
> +       unsigned int offset = 4 * bank->id;
> +       void __iomem *reg_dout;
> +       u32 dout;
> +       unsigned long flags;
> +
> +       reg_dout = sfp->base + info->regs->output + offset;
> +       dout = (value ? GPOUT_HIGH : GPOUT_LOW) << gpio;
> +
> +       raw_spin_lock_irqsave(&sfp->lock, flags);
> +       dout |= readl_relaxed(reg_dout) & ~BIT(gpio);
> +       writel_relaxed(dout, reg_dout);
> +       raw_spin_unlock_irqrestore(&sfp->lock, flags);
> +
> +       return 0;
> +}

This looks right, did you only test output and not input..?

> +static const struct irq_chip jhb100_irq_chip = {
> +       .irq_ack        = jhb100_irq_ack,
> +       .irq_mask       = jhb100_irq_mask,
> +       .irq_mask_ack   = jhb100_irq_mask_ack,
> +       .irq_unmask     = jhb100_irq_unmask,
> +       .irq_set_type   = jhb100_irq_set_type,
> +       .irq_set_wake   = jhb100_irq_set_wake,
> +       .irq_print_chip = jhb100_irq_print_chip,
> +       .flags          = IRQCHIP_SET_TYPE_MASKED |
> +                         IRQCHIP_IMMUTABLE |
> +                         IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND |
> +                         IRQCHIP_MASK_ON_SUSPEND |
> +                         IRQCHIP_SKIP_SET_WAKE,
> +       GPIOCHIP_IRQ_RESOURCE_HELPERS,
> +};

The irqchip looks good!

> +static int field_compare(const void *a, const void *b)
> +{
> +       const struct field_info *fa = (const struct field_info *)a;
> +       const struct field_info *fb = (const struct field_info *)b;
> +
> +       if (fa->shift < fb->shift)
> +               return -1;
> +
> +       if (fa->shift > fb->shift)
> +               return 1;
> +
> +       return 0;
> +}

Are you sure the kernel doesn't already have a helper like this...

> +       sfp->num_banks = DIV_ROUND_UP(sfp->ngpios, JHB100_NR_GPIOS_PER_BANK);
> +
> +       for (unsigned int i = 0; i < sfp->num_banks; i++) {
> +               if (sfp->ngpios > (i + 1) * JHB100_NR_GPIOS_PER_BANK)
> +                       sfp->banks[i].gc.ngpio = (i + 1) * JHB100_NR_GPIOS_PER_BANK;
> +               else
> +                       sfp->banks[i].gc.ngpio = sfp->ngpios - i * JHB100_NR_GPIOS_PER_BANK;

This looks completely bananas, shouldn't this be simply:

sfp->banks[i].gc.ngpio = JHB100_NR_GPIOS_PER_BANK;

???

What is getting assigned to ngpios looks like a gpiochip base, and have
all the signs of a real bad AI hallucination.

> +
> +               sfp->banks[i].id = i;
> +
> +               sfp->banks[i].gc.parent = dev;
> +               sfp->banks[i].gc.label = dev_name(dev);
> +               sfp->banks[i].gc.owner = THIS_MODULE;
> +               sfp->banks[i].gc.request = pinctrl_gpio_request;

Use
gpiochip_generic_request

> +               sfp->banks[i].gc.free = pinctrl_gpio_free;

Use
gpiochip_generic_free

These calls will do what you want, and also check that the
right gpio ranges are available.

Make sure you add GPIO ranges (the mapping between pin control
pins and corresponding GPIO offsets) for this to work properly.

I'm pretty sure you can have a generic pin config backend as well.

sfp->banks[i].gc.set_config = gpiochip_generic_config;

This will make config calls to the gpiochip call into the pinctrl
backend = what you want.

> +               sfp->banks[i].gc.get_direction = jhb100_gpio_get_direction;
> +               sfp->banks[i].gc.direction_input = jhb100_gpio_direction_input;
> +               sfp->banks[i].gc.direction_output = jhb100_gpio_direction_output;
> +               sfp->banks[i].gc.get = jhb100_gpio_get;
> +               sfp->banks[i].gc.set = jhb100_gpio_set;
> +               sfp->banks[i].gc.set_config = gpiochip_generic_config;
> +               sfp->banks[i].gc.base = -1;
> +               sfp->banks[i].gc.of_gpio_n_cells = 3;
> +               sfp->banks[i].gc.of_node_instance_match = starfive_of_node_instance_match;

Since you have a threecell scheme with 32 gpios
(JHB100_NR_GPIOS_PER_BANK)  per instance (right? the ngpios
code above made me really confused....)
you should be able so select GPIO_GENERIC,
#include <linux/gpio/generic.h> and use
the generic GPIO pretty much the same way
drivers/gpio/gpio-spacemit-k1.c does it, check that driver
out (especially spacemit_gpio_add_bank()).

Yours,
Linus Walleij


From aleksa.paunovic at htecgroup.com  Thu Jun 11 04:51:14 2026
From: aleksa.paunovic at htecgroup.com (Aleksa Paunovic)
Date: Thu, 11 Jun 2026 11:51:14 +0000
Subject: [PATCH v8 1/3] dt-bindings: timer: mips,p8700-gcru
In-Reply-To: <a2b5c9b4-5fc0-4507-a221-8695ed9574d8@kernel.org>
References: <a2b5c9b4-5fc0-4507-a221-8695ed9574d8@kernel.org>
Message-ID: <7027c47b-7890-4850-976f-50a1c8cfbeca@htecgroup.com>

On 6/11/26 09:50, Krzysztof Kozlowski wrote:
> On 11/06/2026 09:39, Aleksa Paunovic wrote:
>> Hi Krzysztof,
>>
>>
>> On 6/11/26 08:54, Krzysztof Kozlowski wrote:
>>> On 11/06/2026 08:51, Krzysztof Kozlowski wrote:
>>>> On 10/06/2026 10:22, Aleksa Paunovic via B4 Relay wrote:
>>>>> From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
>>>>>
>>>>> Add dt-bindings for the GCR.U memory mapped timer device for RISC-V
>>>>> platforms. The GCR.U memory region contains shadow copies of the RISC-V
>>>>> mtime register and the hrtime Global Configuration Register.
>>>>>
>>>>> Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
>>>> You keep ignoring reviews you received (14th May!) and sending same mistake.
>>>>
>>>> Can you address the emails?
>> I wasn't really sure what the etiquette was for replying to Sashiko reviews, so I decided to
>> address the comments for other patches and send a v8 without replying.
>>
>> As for this patch, the GCR.U itself does start at 0x7F000, but the first
>> actual register (mtime) is at 0x7F050 [1].
>> I'm not seeing any warnings when running dt_binding_check.
> It's still a warning which you can easily reproduce on W=1 on dts. You
> CANNOT have mismatch. If block starts at 0x7f000, first register CANNOT
> start at different address or it completely does not matter where the
> register is. It's contradictory. The block start address defines
> where... does it start.

You are right: I just checked by manually running dtc and the warning's clearly there.
Will fix the alignment in v9. Thanks!
?

Best regards,
Aleksa?

From baoquan.he at linux.dev  Thu Jun 11 05:03:53 2026
From: baoquan.he at linux.dev (Baoquan He)
Date: Thu, 11 Jun 2026 20:03:53 +0800
Subject: [PATCH v3 00/11] kdump: reduce vmcore size and capture time
In-Reply-To: <a3993db0-6975-455d-9674-4fd7cfcf80fc@gmail.com>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <7ed207fa-4c86-426a-8570-495902ce04c3@gmail.com>
 <a3993db0-6975-455d-9674-4fd7cfcf80fc@gmail.com>
Message-ID: <aiqkKe1gXPZ5LZ7t@MiWiFi-R3L-srv>

On 06/11/26 at 11:09am, Wandun wrote:
> 
> 
> On 6/11/26 10:09, Wandun wrote:
> > 
> > 
> > On 5/27/26 11:29, Wandun Chen wrote:
> >> From: Wandun Chen <chenwandun at lixiang.com>
> >>
> >> On SoCs that carve out large firmware-owned reserved memory (GPU
> >> firmware, DSP, modem, camera ISP, NPU, ...), kdump currently dumps
> >> those carveouts as part of system RAM even though their contents are
> >> firmware state that is not useful for kernel crash analysis.
> >>
> >> This series introduces an opt-in 'dumpable' flag [1] on struct
> >> reserved_mem and uses it to filter the elfcorehdr PT_LOAD ranges on
> >> DT-based architectures (arm64, riscv, loongarch). By default reserved
> >> regions are treated as non-dumpable; CMA regions are explicitly opted
> >> in because their pages are returned to the buddy allocator and may
> >> carry key crash-analysis data.
> >>
> >> The series is organized as follows:
> >> Patches 1-3: Pre-existing fixes and a small prep change.
> >> Patches 4-5: Restructure to allow appending /memreserve/ entries.
> >> Patches 6-7: Add a dumpable flag and append /memreserve/ entries.
> >> Patch 8: Add generic kdump helpers.
> >> Patches 9-11: Wire the helpers into arm64, riscv and loongarch kdump
> >> ?????????????? elfcorehdr preparation.
> > Hi,
> > 
> > Gentle ping on this series.
> > 
> > Status summary:
> > -patch 03: respun separately per Rob's suggestion, picked up for 7.2
> > -patch 06: Acked-by: Marek Szyprowski -patch 09: Acked-by: Will Deacon
> > The remaining patches (01, 02, 04, 05, 07, 08, 10, 11) are still
> > awaiting review. your feedback would be greately appreciated. I know we
> > are at the end of 7.1 -rc cycle, I don't want to rush this series, just
> > collecting more feedback, and will send next version based on 7.2-rc1.
> > If spliting the series into smaller logical group would make review
> > easier, please let me know. Best regards, Wandun
> 
> Apologies for the formatting issue in my previous email.
> Here is the properly formatted version.
> 
> Gentle ping on this series.

Thanks for the effort, the overral looks good to me at 1st glance. I will
check if there's concern on generic part. And meanwhile, I am wondering
if there's any chance x86 or other ARCH-es w/o OF/FDT can also choose to
not dump some areas, e.g GPU stolen memory. Surely, that's another story.

> 
> Status summary:
> - patch 03: respun separately per Rob's suggestion, picked up for 7.2
> - patch 06: Acked-by: Marek Szyprowski
> - patch 09: Acked-by: Will Deacon
> 
> The remaining patches (01, 02, 04, 05, 07, 08, 10, 11) are still
> awaiting review. Your feedback would be greatly appreciated.
> 
> I know we are at the end of 7.1-rc cycle, I don't want to rush this
> series, just collecting more feedback, and will send next version based
> on 7.2-rc1.
> 
> If splitting the series into smaller logical groups would make review
> easier, please let me know.
> 
> Best regards,
> Wandun
> 
> 
> >>
> >> v2 --> v3:
> >> 1. Fix out-of-bounds issue if device tree lacks /reserved-memory node.[2]
> >> 2. Fix UAF issue when alloc_reserved_mem_array() fails.
> >> 3. Add some prepare patches.
> >>
> >> v1 --> v2:
> >> 1. v1 added an opt-out DT property ('linux,no-dump'). Per Rob's
> >> ??? feedback [1], v2 drop that property and exclude reserve memory
> >> ??? by default.
> >> 2. Split some prepared patches from the original patches.
> >> 3. Address coding-style comments on patch 5 from Rob.
> >>
> >> [1] https://lore.kernel.org/lkml/20260506144542.GA2072596-
> >> robh at kernel.org/
> >> [2] https://sashiko.dev/#/patchset/20260520091844.592753-1-
> >> chenwandun%40lixiang.com?part=4
> >>
> >> Wandun Chen (11):
> >> ?? of: reserved_mem: handle NULL name in of_reserved_mem_lookup()
> >> ?? kexec/crash: provide crash_exclude_mem_range() stub when
> >> ???? CONFIG_CRASH_DUMP=n
> >> ?? of: reserved_mem: avoid post-init UAF when alloc_reserved_mem_array()
> >> ???? fails
> >> ?? of: reserved_mem: zero total_reserved_mem_cnt if no valid
> >> ???? /reserved-memory entry
> >> ?? of: reserved_mem: split alloc_reserved_mem_array() from
> >> ???? fdt_scan_reserved_mem_late()
> >> ?? of: reserved_mem: add dumpable flag to opt-in vmcore
> >> ?? of: reserved_mem: save /memreserve/ entries into the reserved_mem
> >> ???? array
> >> ?? of: reserved_mem: add kdump helpers to exclude non-dumpable regions
> >> ?? arm64: kdump: exclude non-dumpable reserved memory regions from vmcore
> >> ?? riscv: kdump: exclude non-dumpable reserved memory regions from vmcore
> >> ?? loongarch: kdump: exclude non-dumpable reserved memory regions from
> >> ???? vmcore
> >>
> >> ? arch/arm64/kernel/machine_kexec_file.c???? |?? 6 ++
> >> ? arch/loongarch/kernel/machine_kexec_file.c |?? 6 ++
> >> ? arch/riscv/kernel/machine_kexec_file.c???? |?? 4 +
> >> ? drivers/of/fdt.c?????????????????????????? |? 11 +-
> >> ? drivers/of/of_private.h??????????????????? |?? 3 +
> >> ? drivers/of/of_reserved_mem.c?????????????? | 117 +++++++++++++++++++--
> >> ? include/linux/crash_core.h???????????????? |?? 6 ++
> >> ? include/linux/of_reserved_mem.h??????????? |? 15 +++
> >> ? kernel/dma/contiguous.c??????????????????? |?? 1 +
> >> ? 9 files changed, 157 insertions(+), 12 deletions(-)
> >>
> > 
> 


From docular.xu at gmail.com  Thu Jun 11 06:17:28 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 09:17:28 -0400
Subject: [PATCH v3] riscv: dts: spacemit: Use symbolic PDMA request numbers
 on K1
Message-ID: <20260611-b4-k1-pdma-req-macros-v3-1-ae8416052571@gmail.com>

Add a local DTS header, k1-pdma.h, that gives symbolic names to the K1
PDMA request numbers. These request numbers are hardware-fixed; their
allocation can be found in K1 manual.

Replace the hard-coded numbers in the SPI3 "dmas" property with the
K1_PDMA_SPI3_RX/TX macros.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
Add a local DTS header naming the K1 PDMA request lines and convert the
current user (the K1 SPI3 node) to the new K1_PDMA_* macros. The request
numbers come from the SpacemiT K1 User Manual [1], Chapter 9.4.3 DMA
Connectivity & Assignments.

[1]: https://www.spacemit.com/community/document/info?lang=en&nodepath=hardware/key_stone/k1/k1_docs/k1_usermanual/9.Top_System.md

Changes in v3:
- Move the request-number macros from include/dt-bindings/dma/ to a local
  DTS header arch/riscv/boot/dts/spacemit/k1-pdma.h (Conor).
- Squash the header and its user into a single patch.
- Link to v2: https://patch.msgid.link/20260609-b4-k1-pdma-req-macros-v2-0-5d5d7b997b54 at gmail.com

Changes in v2:
- Drop the #dma-cells description change in spacemit,k1-pdma.yaml; the request
  numbers are hardware-fixed and unused by the driver (Conor)
- Link to v1: https://patch.msgid.link/20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c at gmail.com

BR,
Guodong Xu
---
 arch/riscv/boot/dts/spacemit/k1-pdma.h | 56 ++++++++++++++++++++++++++++++++++
 arch/riscv/boot/dts/spacemit/k1.dtsi   |  4 ++-
 2 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/boot/dts/spacemit/k1-pdma.h b/arch/riscv/boot/dts/spacemit/k1-pdma.h
new file mode 100644
index 0000000000000..65112d5847add
--- /dev/null
+++ b/arch/riscv/boot/dts/spacemit/k1-pdma.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
+/*
+ * This header provides DMA request number for non-secure peripherals of
+ * SpacemiT K1 PDMA.
+ *
+ * Copyright (c) 2026 Guodong Xu <docular.xu at gmail.com>
+ */
+
+#ifndef _DTS_SPACEMIT_K1_PDMA_H
+#define _DTS_SPACEMIT_K1_PDMA_H
+
+#define K1_PDMA_UART0_TX	3
+#define K1_PDMA_UART0_RX	4
+#define K1_PDMA_UART2_TX	5
+#define K1_PDMA_UART2_RX	6
+#define K1_PDMA_UART3_TX	7
+#define K1_PDMA_UART3_RX	8
+#define K1_PDMA_UART4_TX	9
+#define K1_PDMA_UART4_RX	10
+#define K1_PDMA_I2C0_TX		11
+#define K1_PDMA_I2C0_RX		12
+#define K1_PDMA_I2C1_TX		13
+#define K1_PDMA_I2C1_RX		14
+#define K1_PDMA_I2C2_TX		15
+#define K1_PDMA_I2C2_RX		16
+#define K1_PDMA_I2C4_TX		17
+#define K1_PDMA_I2C4_RX		18
+#define K1_PDMA_SPI3_TX		19
+#define K1_PDMA_SPI3_RX		20
+#define K1_PDMA_I2S0_TX		21
+#define K1_PDMA_I2S0_RX		22
+#define K1_PDMA_I2S1_TX		23
+#define K1_PDMA_I2S1_RX		24
+#define K1_PDMA_UART5_TX	25
+#define K1_PDMA_UART5_RX	26
+#define K1_PDMA_UART6_TX	27
+#define K1_PDMA_UART6_RX	28
+#define K1_PDMA_UART7_TX	29
+#define K1_PDMA_UART7_RX	30
+#define K1_PDMA_UART8_TX	31
+#define K1_PDMA_UART8_RX	32
+#define K1_PDMA_UART9_TX	33
+#define K1_PDMA_UART9_RX	34
+#define K1_PDMA_I2C5_TX		35
+#define K1_PDMA_I2C5_RX		36
+#define K1_PDMA_I2C6_TX		37
+#define K1_PDMA_I2C6_RX		38
+#define K1_PDMA_I2C7_TX		39
+#define K1_PDMA_I2C7_RX		40
+#define K1_PDMA_I2C8_TX		41
+#define K1_PDMA_I2C8_RX		42
+#define K1_PDMA_CAN0_RX		43
+#define K1_PDMA_QSPI_RX		44
+#define K1_PDMA_QSPI_TX		45
+
+#endif /* _DTS_SPACEMIT_K1_PDMA_H */
diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index 08a0f28d011fe..7d414e15d2cc2 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -6,6 +6,8 @@
 #include <dt-bindings/clock/spacemit,k1-syscon.h>
 #include <dt-bindings/phy/phy.h>
 
+#include "k1-pdma.h"
+
 /dts-v1/;
 / {
 	#address-cells = <2>;
@@ -1094,7 +1096,7 @@ spi3: spi at d401c000 {
 				clock-names = "core", "bus";
 				resets = <&syscon_apbc RESET_SSP3>;
 				interrupts = <55>;
-				dmas = <&pdma 20>, <&pdma 19>;
+				dmas = <&pdma K1_PDMA_SPI3_RX>, <&pdma K1_PDMA_SPI3_TX>;
 				dma-names = "rx", "tx";
 				status = "disabled";
 			};

---
base-commit: 793cc54475b49b5b558902b5c13e4bfe66530a50
change-id: 20260607-b4-k1-pdma-req-macros-8d276d0126df

Best regards,
--  
Guodong Xu <docular.xu at gmail.com>



From ruanjinjie at huawei.com  Thu Jun 11 06:38:07 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 11 Jun 2026 21:38:07 +0800
Subject: [PATCH RFC 1/3] cpu/hotplug: Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST
In-Reply-To: <20260611133809.3854977-1-ruanjinjie@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
Message-ID: <20260611133809.3854977-2-ruanjinjie@huawei.com>

During parallel CPU bringup, x86 requires primary SMT threads to boot
first to avoid siblings stopping during microcode updates. This constraint
is architecture-specific and unnecessary for other platforms
like arm64.

Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST to decouple this constraint.
Platforms requiring this temporal order (e.g., x86) can select it
in Kconfig. Other architectures (e.g., arm64) can leave it unselected
to entirely bypass the SMT branch via the preprocessor.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/Kconfig       | 4 ++++
 arch/mips/Kconfig  | 1 +
 arch/riscv/Kconfig | 1 +
 arch/x86/Kconfig   | 1 +
 kernel/cpu.c       | 6 +++++-
 5 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index e86880045158..0365d2df2659 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -102,6 +102,10 @@ config HOTPLUG_PARALLEL
 	bool
 	select HOTPLUG_SPLIT_STARTUP
 
+config PARALLEL_SMT_PRIMARY_FIRST
+	bool
+	depends on HOTPLUG_PARALLEL
+
 config GENERIC_IRQ_ENTRY
 	bool
 
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 4364f3dba688..84e11ac0cf71 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -642,6 +642,7 @@ config EYEQ
 	select MIPS_CPU_SCACHE
 	select MIPS_GIC
 	select MIPS_L1_CACHE_SHIFT_7
+	select PARALLEL_SMT_PRIMARY_FIRST if HOTPLUG_PARALLEL
 	select PCI_DRIVERS_GENERIC
 	select SMP_UP if SMP
 	select SWAP_IO_SPACE
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index d235396c4514..0cc49aecc841 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -210,6 +210,7 @@ config RISCV
 	select OF
 	select OF_EARLY_FLATTREE
 	select OF_IRQ
+	select PARALLEL_SMT_PRIMARY_FIRST if HOTPLUG_PARALLEL
 	select PCI_DOMAINS_GENERIC if PCI
 	select PCI_ECAM if (ACPI && PCI)
 	select PCI_MSI if PCI
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f3f7cb01d69d..3ad4115ad051 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -314,6 +314,7 @@ config X86
 	select NEED_PER_CPU_PAGE_FIRST_CHUNK
 	select NEED_SG_DMA_LENGTH
 	select NUMA_MEMBLKS			if NUMA
+	select PARALLEL_SMT_PRIMARY_FIRST	if HOTPLUG_PARALLEL
 	select PCI_DOMAINS			if PCI
 	select PCI_LOCKLESS_CONFIG		if PCI
 	select PERF_EVENTS
diff --git a/kernel/cpu.c b/kernel/cpu.c
index bc4f7a9ba64e..7ef8cdf4d239 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1792,6 +1792,7 @@ static int __init parallel_bringup_parse_param(char *arg)
 }
 early_param("cpuhp.parallel", parallel_bringup_parse_param);
 
+#ifdef CONFIG_PARALLEL_SMT_PRIMARY_FIRST
 #ifdef CONFIG_HOTPLUG_SMT
 static inline bool cpuhp_smt_aware(void)
 {
@@ -1811,7 +1812,8 @@ static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
 {
 	return cpu_none_mask;
 }
-#endif
+#endif /* CONFIG_HOTPLUG_SMT */
+#endif /* CONFIG_PARALLEL_SMT_PRIMARY_FIRST */
 
 bool __weak arch_cpuhp_init_parallel_bringup(void)
 {
@@ -1837,6 +1839,7 @@ static bool __init cpuhp_bringup_cpus_parallel(unsigned int ncpus)
 	if (!__cpuhp_parallel_bringup)
 		return false;
 
+#ifdef CONFIG_PARALLEL_SMT_PRIMARY_FIRST
 	if (cpuhp_smt_aware()) {
 		const struct cpumask *pmask = cpuhp_get_primary_thread_mask();
 		static struct cpumask tmp_mask __initdata;
@@ -1857,6 +1860,7 @@ static bool __init cpuhp_bringup_cpus_parallel(unsigned int ncpus)
 		cpumask_andnot(&tmp_mask, mask, pmask);
 		mask = &tmp_mask;
 	}
+#endif /* CONFIG_PARALLEL_SMT_PRIMARY_FIRST */
 
 	/* Bring the not-yet started CPUs up */
 	cpuhp_bringup_mask(mask, ncpus, CPUHP_BP_KICK_AP);
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Jun 11 06:38:06 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 11 Jun 2026 21:38:06 +0800
Subject: [PATCH RFC 0/3] arm64: Add HOTPLUG_PARALLEL support for secondary CPUs
Message-ID: <20260611133809.3854977-1-ruanjinjie@huawei.com>

Support for parallel secondary CPU bringup is already utilized by x86,
MIPS, and RISC-V. This patch brings this capability to the arm64
architecture.

Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST to avoid primary SMT threads
to boot first constraint.

And Add a 'cpu' parameter to update_cpu_boot_status() to allow updating the
boot status at a per-CPU granularity during parallel bringup.

Rework the global `secondary_data` accessed during early boot into
a per-CPU array. This array maps logical CPU IDs to MPIDR_EL1 values,
enabling the early boot code in head.S to resolve each secondary CPU's
logical ID concurrently.

Jinjie Ruan (3):
  cpu/hotplug: Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST
  arm64: smp: Pass CPU ID to update_cpu_boot_status()
  arm64: Add HOTPLUG_PARALLEL support for secondary CPUs

 arch/Kconfig                   |  4 ++++
 arch/arm64/Kconfig             |  1 +
 arch/arm64/include/asm/smp.h   | 14 +++++++++++---
 arch/arm64/kernel/cpufeature.c |  2 +-
 arch/arm64/kernel/head.S       | 23 ++++++++++++++++++++++
 arch/arm64/kernel/smp.c        | 35 ++++++++++++++++++++++++++++++----
 arch/arm64/mm/context.c        |  2 +-
 arch/mips/Kconfig              |  1 +
 arch/riscv/Kconfig             |  1 +
 arch/x86/Kconfig               |  1 +
 kernel/cpu.c                   |  6 +++++-
 11 files changed, 80 insertions(+), 10 deletions(-)

-- 
2.34.1



From ruanjinjie at huawei.com  Thu Jun 11 06:38:09 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 11 Jun 2026 21:38:09 +0800
Subject: [PATCH RFC 3/3] arm64: Add HOTPLUG_PARALLEL support for secondary CPUs
In-Reply-To: <20260611133809.3854977-1-ruanjinjie@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
Message-ID: <20260611133809.3854977-4-ruanjinjie@huawei.com>

Support for parallel secondary CPU bringup is already utilized by x86,
MIPS, and RISC-V. This patch brings this capability to the arm64
architecture.

Rework the global `secondary_data` accessed during early boot into
a per-CPU array. This array maps logical CPU IDs to MPIDR_EL1 values,
enabling the early boot code in head.S to resolve each secondary CPU's
logical ID concurrently.

To fully enable HOTPLUG_PARALLEL, this patch implements:
1) An arm64-specific arch_cpuhp_kick_ap_alive() handler.
2) Callbacks to cpuhp_ap_sync_alive() inside secondary_start_kernel().

Successfully tested on QEMU ARM64 virt machine (KVM on, 128 vCPUs).

|     test kernel	   | secondary CPUs boot time |
|  ---------------------   |	--------------------  |
|   Without this patch     |		155.672	      |
|   cpuhp.parallel=0	   |		62.897	      |
|   cpuhp.parallel=1	   |		166.703	      |

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/Kconfig           |  1 +
 arch/arm64/include/asm/smp.h |  8 ++++++++
 arch/arm64/kernel/head.S     | 23 +++++++++++++++++++++++
 arch/arm64/kernel/smp.c      | 27 +++++++++++++++++++++++++++
 4 files changed, 59 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9091c67e1cc2..8735e9d8ed13 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -113,6 +113,7 @@ config ARM64
 	select CPUMASK_OFFSTACK if NR_CPUS > 256
 	select DCACHE_WORD_ACCESS
 	select HAVE_EXTRA_IPI_TRACEPOINTS
+	select HOTPLUG_PARALLEL if SMP && HOTPLUG_CPU
 	select DYNAMIC_FTRACE if FUNCTION_TRACER
 	select DMA_BOUNCE_UNALIGNED_KMALLOC
 	select DMA_DIRECT_REMAP
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index e2151a01731f..c39d4c0f8a37 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -92,6 +92,10 @@ struct secondary_data {
 	long status;
 };
 
+#ifdef CONFIG_HOTPLUG_PARALLEL
+extern struct secondary_data cpu_boot_data[NR_CPUS];
+#endif
+
 extern struct secondary_data secondary_data;
 extern long __early_cpu_boot_status;
 extern void secondary_entry(void);
@@ -124,7 +128,11 @@ static inline void __noreturn cpu_park_loop(void)
 
 static inline void update_cpu_boot_status(unsigned int cpu, int val)
 {
+#ifdef CONFIG_HOTPLUG_PARALLEL
+	WRITE_ONCE(cpu_boot_data[cpu].status, val);
+#else
 	WRITE_ONCE(secondary_data.status, val);
+#endif
 	/* Ensure the visibility of the status update */
 	dsb(ishst);
 }
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 87a822e5c4ca..8f6c1c5e66d2 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -12,6 +12,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <linux/pgtable.h>
+#include <linux/threads.h>
 
 #include <asm/asm_pointer_auth.h>
 #include <asm/assembler.h>
@@ -391,7 +392,29 @@ SYM_FUNC_START_LOCAL(__secondary_switched)
 	msr	vbar_el1, x5
 	isb
 
+#ifdef CONFIG_HOTPLUG_PARALLEL
+	mrs	x0, mpidr_el1
+	mov_q	x1, MPIDR_HWID_BITMASK
+	and	x0, x0, x1
+
+	adr_l	x1, __mpidr_to_cpuid_table
+	mov	x19, #0
+.Lfind_cpuid:
+	ldr	x3, [x1, x19, lsl #3]
+	cmp	x3, x0
+	b.eq	.Lfound_cpuid
+	add	x19, x19, #1
+	cmp	x19, #NR_CPUS
+	b.ne	.Lfind_cpuid
+	b	.
+
+.Lfound_cpuid:
+	adr_l	x0, cpu_boot_data
+	lsl	x3, x19, #4
+	add	x0, x0, x3
+#else
 	adr_l	x0, secondary_data
+#endif
 	ldr	x2, [x0, #CPU_BOOT_TASK]
 	cbz	x2, __secondary_too_slow
 
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 6bc90ee4820a..c909bf1c5119 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -61,6 +61,12 @@
  * where to place its SVC stack
  */
 struct secondary_data secondary_data;
+
+#ifdef CONFIG_HOTPLUG_PARALLEL
+struct secondary_data cpu_boot_data[NR_CPUS] ____cacheline_aligned __ro_after_init;
+unsigned long __mpidr_to_cpuid_table[NR_CPUS] ____cacheline_aligned;
+#endif
+
 /* Number of CPUs which aren't online, but looping in kernel text. */
 static int cpus_stuck_in_kernel;
 
@@ -106,8 +112,19 @@ static int boot_secondary(unsigned int cpu, struct task_struct *idle)
 	return -EOPNOTSUPP;
 }
 
+#ifndef CONFIG_HOTPLUG_PARALLEL
 static DECLARE_COMPLETION(cpu_running);
+#endif
+
+#ifdef CONFIG_HOTPLUG_PARALLEL
+int arch_cpuhp_kick_ap_alive(unsigned int cpu, struct task_struct *tidle)
+{
+	cpu_boot_data[cpu].task = tidle;
+	update_cpu_boot_status(cpu, CPU_MMU_OFF);
 
+	return boot_secondary(cpu, tidle);
+}
+#else
 int __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
 	int ret;
@@ -172,6 +189,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
 
 	return -EIO;
 }
+#endif /* CONFIG_HOTPLUG_PARALLEL */
 
 static void init_gic_priority_masking(void)
 {
@@ -206,6 +224,10 @@ asmlinkage notrace void secondary_start_kernel(void)
 	mmgrab(mm);
 	current->active_mm = mm;
 
+#ifdef CONFIG_HOTPLUG_PARALLEL
+	cpuhp_ap_sync_alive();
+#endif
+
 	/*
 	 * TTBR0 is only used for the identity mapping at this stage. Make it
 	 * point to zero page to avoid speculatively fetching new entries.
@@ -254,7 +276,9 @@ asmlinkage notrace void secondary_start_kernel(void)
 					 read_cpuid_id());
 	update_cpu_boot_status(cpu, CPU_BOOT_SUCCESS);
 	set_cpu_online(cpu, true);
+#ifndef CONFIG_HOTPLUG_PARALLEL
 	complete(&cpu_running);
+#endif
 
 	/*
 	 * Secondary CPUs enter the kernel with all DAIF exceptions masked.
@@ -762,6 +786,9 @@ void __init smp_init_cpus(void)
 	 */
 	for (i = 1; i < nr_cpu_ids; i++) {
 		if (cpu_logical_map(i) != INVALID_HWID) {
+#ifdef CONFIG_HOTPLUG_PARALLEL
+			__mpidr_to_cpuid_table[i] = cpu_logical_map(i);
+#endif
 			if (smp_cpu_setup(i))
 				set_cpu_logical_map(i, INVALID_HWID);
 		}
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Jun 11 06:38:08 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 11 Jun 2026 21:38:08 +0800
Subject: [PATCH RFC 2/3] arm64: smp: Pass CPU ID to update_cpu_boot_status()
In-Reply-To: <20260611133809.3854977-1-ruanjinjie@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
Message-ID: <20260611133809.3854977-3-ruanjinjie@huawei.com>

To support CONFIG_HOTPLUG_PARALLEL, the CPU boot status tracking must
be refactored from a single global variable (secondary_data.status)
to a per-CPU tracking structure to prevent multi-core race conditions.

Add a 'cpu' parameter to update_cpu_boot_status() and update all its
callsites to pass the corresponding CPU ID. This allows updating the
boot status at a per-CPU granularity during parallel bringup.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/smp.h   | 6 +++---
 arch/arm64/kernel/cpufeature.c | 2 +-
 arch/arm64/kernel/smp.c        | 8 ++++----
 arch/arm64/mm/context.c        | 2 +-
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 10ea4f543069..e2151a01731f 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -122,7 +122,7 @@ static inline void __noreturn cpu_park_loop(void)
 	}
 }
 
-static inline void update_cpu_boot_status(int val)
+static inline void update_cpu_boot_status(unsigned int cpu, int val)
 {
 	WRITE_ONCE(secondary_data.status, val);
 	/* Ensure the visibility of the status update */
@@ -134,9 +134,9 @@ static inline void update_cpu_boot_status(int val)
  * which calls for a kernel panic. Update the boot status and park the calling
  * CPU.
  */
-static inline void __noreturn cpu_panic_kernel(void)
+static inline void __noreturn cpu_panic_kernel(unsigned int cpu)
 {
-	update_cpu_boot_status(CPU_PANIC_KERNEL);
+	update_cpu_boot_status(cpu, CPU_PANIC_KERNEL);
 	cpu_park_loop();
 }
 
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 6d53bb15cf7b..0552202702bf 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -3674,7 +3674,7 @@ static void verify_local_cpu_caps(u16 scope_mask)
 			caps->desc, system_has_cap, cpu_has_cap);
 
 		if (cpucap_panic_on_conflict(caps))
-			cpu_panic_kernel();
+			cpu_panic_kernel(smp_processor_id());
 		else
 			cpu_die_early();
 	}
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 24f8448e1fbb..6bc90ee4820a 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -118,7 +118,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
 	 * page tables.
 	 */
 	secondary_data.task = idle;
-	update_cpu_boot_status(CPU_MMU_OFF);
+	update_cpu_boot_status(cpu, CPU_MMU_OFF);
 
 	/* Now bring the CPU into our world */
 	ret = boot_secondary(cpu, idle);
@@ -252,7 +252,7 @@ asmlinkage notrace void secondary_start_kernel(void)
 	pr_info("CPU%u: Booted secondary processor 0x%010lx [0x%08x]\n",
 					 cpu, (unsigned long)mpidr,
 					 read_cpuid_id());
-	update_cpu_boot_status(CPU_BOOT_SUCCESS);
+	update_cpu_boot_status(cpu, CPU_BOOT_SUCCESS);
 	set_cpu_online(cpu, true);
 	complete(&cpu_running);
 
@@ -411,11 +411,11 @@ void __noreturn cpu_die_early(void)
 	rcutree_report_cpu_dead();
 
 	if (IS_ENABLED(CONFIG_HOTPLUG_CPU)) {
-		update_cpu_boot_status(CPU_KILL_ME);
+		update_cpu_boot_status(cpu, CPU_KILL_ME);
 		__cpu_try_die(cpu);
 	}
 
-	update_cpu_boot_status(CPU_STUCK_IN_KERNEL);
+	update_cpu_boot_status(cpu, CPU_STUCK_IN_KERNEL);
 
 	cpu_park_loop();
 }
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index 0f4a28b87469..6b8a3245f393 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -72,7 +72,7 @@ void verify_cpu_asid_bits(void)
 		 */
 		pr_crit("CPU%d: smaller ASID size(%u) than boot CPU (%u)\n",
 				smp_processor_id(), asid, asid_bits);
-		cpu_panic_kernel();
+		cpu_panic_kernel(smp_processor_id());
 	}
 }
 
-- 
2.34.1



From conor at kernel.org  Thu Jun 11 08:00:42 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 11 Jun 2026 16:00:42 +0100
Subject: [PATCH v3] hwmon: add a driver for the temp/voltage sensor on PolarFire SoC
Message-ID: <20260611-blank-footprint-5504b819baec@spud>

From: Lars Randers <lranders at mail.dk>

Add a driver for the temperature and voltage sensors on PolarFire SoC.
The temperature reports how hot the die is, and the voltages are the
SoC's 1.05, 1.8 and 2.5 volt rails respectively.

The hardware supports alarms in theory, but there is an erratum that
prevents clearing them once triggered, so no support is added for them.

The hardware measures voltage with 16 bits, of which 1 is a sign bit and
the remainder holds the voltage as a fixed point integer value. It's
improbable that the hardware will work if the voltages are negative, so
the driver ignores the sign bits.

There's no dt support etc here because this is the child of a simple-mfd
syscon.

Signed-off-by: Lars Randers <lranders at mail.dk>
Co-developed-by: Conor Dooley <conor.dooley at microchip.com>
Signed-off-by: Conor Dooley <conor.dooley at microchip.com>
---
v3:
- clamp interval values
- note that 0-8 ms is the range for update_interval
- return -ENODATA for invalid data
- do write bounds checking once
- comment on MMIO regmap return value checks

v2:
- Fix some minor things pointed out by Sashiko including inaccurate
  comments, bounds checking of values read from sysfs and Kconfig
  dependencies.
- Make update_interval use milliseconds instead of microseconds
  (I'll add update_interval_us support when that lands, there's a
  proposed workaround for the erratum circulating internally, so it'll
  probably come alongside alarm support).

CC: Guenter Roeck <linux at roeck-us.net>
CC: Jonathan Corbet <corbet at lwn.net>
CC: Shuah Khan <skhan at linuxfoundation.org>
CC: Conor Dooley <conor.dooley at microchip.com>
CC: Daire McNamara <daire.mcnamara at microchip.com>
CC: linux-hwmon at vger.kernel.org
CC: linux-doc at vger.kernel.org
CC: linux-kernel at vger.kernel.org
CC: linux-riscv at lists.infradead.org
CC: Valentina.FernandezAlanis at microchip.com
---
 Documentation/hwmon/index.rst    |   1 +
 Documentation/hwmon/tvs-mpfs.rst |  53 +++++
 MAINTAINERS                      |   1 +
 drivers/hwmon/Kconfig            |  13 ++
 drivers/hwmon/Makefile           |   1 +
 drivers/hwmon/tvs-mpfs.c         | 388 +++++++++++++++++++++++++++++++
 6 files changed, 457 insertions(+)
 create mode 100644 Documentation/hwmon/tvs-mpfs.rst
 create mode 100644 drivers/hwmon/tvs-mpfs.c

diff --git a/Documentation/hwmon/index.rst b/Documentation/hwmon/index.rst
index 8b655e5d6b68..84a5339e1d6f 100644
--- a/Documentation/hwmon/index.rst
+++ b/Documentation/hwmon/index.rst
@@ -262,6 +262,7 @@ Hardware Monitoring Kernel Drivers
    tps53679
    tps546d24
    tsc1641
+   tvs-mpfs
    twl4030-madc-hwmon
    ucd9000
    ucd9200
diff --git a/Documentation/hwmon/tvs-mpfs.rst b/Documentation/hwmon/tvs-mpfs.rst
new file mode 100644
index 000000000000..1035812f363a
--- /dev/null
+++ b/Documentation/hwmon/tvs-mpfs.rst
@@ -0,0 +1,53 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Kernel driver tvs-mpfs
+======================
+
+Supported chips:
+
+  * PolarFire SoC
+
+Authors:
+
+   - Conor Dooley <conor.dooley at microchip.com>
+   - Lars Randers <lranders at mail.dk>
+
+Description
+-----------
+
+This driver implements support for the temperature and voltage sensors on
+PolarFire SoC. The temperature reports how hot the die is, and the voltages are
+the SoC's 1.05, 1.8 and 2.5 volt rails respectively.
+
+
+Usage Notes
+-----------
+
+update_interval has a permitted range of 0 to 8 milliseconds.
+
+Temperatures are read in millidegrees Celsius, but the hardware measures in
+degrees Kelvin, storing the result as 11.4 fixed point data, for a maximum
+value of 2047.9375 degrees Kelvin.
+
+Voltages are read in millivolts. The hardware measures in millivolts, storing
+the value as 12.3 fixed point data, for a maximum of 4095.875 millivolts.
+The minimum value reportable by the driver is 0 volts, although the hardware
+is capable of measuring negative values.
+
+Sysfs entries
+-------------
+
+The following attributes are supported. update_interval is read-write, as are
+the enables. All other attributes are read only.
+
+======================= ====================================================
+temp1_label		Fixed name for channel.
+temp1_input		Measured temperature for channel.
+temp1_enable		Enable/disable for channel.
+
+in[0-2]_label		Fixed name for channel.
+in[0-2]_input		Measured voltage for channel.
+in[0-2]_enable		Enable/disable for channel.
+
+update_interval		The interval at which the chip will update readings.
+======================= ====================================================
diff --git a/MAINTAINERS b/MAINTAINERS
index 2fb1c75afd16..a492cf5ad0fc 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -22938,6 +22938,7 @@ F:	drivers/char/hw_random/mpfs-rng.c
 F:	drivers/clk/microchip/clk-mpfs*.c
 F:	drivers/firmware/microchip/mpfs-auto-update.c
 F:	drivers/gpio/gpio-mpfs.c
+F:	drivers/hwmon/tvs-mpfs.c
 F:	drivers/i2c/busses/i2c-microchip-corei2c.c
 F:	drivers/mailbox/mailbox-mpfs.c
 F:	drivers/pci/controller/plda/pcie-microchip-host.c
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 14e4cea48acc..2b9622b1db95 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -930,6 +930,19 @@ config SENSORS_JC42
 	  This driver can also be built as a module. If so, the module
 	  will be called jc42.
 
+config SENSORS_POLARFIRE_SOC_TVS
+	tristate "PolarFire SoC (MPFS) temperature and voltage sensor"
+	depends on POLARFIRE_SOC_SYSCONS || COMPILE_TEST
+	depends on MFD_SYSCON
+	help
+	  This driver adds support for the PolarFire SoC (MPFS) Temperature and
+	  Voltage Sensor.
+
+	  To compile this driver as a module, choose M here. the
+	  module will be called tvs-mpfs.
+
+	  If unsure, say N.
+
 config SENSORS_POWERZ
 	tristate "ChargerLAB POWER-Z USB-C tester"
 	depends on USB
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 4788996aa137..b58d249e4cf4 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -194,6 +194,7 @@ obj-$(CONFIG_SENSORS_NZXT_SMART2) += nzxt-smart2.o
 obj-$(CONFIG_SENSORS_PC87360)	+= pc87360.o
 obj-$(CONFIG_SENSORS_PC87427)	+= pc87427.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
+obj-$(CONFIG_SENSORS_POLARFIRE_SOC_TVS)  += tvs-mpfs.o
 obj-$(CONFIG_SENSORS_POWERZ)	+= powerz.o
 obj-$(CONFIG_SENSORS_POWR1220)  += powr1220.o
 obj-$(CONFIG_SENSORS_PT5161L)	+= pt5161l.o
diff --git a/drivers/hwmon/tvs-mpfs.c b/drivers/hwmon/tvs-mpfs.c
new file mode 100644
index 000000000000..48de8d98b344
--- /dev/null
+++ b/drivers/hwmon/tvs-mpfs.c
@@ -0,0 +1,388 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Author: Lars Randers <lranders at mail.dk>
+ */
+
+#include <linux/bitfield.h>
+#include <linux/err.h>
+#include <linux/freezer.h>
+#include <linux/hwmon.h>
+#include <linux/io.h>
+#include <linux/kthread.h>
+#include <linux/mfd/syscon.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define MPFS_TVS_CTRL 0x08
+#define MPFS_TVS_OUTPUT0 0x24
+#define MPFS_TVS_OUTPUT1 0x28
+
+#define MPFS_TVS_CTRL_TEMP_VALID	BIT(19)
+#define MPFS_TVS_CTRL_V2P5_VALID	BIT(18)
+#define MPFS_TVS_CTRL_V1P8_VALID	BIT(17)
+#define MPFS_TVS_CTRL_V1P05_VALID	BIT(16)
+
+#define MPFS_TVS_CTRL_TEMP_ENABLE	BIT(3)
+#define MPFS_TVS_CTRL_V2P5_ENABLE	BIT(2)
+#define MPFS_TVS_CTRL_V1P8_ENABLE	BIT(1)
+#define MPFS_TVS_CTRL_V1P05_ENABLE	BIT(0)
+#define MPFS_TVS_CTRL_ENABLE_ALL	GENMASK(3, 0)
+
+/*
+ * For all of these the value in millivolts is stored in 16 bits, with an upper
+ * sign bit and a lower 3 bits of decimal. These masks discard the sign bit and
+ * decimal places, because if Linux is running these voltages cannot be negative
+ * and so avoid having to convert to two's complement.
+ */
+#define MPFS_OUTPUT0_V1P8_MASK	GENMASK(30, 19)
+#define MPFS_OUTPUT0_V1P05_MASK	GENMASK(14, 3)
+#define MPFS_OUTPUT1_V2P5_MASK	GENMASK(14, 3)
+
+/*
+ * The register map claims that the temperature is stored in bits 31:16, but
+ * application note "AN4682: PolarFire FPGA Temperature and Voltage Sensor"
+ * says that 31 is reserved. Temperature is in kelvin, so what's probably a
+ * sign bit has no value anyway.
+ */
+#define MPFS_OUTPUT1_TEMP_MASK GENMASK(30, 16)
+
+#define MPFS_TVS_INTERVAL_MASK GENMASK(15, 8)
+#define MPFS_TVS_INTERVAL_OFFSET 8
+/* The interval register is in increments of 32 us */
+#define MPFS_TVS_INTERVAL_SCALE 32
+/* with 254 usable increments of 32 us available, 8 ms is the integer limit */
+#define MPFS_TVS_INTERVAL_MAX_MS 8U
+
+/* 273.1875 in 11.4 fixed-point notation */
+#define MPFS_TVS_K_TO_C 0x1113
+
+enum mpfs_tvs_sensors {
+	SENSOR_V1P05 = 0,
+	SENSOR_V1P8,
+	SENSOR_V2P5,
+};
+
+static const char * const mpfs_tvs_voltage_labels[] = { "1P05", "1P8", "2P5" };
+
+struct mpfs_tvs {
+	struct regmap *regmap;
+};
+
+static int mpfs_tvs_voltage_read(struct mpfs_tvs *data, u32 attr,
+				 int channel, long *val)
+{
+	u32 tmp, control;
+
+	if (attr != hwmon_in_input && attr != hwmon_in_enable)
+		return -EOPNOTSUPP;
+
+	regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
+
+	switch (channel) {
+	case SENSOR_V2P5:
+		if (attr == hwmon_in_enable) {
+			*val = FIELD_GET(MPFS_TVS_CTRL_V2P5_ENABLE, control);
+			break;
+		}
+
+		if (!(control & MPFS_TVS_CTRL_V2P5_VALID))
+			return -ENODATA;
+
+		regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
+		*val = FIELD_GET(MPFS_OUTPUT1_V2P5_MASK, tmp);
+		break;
+	case SENSOR_V1P8:
+		if (attr == hwmon_in_enable) {
+			*val = FIELD_GET(MPFS_TVS_CTRL_V1P8_ENABLE, control);
+			break;
+		}
+
+		if (!(control & MPFS_TVS_CTRL_V1P8_VALID))
+			return -ENODATA;
+
+		regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp);
+		*val = FIELD_GET(MPFS_OUTPUT0_V1P8_MASK, tmp);
+		break;
+	case SENSOR_V1P05:
+		if (attr == hwmon_in_enable) {
+			*val = FIELD_GET(MPFS_TVS_CTRL_V1P05_ENABLE, control);
+			break;
+		}
+
+		if (!(control & MPFS_TVS_CTRL_V1P05_VALID))
+			return -ENODATA;
+
+		regmap_read(data->regmap, MPFS_TVS_OUTPUT0, &tmp);
+		*val = FIELD_GET(MPFS_OUTPUT0_V1P05_MASK, tmp);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int mpfs_tvs_voltage_write(struct mpfs_tvs *data, u32 attr,
+				  int channel, long val)
+{
+	u32 tmp;
+
+	if (attr != hwmon_in_enable)
+		return -EOPNOTSUPP;
+
+	if (val > 1 || val < 0)
+		return -EINVAL;
+
+	switch (channel) {
+	case SENSOR_V2P5:
+		tmp = FIELD_PREP(MPFS_TVS_CTRL_V2P5_ENABLE, val);
+		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+				   MPFS_TVS_CTRL_V2P5_ENABLE, tmp);
+		break;
+	case SENSOR_V1P8:
+		tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P8_ENABLE, val);
+		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+				   MPFS_TVS_CTRL_V1P8_ENABLE, tmp);
+		break;
+	case SENSOR_V1P05:
+		tmp = FIELD_PREP(MPFS_TVS_CTRL_V1P05_ENABLE, val);
+		regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+				   MPFS_TVS_CTRL_V1P05_ENABLE, tmp);
+		break;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return 0;
+}
+
+static int mpfs_tvs_temp_read(struct mpfs_tvs *data, u32 attr, long *val)
+{
+	u32 tmp, control;
+
+	if (attr != hwmon_temp_input && attr != hwmon_temp_enable)
+		return -EOPNOTSUPP;
+
+	regmap_read(data->regmap, MPFS_TVS_CTRL, &control);
+
+	if (attr == hwmon_temp_enable) {
+		*val = FIELD_GET(MPFS_TVS_CTRL_TEMP_ENABLE, control);
+		return 0;
+	}
+
+	if (!(control & MPFS_TVS_CTRL_TEMP_VALID))
+		return -ENODATA;
+
+	regmap_read(data->regmap, MPFS_TVS_OUTPUT1, &tmp);
+	*val = FIELD_GET(MPFS_OUTPUT1_TEMP_MASK, tmp);
+	*val -= MPFS_TVS_K_TO_C;
+	*val = (1000 * *val) >> 4; /* fixed point (11.4) to millidegrees */
+
+	return 0;
+}
+
+static int mpfs_tvs_temp_write(struct mpfs_tvs *data, u32 attr, long val)
+{
+	u32 tmp;
+
+	if (attr != hwmon_temp_enable)
+		return -EOPNOTSUPP;
+
+	if (val > 1 || val < 0)
+		return -EINVAL;
+
+	tmp = FIELD_PREP(MPFS_TVS_CTRL_TEMP_ENABLE, val);
+	regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+			   MPFS_TVS_CTRL_TEMP_ENABLE, tmp);
+
+	return 0;
+}
+
+static int mpfs_tvs_interval_read(struct mpfs_tvs *data, u32 attr, long *val)
+{
+	u32 tmp;
+
+	if (attr != hwmon_chip_update_interval)
+		return -EOPNOTSUPP;
+
+	regmap_read(data->regmap, MPFS_TVS_CTRL, &tmp);
+	*val = FIELD_GET(MPFS_TVS_INTERVAL_MASK, tmp);
+	*val *= MPFS_TVS_INTERVAL_SCALE;
+	*val /= 1000;
+
+	return 0;
+}
+
+static int mpfs_tvs_interval_write(struct mpfs_tvs *data, u32 attr, long val)
+{
+	unsigned long temp = val;
+
+	if (attr != hwmon_chip_update_interval)
+		return -EOPNOTSUPP;
+
+	temp = clamp(temp, 0U, MPFS_TVS_INTERVAL_MAX_MS);
+
+	temp *= 1000;
+	temp /= MPFS_TVS_INTERVAL_SCALE;
+
+	temp <<= MPFS_TVS_INTERVAL_OFFSET;
+	regmap_update_bits(data->regmap, MPFS_TVS_CTRL,
+			   MPFS_TVS_INTERVAL_MASK, temp);
+
+	return 0;
+}
+
+static umode_t mpfs_tvs_is_visible(const void *data,
+				   enum hwmon_sensor_types type,
+				   u32 attr, int channel)
+{
+	if (type == hwmon_chip && attr == hwmon_chip_update_interval)
+		return 0644;
+
+	if (type == hwmon_temp) {
+		switch (attr) {
+		case hwmon_temp_enable:
+			return 0644;
+		case hwmon_temp_input:
+		case hwmon_temp_label:
+			return 0444;
+		default:
+			return 0;
+		}
+	}
+
+	if (type == hwmon_in) {
+		switch (attr) {
+		case hwmon_in_enable:
+			return 0644;
+		case hwmon_in_input:
+		case hwmon_in_label:
+			return 0444;
+		default:
+			return 0;
+		}
+	}
+
+	return 0;
+}
+
+static int mpfs_tvs_read(struct device *dev, enum hwmon_sensor_types type,
+			 u32 attr, int channel, long *val)
+{
+	struct mpfs_tvs *data = dev_get_drvdata(dev);
+
+	switch (type) {
+	case hwmon_temp:
+		return mpfs_tvs_temp_read(data, attr, val);
+	case hwmon_in:
+		return mpfs_tvs_voltage_read(data, attr, channel, val);
+	case hwmon_chip:
+		return mpfs_tvs_interval_read(data, attr, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int mpfs_tvs_write(struct device *dev, enum hwmon_sensor_types type,
+			  u32 attr, int channel, long val)
+{
+	struct mpfs_tvs *data = dev_get_drvdata(dev);
+
+	switch (type) {
+	case hwmon_temp:
+		return mpfs_tvs_temp_write(data, attr, val);
+	case hwmon_in:
+		return mpfs_tvs_voltage_write(data, attr, channel, val);
+	case hwmon_chip:
+		return mpfs_tvs_interval_write(data, attr, val);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static int mpfs_tvs_read_labels(struct device *dev,
+				enum hwmon_sensor_types type,
+				u32 attr, int channel,
+				const char **str)
+{
+	switch (type) {
+	case hwmon_temp:
+		*str = "Die Temp";
+		return 0;
+	case hwmon_in:
+		*str = mpfs_tvs_voltage_labels[channel];
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+static const struct hwmon_ops mpfs_tvs_ops = {
+	.is_visible = mpfs_tvs_is_visible,
+	.read_string = mpfs_tvs_read_labels,
+	.read = mpfs_tvs_read,
+	.write = mpfs_tvs_write,
+};
+
+static const struct hwmon_channel_info *mpfs_tvs_info[] = {
+	HWMON_CHANNEL_INFO(chip,
+			   HWMON_C_REGISTER_TZ | HWMON_C_UPDATE_INTERVAL),
+	HWMON_CHANNEL_INFO(temp,
+			   HWMON_T_INPUT | HWMON_T_LABEL | HWMON_T_ENABLE),
+	HWMON_CHANNEL_INFO(in,
+			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE,
+			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE,
+			   HWMON_I_INPUT | HWMON_I_LABEL | HWMON_I_ENABLE),
+	NULL
+};
+
+static const struct hwmon_chip_info mpfs_tvs_chip_info = {
+	.ops = &mpfs_tvs_ops,
+	.info = mpfs_tvs_info,
+};
+
+static int mpfs_tvs_probe(struct platform_device *pdev)
+{
+	struct device *hwmon_dev;
+	struct mpfs_tvs *data;
+
+	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->regmap = device_node_to_regmap(pdev->dev.parent->of_node);
+	if (IS_ERR(data->regmap))
+		return dev_err_probe(&pdev->dev, PTR_ERR(data->regmap),
+				     "Failed to find syscon regmap\n");
+
+	/*
+	 * It's an MMIO regmap with no resources, there's nothing that can fail
+	 * and return an error
+	 */
+	regmap_write(data->regmap, MPFS_TVS_CTRL, MPFS_TVS_CTRL_ENABLE_ALL);
+
+	hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev, "mpfs_tvs",
+							 data,
+							 &mpfs_tvs_chip_info,
+							 NULL);
+	if (IS_ERR(hwmon_dev))
+		return dev_err_probe(&pdev->dev, PTR_ERR(hwmon_dev),
+				     "hwmon device registration failed.\n");
+
+	return 0;
+}
+
+static struct platform_driver mpfs_tvs_driver = {
+	.probe = mpfs_tvs_probe,
+	.driver = {
+		.name = "mpfs-tvs",
+	},
+};
+module_platform_driver(mpfs_tvs_driver);
+
+MODULE_AUTHOR("Lars Randers <lranders at mail.dk>");
+MODULE_DESCRIPTION("PolarFire SoC temperature & voltage sensor driver");
+MODULE_LICENSE("GPL");
-- 
2.53.0



From fustini at kernel.org  Thu Jun 11 09:16:08 2026
From: fustini at kernel.org (Drew Fustini)
Date: Thu, 11 Jun 2026 09:16:08 -0700
Subject: [PATCH v2] riscv: defconfig: thead: enable PCA953X GPIO driver
In-Reply-To: <20260608074104.2198409-1-m.szyprowski@samsung.com>
References: <CGME20260608074116eucas1p15c0f84c280d8645d778e42777bd238d1@eucas1p1.samsung.com>
 <20260608074104.2198409-1-m.szyprowski@samsung.com>
Message-ID: <airfSHk5h/u/d2O/@x1>

On Mon, Jun 08, 2026 at 09:41:04AM +0200, Marek Szyprowski wrote:
> Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
> LicheePi4a board.
> 
> Signed-off-by: Marek Szyprowski <m.szyprowski at samsung.com>
> ---
> v2:
> - copile GPIO_PCA953X as a module
> v1:
> https://lore.kernel.org/all/20260603082132.3200787-1-m.szyprowski at samsung.com/
> ---
>  arch/riscv/configs/defconfig | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/arch/riscv/configs/defconfig b/arch/riscv/configs/defconfig
> index 08445df56006..a51a423d53f4 100644
> --- a/arch/riscv/configs/defconfig
> +++ b/arch/riscv/configs/defconfig
> @@ -174,6 +174,8 @@ CONFIG_PINCTRL_SOPHGO_SG2002=y
>  CONFIG_GPIO_DWAPB=y
>  CONFIG_GPIO_SIFIVE=y
>  CONFIG_GPIO_SPACEMIT_K1=y
> +CONFIG_GPIO_PCA953X=m
> +CONFIG_GPIO_PCA953X_IRQ=y
>  CONFIG_POWER_RESET_GPIO_RESTART=y
>  CONFIG_SENSORS_SFCTEMP=m
>  CONFIG_CPU_THERMAL=y
> -- 
> 2.34.1
> 

I have applied this to my riscv-config-for-next branch:

https://git.kernel.org/pub/scm/linux/kernel/git/fustini/linux.git/commit/?h=riscv-config-for-next&id=fb266bbe9aef17d547db468a1a7187b59ed33e9a

Thanks,
Drew


From docular.xu at gmail.com  Thu Jun 11 13:12:37 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:37 -0400
Subject: [PATCH v4 00/16] riscv: hwprobe: Expose RVA23U64 base behavior
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>

This series builds on Andrew Jones's earlier RFC [1]. It lets userspace
check for RVA23U64 conformance in one call, instead of walking hwprobe +
prctl across every mandatory extension.

The series adds a small framework that resolves profile-class bases (IMA
and RVA23U64) from the kernel's ISA extension bitmap at init time, and
surfaces the result through both /proc/cpuinfo and hwprobe. Later patches
can add RVA23S64, and backward RVA22 / RVA20 detection, to
riscv_set_isa_bases() without changes to the surrounding code.

Series outline (v4):

  Housekeeping, clean-ups:
   1.  dt-bindings: sort the multi-letter Z extensions alphanumerically.
   2.  hwprobe.rst: normalize indentation.
   3.  hwprobe.rst: document EXT_ZICFISS / EXT_ZICFILP.
   4.  Standardize the single-letter extension macros to uppercase
       (RISCV_ISA_EXT_a -> RISCV_ISA_EXT_A, etc.).

  Per-extension cpufeature parsing + hwprobe export:
   5.  Zicclsm.
   6.  Ziccamoa, Ziccif, Ziccrse, Za64rs.
   7.  B (the Zba/Zbb/Zbs set).

  Zic64b (new first-class extension):
   8.  dt-binding, with a schema check.
   9.  cpufeature parsing + hwprobe export.
  10-12. dts: declare zic64b in the SpacemiT K3, SpacemiT K1, and Sophgo
         SG2044 device trees.

  RVA23U64 base detection and exposure:
  13.  riscv_have_user_pmlen(): accessor for user pointer-masking PMLEN
       support.
  14.  cpufeature: per-hart and host-wide isa_bases bitmaps; IMA and
       RVA23U64 detection lives here.
  15.  /proc/cpuinfo: print "isa bases:" and "hart isa bases:", e.g.
       rva23u64.
  16.  hwprobe: expose RVA23U64.

Tested on both K3 Pico ITX and QEMU with -cpu rva23s64,sv39=on:
  - /proc/cpuinfo reports "isa bases : rv64ima rva23u64" on both the
    aggregated and per-hart lines.
  - hwprobe RISCV_HWPROBE_KEY_BASE_BEHAVIOR returns
    BASE_BEHAVIOR_IMA | BASE_BEHAVIOR_RVA23U64.

Based on v7.1-rc6 plus [2]; happy to rebase onto another tree if needed.
A branch is available for all patches in the series: [3].

Note: [2] is only required to save the merge effort for adding 'Zic64b'
      and 'Ziccrse' into the same k3.dtsi file.

Link: Andrew's RFC v1:
      https://lore.kernel.org/linux-riscv/20260206002349.96740-1-andrew.jones at oss.qualcomm.com/ [1]
Link: Prerequisite for applying on K3 w/Ziccrse:
      https://lore.kernel.org/all/20260602070257-KYC5031219 at kernel.org/ [2]
Link: Branch: https://github.com/docularxu/linux/commits/b4/rva23u64-hwprobe-v4/ [3]

Changes in v4:
- New patch: sort the multi-letter Z extensions alphanumerically in the
  dt-binding (Conor), and place zic64b at its sorted position.
- Zic64b cpufeature: validate only the CBO block sizes that are present;
  overlaps Qingwei Hu's earlier patch, so it is now authored by Qingwei.
- Document EXT_ZICFISS / EXT_ZICFILP: cite the riscv-cfi v1.0 tag commit.
- Picked up Inochi Amaoto's Acked-by (SG2044 dts) and Andrew Jones's
  Reviewed-by (documentation patch).
- Link to v3: https://patch.msgid.link/20260603-rva23u64-hwprobe-v2-v3-0-5529a7b28384 at gmail.com

Changes in v3:
- Add Zic64b as a first-class ISA extension: dt-binding, cpufeature
  parsing with a validate check, hwprobe export, and device-tree
  declarations for K3/K1/SG2044.
- Patch 1 is now a clean up of hwprobe.rst indentation.
- Document RISCV_HWPROBE_EXT_ZICFILP alongside ZICFISS.
- Move the Zicclsm hwprobe.rst entry to the IMA_EXT_1 section to match
  its bit allocation.
- Collect Anup Patel's Acked-by/Reviewed-by on Patch 3, the capitalization.
- In cpufeature.c, set the local ext_mask with __set_bit().
- Update Guodong Xu's email to docular.xu at gmail.com.
- Link to v2: https://patch.msgid.link/20260511-rva23u64-hwprobe-v2-v2-0-21c5a544f1dc at riscstar.com

Changes in v2 (since Andrew's RFC v1):
- Rebased onto v7.1-rc2.
- Reworked rva23u64 detection into per-hart and host isa_bases bitmaps,
  shared by /proc/cpuinfo and hwprobe.
- Scoped to IMA and RVA23U64 (RVA23S64, RVA20/RVA22 cpuinfo output deferred).
- Link to v1:  https://lore.kernel.org/linux-riscv/20260206002349.96740-1-andrew.jones at oss.qualcomm.com

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
Andrew Jones (4):
      riscv: hwprobe.rst: Make indentation consistent
      riscv: Add Ziccamoa, Ziccif, Ziccrse, and Za64rs to cpufeature and hwprobe
      riscv: Add B to hwcap and hwprobe
      riscv: Add a getter for user PMLEN support

Charlie Jenkins (1):
      riscv: Standardize extension capitalization

Guodong Xu (9):
      dt-bindings: riscv: sort multi-letter Z extensions alphanumerically
      riscv: hwprobe.rst: Document EXT_ZICFISS and EXT_ZICFILP
      dt-bindings: riscv: Add Zic64b extension description
      riscv: dts: spacemit: k3: Add Zic64b ISA extension
      riscv: dts: spacemit: k1: Add Zic64b ISA extension
      riscv: dts: sophgo: sg2044: Add Zic64b ISA extension
      riscv: cpufeature: Introduce ISA bases bitmap and rva23u64 detection
      riscv: cpu: Output isa bases lines in cpuinfo
      riscv: hwprobe: Introduce rva23u64 base behavior

Jesse Taube (1):
      riscv: Add Zicclsm to cpufeature and hwprobe

Qingwei Hu (1):
      riscv: Add Zic64b to cpufeature and hwprobe

 Documentation/arch/riscv/hwprobe.rst               | 240 ++++++++++++---------
 .../devicetree/bindings/riscv/extensions.yaml      | 204 ++++++++++--------
 arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi        | 128 +++++------
 arch/riscv/boot/dts/spacemit/k1.dtsi               |  80 +++----
 arch/riscv/boot/dts/spacemit/k3.dtsi               |  48 ++---
 arch/riscv/include/asm/cpufeature.h                |  14 ++
 arch/riscv/include/asm/hwcap.h                     |  24 ++-
 arch/riscv/include/asm/processor.h                 |   4 +
 arch/riscv/include/asm/switch_to.h                 |   4 +-
 arch/riscv/include/uapi/asm/hwcap.h                |   1 +
 arch/riscv/include/uapi/asm/hwprobe.h              |  10 +-
 arch/riscv/kernel/cpu.c                            |  26 +++
 arch/riscv/kernel/cpufeature.c                     | 183 ++++++++++++++--
 arch/riscv/kernel/process.c                        |  12 ++
 arch/riscv/kernel/sys_hwprobe.c                    |  34 ++-
 arch/riscv/kvm/isa.c                               |  16 +-
 arch/riscv/kvm/main.c                              |   2 +-
 arch/riscv/kvm/vcpu_fp.c                           |  20 +-
 arch/riscv/kvm/vcpu_onereg.c                       |   6 +-
 arch/riscv/kvm/vcpu_vector.c                       |  10 +-
 tools/testing/selftests/riscv/hwprobe/which-cpus.c |   2 +-
 21 files changed, 680 insertions(+), 388 deletions(-)
---
base-commit: 99c201dabc35bbd21252c4c682488209dcb4295e
change-id: 20260508-rva23u64-hwprobe-v2-1d20739cbb8e

Best regards,
--  
Guodong Xu <docular.xu at gmail.com>



From docular.xu at gmail.com  Thu Jun 11 13:12:38 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:38 -0400
Subject: [PATCH v4 01/16] dt-bindings: riscv: sort multi-letter Z
 extensions alphanumerically
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-1-3f01a2449488@gmail.com>

The multi-letter extension enum is documented as being sorted
alphanumerically (see the "multi-letter extensions, sorted
alphanumerically" comment), but several Z entries have drifted out of
order.

Reorder the affected entries so the multi-letter Z list is sorted
alphanumerically again.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: New patch.
---
 .../devicetree/bindings/riscv/extensions.yaml      | 184 ++++++++++-----------
 1 file changed, 92 insertions(+), 92 deletions(-)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb214..5ffc40d599c02 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -457,6 +457,13 @@ properties:
             merged in the riscv-isa-manual by commit dbc79cf28a2 ("Initial seed
             of zc.adoc to src tree.").
 
+        - const: zclsd
+          description:
+            The Zclsd extension implements the compressed (16-bit) version of the
+            Load/Store Pair for RV32. As with Zilsd, this extension was ratified
+            in commit f88abf1 ("Integrating load/store pair for RV32 with the
+            main manual") of riscv-isa-manual.
+
         - const: zcmop
           description:
             The standard Zcmop extension version 1.0, as ratified in commit
@@ -487,6 +494,22 @@ properties:
             in commit 64074bc ("Update version numbers for Zfh/Zfinx") of
             riscv-isa-manual.
 
+        - const: zicbom
+          description:
+            The standard Zicbom extension for base cache management operations as
+            ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+
+        - const: zicbop
+          description:
+            The standard Zicbop extension for cache-block prefetch instructions
+            as ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of
+            riscv-CMOs.
+
+        - const: zicboz
+          description:
+            The standard Zicboz extension for cache-block zeroing as ratified
+            in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+
         - const: ziccamoa
           description:
             The standard Ziccamoa extension for main memory (cacheability and
@@ -514,6 +537,66 @@ properties:
             guarantee on LR/SC sequences, as ratified in commit b1d806605f87
             ("Updated to ratified state.") of the riscv profiles specification.
 
+        - const: zicfilp
+          description: |
+            The standard Zicfilp extension for enforcing forward edge
+            control-flow integrity as ratified in commit 3f8e450 ("merge
+            pull request #227 from ved-rivos/0709") of riscv-cfi
+            github repo.
+
+        - const: zicfiss
+          description: |
+            The standard Zicfiss extension for enforcing backward edge
+            control-flow integrity as ratified in commit 3f8e450 ("merge
+            pull request #227 from ved-rivos/0709") of riscv-cfi
+            github repo.
+
+        - const: zicntr
+          description:
+            The standard Zicntr extension for base counters and timers, as
+            ratified in the 20191213 version of the unprivileged ISA
+            specification.
+
+        - const: zicond
+          description:
+            The standard Zicond extension for conditional arithmetic and
+            conditional-select/move operations as ratified in commit 95cf1f9
+            ("Add changes requested by Ved during signoff") of riscv-zicond.
+
+        - const: zicsr
+          description: |
+            The standard Zicsr extension for control and status register
+            instructions, as ratified in the 20191213 version of the
+            unprivileged ISA specification.
+
+            This does not include Chapter 10, "Counters", which documents
+            special case read-only CSRs, that were moved into the Zicntr and
+            Zihpm extensions after the ratification of the 20191213 version of
+            the unprivileged specification.
+
+        - const: zifencei
+          description:
+            The standard Zifencei extension for instruction-fetch fence, as
+            ratified in the 20191213 version of the unprivileged ISA
+            specification.
+
+        - const: zihintntl
+          description:
+            The standard Zihintntl extension for non-temporal locality hints, as
+            ratified in commit 0dc91f5 ("Zihintntl is ratified") of the
+            riscv-isa-manual.
+
+        - const: zihintpause
+          description:
+            The standard Zihintpause extension for pause hints, as ratified in
+            commit d8ab5c7 ("Zihintpause is ratified") of the riscv-isa-manual.
+
+        - const: zihpm
+          description:
+            The standard Zihpm extension for hardware performance counters, as
+            ratified in the 20191213 version of the unprivileged ISA
+            specification.
+
         - const: zilsd
           description:
             The standard Zilsd extension which provides support for aligned
@@ -521,12 +604,10 @@ properties:
             encodings, as ratified in commit f88abf1 ("Integrating
             load/store pair for RV32 with the main manual") of riscv-isa-manual.
 
-        - const: zclsd
+        - const: zimop
           description:
-            The Zclsd extension implements the compressed (16-bit) version of the
-            Load/Store Pair for RV32. As with Zilsd, this extension was ratified
-            in commit f88abf1 ("Integrating load/store pair for RV32 with the
-            main manual") of riscv-isa-manual.
+            The standard Zimop extension version 1.0, as ratified in commit
+            58220614a5f ("Zimop is ratified/1.0") of the riscv-isa-manual.
 
         - const: zk
           description:
@@ -590,87 +671,6 @@ properties:
             in version 1.0 of RISC-V Cryptography Extensions Volume I
             specification.
 
-        - const: zicbom
-          description:
-            The standard Zicbom extension for base cache management operations as
-            ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
-
-        - const: zicbop
-          description:
-            The standard Zicbop extension for cache-block prefetch instructions
-            as ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of
-            riscv-CMOs.
-
-        - const: zicboz
-          description:
-            The standard Zicboz extension for cache-block zeroing as ratified
-            in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
-
-        - const: zicfilp
-          description: |
-            The standard Zicfilp extension for enforcing forward edge
-            control-flow integrity as ratified in commit 3f8e450 ("merge
-            pull request #227 from ved-rivos/0709") of riscv-cfi
-            github repo.
-
-        - const: zicfiss
-          description: |
-            The standard Zicfiss extension for enforcing backward edge
-            control-flow integrity as ratified in commit 3f8e450 ("merge
-            pull request #227 from ved-rivos/0709") of riscv-cfi
-            github repo.
-
-        - const: zicntr
-          description:
-            The standard Zicntr extension for base counters and timers, as
-            ratified in the 20191213 version of the unprivileged ISA
-            specification.
-
-        - const: zicond
-          description:
-            The standard Zicond extension for conditional arithmetic and
-            conditional-select/move operations as ratified in commit 95cf1f9
-            ("Add changes requested by Ved during signoff") of riscv-zicond.
-
-        - const: zicsr
-          description: |
-            The standard Zicsr extension for control and status register
-            instructions, as ratified in the 20191213 version of the
-            unprivileged ISA specification.
-
-            This does not include Chapter 10, "Counters", which documents
-            special case read-only CSRs, that were moved into the Zicntr and
-            Zihpm extensions after the ratification of the 20191213 version of
-            the unprivileged specification.
-
-        - const: zifencei
-          description:
-            The standard Zifencei extension for instruction-fetch fence, as
-            ratified in the 20191213 version of the unprivileged ISA
-            specification.
-
-        - const: zihintpause
-          description:
-            The standard Zihintpause extension for pause hints, as ratified in
-            commit d8ab5c7 ("Zihintpause is ratified") of the riscv-isa-manual.
-
-        - const: zihintntl
-          description:
-            The standard Zihintntl extension for non-temporal locality hints, as
-            ratified in commit 0dc91f5 ("Zihintntl is ratified") of the
-            riscv-isa-manual.
-
-        - const: zihpm
-          description:
-            The standard Zihpm extension for hardware performance counters, as
-            ratified in the 20191213 version of the unprivileged ISA
-            specification.
-
-        - const: zimop
-          description:
-            The standard Zimop extension version 1.0, as ratified in commit
-            58220614a5f ("Zimop is ratified/1.0") of the riscv-isa-manual.
-
         - const: ztso
           description:
             The standard Ztso extension for total store ordering, as ratified
@@ -809,18 +809,18 @@ properties:
             instructions, as ratified in commit 56ed795 ("Update
             riscv-crypto-spec-vector.adoc") of riscv-crypto.
 
-        - const: zvksh
-          description: |
-            The standard Zvksh extension for ShangMi suite: SM3 secure hash
-            instructions, as ratified in commit 56ed795 ("Update
-            riscv-crypto-spec-vector.adoc") of riscv-crypto.
-
         - const: zvksg
           description:
             The standard Zvksg extension for ShangMi algorithm suite with GCM
             instructions, as ratified in commit 56ed795 ("Update
             riscv-crypto-spec-vector.adoc") of riscv-crypto.
 
+        - const: zvksh
+          description: |
+            The standard Zvksh extension for ShangMi suite: SM3 secure hash
+            instructions, as ratified in commit 56ed795 ("Update
+            riscv-crypto-spec-vector.adoc") of riscv-crypto.
+
         - const: zvkt
           description:
             The standard Zvkt extension for vector data-independent execution

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:39 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:39 -0400
Subject: [PATCH v4 02/16] riscv: hwprobe.rst: Make indentation consistent
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-2-3f01a2449488@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

A handful of vendor-extension entries indent continuation lines with a
tab character, while the rest of hwprobe.rst uses spaces.  In addition,
many list items align their continuation lines under the 'm' of
':c:macro:' (column 7) rather than under the item text (column 4), so
the file mixes several indentation styles.

Replace the tabs with spaces and align every list item's continuation
lines under the item text, giving the whole file one consistent style.

Whitespace-only change, no functional change.

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
[Guodong: extend from tabs->spaces to normalizing all continuation-line
 indentation across the file]
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: No change.
v3:
- Move to the front of the series.
- Extend from replacing tabs to normalizing all continuation-line
  indentation, so later patches add documentation on top of a
  consistent base (Andrew).
---
 Documentation/arch/riscv/hwprobe.rst | 194 +++++++++++++++++------------------
 1 file changed, 97 insertions(+), 97 deletions(-)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index c420a8349bc68..a09a8f16bd16f 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -82,121 +82,121 @@ The following keys are defined:
     version 1.0 of the RISC-V Vector extension manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBA`: The Zba address generation extension is
-       supported, as defined in version 1.0 of the Bit-Manipulation ISA
-       extensions.
+    supported, as defined in version 1.0 of the Bit-Manipulation ISA
+    extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBB`: The Zbb extension is supported, as defined
-       in version 1.0 of the Bit-Manipulation ISA extensions.
+    in version 1.0 of the Bit-Manipulation ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBS`: The Zbs extension is supported, as defined
-       in version 1.0 of the Bit-Manipulation ISA extensions.
+    in version 1.0 of the Bit-Manipulation ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICBOZ`: The Zicboz extension is supported, as
-       ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+    ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBC` The Zbc extension is supported, as defined
-       in version 1.0 of the Bit-Manipulation ISA extensions.
+    in version 1.0 of the Bit-Manipulation ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBKB` The Zbkb extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBKC` The Zbkc extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZBKX` The Zbkx extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKND` The Zknd extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKNE` The Zkne extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKNH` The Zknh extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKSED` The Zksed extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKSH` The Zksh extension is supported, as
-       defined in version 1.0 of the Scalar Crypto ISA extensions.
+    defined in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZKT` The Zkt extension is supported, as defined
-       in version 1.0 of the Scalar Crypto ISA extensions.
+    in version 1.0 of the Scalar Crypto ISA extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVBB`: The Zvbb extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVBC`: The Zvbc extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKB`: The Zvkb extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKG`: The Zvkg extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKNED`: The Zvkned extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKNHA`: The Zvknha extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKNHB`: The Zvknhb extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKSED`: The Zvksed extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKSH`: The Zvksh extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVKT`: The Zvkt extension is supported as
-       defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
+    defined in version 1.0 of the RISC-V Cryptography Extensions Volume II.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZFH`: The Zfh extension version 1.0 is supported
-       as defined in the RISC-V ISA manual.
+    as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZFHMIN`: The Zfhmin extension version 1.0 is
-       supported as defined in the RISC-V ISA manual.
+    supported as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZIHINTNTL`: The Zihintntl extension version 1.0
-       is supported as defined in the RISC-V ISA manual.
+    is supported as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVFH`: The Zvfh extension is supported as
-       defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
-       ("Remove draft warnings from Zvfh[min]").
+    defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
+    ("Remove draft warnings from Zvfh[min]").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVFHMIN`: The Zvfhmin extension is supported as
-       defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
-       ("Remove draft warnings from Zvfh[min]").
+    defined in the RISC-V Vector manual starting from commit e2ccd0548d6c
+    ("Remove draft warnings from Zvfh[min]").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZFA`: The Zfa extension is supported as
-       defined in the RISC-V ISA manual starting from commit 056b6ff467c7
-       ("Zfa is ratified").
+    defined in the RISC-V ISA manual starting from commit 056b6ff467c7
+    ("Zfa is ratified").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZTSO`: The Ztso extension is supported as
-       defined in the RISC-V ISA manual starting from commit 5618fb5a216b
-       ("Ztso is now ratified.")
+    defined in the RISC-V ISA manual starting from commit 5618fb5a216b
+    ("Ztso is now ratified.")
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZACAS`: The Zacas extension is supported as
-       defined in the Atomic Compare-and-Swap (CAS) instructions manual starting
-       from commit 5059e0ca641c ("update to ratified").
+    defined in the Atomic Compare-and-Swap (CAS) instructions manual starting
+    from commit 5059e0ca641c ("update to ratified").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICNTR`: The Zicntr extension version 2.0
-       is supported as defined in the RISC-V ISA manual.
+    is supported as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICOND`: The Zicond extension is supported as
-       defined in the RISC-V Integer Conditional (Zicond) operations extension
-       manual starting from commit 95cf1f9 ("Add changes requested by Ved
-       during signoff")
+    defined in the RISC-V Integer Conditional (Zicond) operations extension
+    manual starting from commit 95cf1f9 ("Add changes requested by Ved
+    during signoff")
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZIHINTPAUSE`: The Zihintpause extension is
-       supported as defined in the RISC-V ISA manual starting from commit
-       d8ab5c78c207 ("Zihintpause is ratified").
+    supported as defined in the RISC-V ISA manual starting from commit
+    d8ab5c78c207 ("Zihintpause is ratified").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZIHPM`: The Zihpm extension version 2.0
-       is supported as defined in the RISC-V ISA manual.
+    is supported as defined in the RISC-V ISA manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVE32X`: The Vector sub-extension Zve32x is
     supported, as defined by version 1.0 of the RISC-V Vector extension manual.
@@ -214,84 +214,84 @@ The following keys are defined:
     supported, as defined by version 1.0 of the RISC-V Vector extension manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZIMOP`: The Zimop May-Be-Operations extension is
-       supported as defined in the RISC-V ISA manual starting from commit
-       58220614a5f ("Zimop is ratified/1.0").
+    supported as defined in the RISC-V ISA manual starting from commit
+    58220614a5f ("Zimop is ratified/1.0").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCA`: The Zca extension part of Zc* standard
-       extensions for code size reduction, as ratified in commit 8be3419c1c0
-       ("Zcf doesn't exist on RV64 as it contains no instructions") of
-       riscv-code-size-reduction.
+    extensions for code size reduction, as ratified in commit 8be3419c1c0
+    ("Zcf doesn't exist on RV64 as it contains no instructions") of
+    riscv-code-size-reduction.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCB`: The Zcb extension part of Zc* standard
-       extensions for code size reduction, as ratified in commit 8be3419c1c0
-       ("Zcf doesn't exist on RV64 as it contains no instructions") of
-       riscv-code-size-reduction.
+    extensions for code size reduction, as ratified in commit 8be3419c1c0
+    ("Zcf doesn't exist on RV64 as it contains no instructions") of
+    riscv-code-size-reduction.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCD`: The Zcd extension part of Zc* standard
-       extensions for code size reduction, as ratified in commit 8be3419c1c0
-       ("Zcf doesn't exist on RV64 as it contains no instructions") of
-       riscv-code-size-reduction.
+    extensions for code size reduction, as ratified in commit 8be3419c1c0
+    ("Zcf doesn't exist on RV64 as it contains no instructions") of
+    riscv-code-size-reduction.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCF`: The Zcf extension part of Zc* standard
-       extensions for code size reduction, as ratified in commit 8be3419c1c0
-       ("Zcf doesn't exist on RV64 as it contains no instructions") of
-       riscv-code-size-reduction.
+    extensions for code size reduction, as ratified in commit 8be3419c1c0
+    ("Zcf doesn't exist on RV64 as it contains no instructions") of
+    riscv-code-size-reduction.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCMOP`: The Zcmop May-Be-Operations extension is
-       supported as defined in the RISC-V ISA manual starting from commit
-       c732a4f39a4 ("Zcmop is ratified/1.0").
+    supported as defined in the RISC-V ISA manual starting from commit
+    c732a4f39a4 ("Zcmop is ratified/1.0").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZAWRS`: The Zawrs extension is supported as
-       ratified in commit 98918c844281 ("Merge pull request #1217 from
-       riscv/zawrs") of riscv-isa-manual.
+    ratified in commit 98918c844281 ("Merge pull request #1217 from
+    riscv/zawrs") of riscv-isa-manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZAAMO`: The Zaamo extension is supported as
-       defined in the in the RISC-V ISA manual starting from commit e87412e621f1
-       ("integrate Zaamo and Zalrsc text (#1304)").
+    defined in the in the RISC-V ISA manual starting from commit e87412e621f1
+    ("integrate Zaamo and Zalrsc text (#1304)").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZALASR`: The Zalasr extension is supported as
-       frozen at commit 194f0094 ("Version 0.9 for freeze") of riscv-zalasr.
+    frozen at commit 194f0094 ("Version 0.9 for freeze") of riscv-zalasr.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZALRSC`: The Zalrsc extension is supported as
-       defined in the in the RISC-V ISA manual starting from commit e87412e621f1
-       ("integrate Zaamo and Zalrsc text (#1304)").
+    defined in the in the RISC-V ISA manual starting from commit e87412e621f1
+    ("integrate Zaamo and Zalrsc text (#1304)").
 
   * :c:macro:`RISCV_HWPROBE_EXT_SUPM`: The Supm extension is supported as
-       defined in version 1.0 of the RISC-V Pointer Masking extensions.
+    defined in version 1.0 of the RISC-V Pointer Masking extensions.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZFBFMIN`: The Zfbfmin extension is supported as
-       defined in the RISC-V ISA manual starting from commit 4dc23d6229de
-       ("Added Chapter title to BF16").
+    defined in the RISC-V ISA manual starting from commit 4dc23d6229de
+    ("Added Chapter title to BF16").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVFBFMIN`: The Zvfbfmin extension is supported as
-       defined in the RISC-V ISA manual starting from commit 4dc23d6229de
-       ("Added Chapter title to BF16").
+    defined in the RISC-V ISA manual starting from commit 4dc23d6229de
+    ("Added Chapter title to BF16").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZVFBFWMA`: The Zvfbfwma extension is supported as
-       defined in the RISC-V ISA manual starting from commit 4dc23d6229de
-       ("Added Chapter title to BF16").
+    defined in the RISC-V ISA manual starting from commit 4dc23d6229de
+    ("Added Chapter title to BF16").
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICBOM`: The Zicbom extension is supported, as
-       ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+    ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZABHA`: The Zabha extension is supported as
-       ratified in commit 49f49c842ff9 ("Update to Rafified state") of
-       riscv-zabha.
+    ratified in commit 49f49c842ff9 ("Update to Rafified state") of
+    riscv-zabha.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZICBOP`: The Zicbop extension is supported, as
-       ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
+    ratified in commit 3dd606f ("Create cmobase-v1.0.pdf") of riscv-CMOs.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZILSD`: The Zilsd extension is supported as
-       defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
-       load/store pair for RV32 with the main manual") of the riscv-isa-manual.
+    defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
+    load/store pair for RV32 with the main manual") of the riscv-isa-manual.
 
   * :c:macro:`RISCV_HWPROBE_EXT_ZCLSD`: The Zclsd extension is supported as
-       defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
-       load/store pair for RV32 with the main manual") of the riscv-isa-manual.
+    defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
+    load/store pair for RV32 with the main manual") of the riscv-isa-manual.
 
 * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated.  Returns similar values to
-     :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
-     mistakenly classified as a bitmask rather than a value.
+  :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
+  mistakenly classified as a bitmask rather than a value.
 
 * :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`: An enum value describing
   the performance of misaligned scalar native word accesses on the selected set
@@ -326,7 +326,7 @@ The following keys are defined:
 * :c:macro:`RISCV_HWPROBE_KEY_TIME_CSR_FREQ`: Frequency (in Hz) of `time CSR`.
 
 * :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_VECTOR_PERF`: An enum value describing the
-     performance of misaligned vector accesses on the selected set of processors.
+  performance of misaligned vector accesses on the selected set of processors.
 
   * :c:macro:`RISCV_HWPROBE_MISALIGNED_VECTOR_UNKNOWN`: The performance of misaligned
     vector accesses is unknown.
@@ -348,7 +348,7 @@ The following keys are defined:
   * MIPS
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XMIPSEXECTL`: The xmipsexectl vendor
-        extension is supported in the MIPS ISA extensions spec.
+      extension is supported in the MIPS ISA extensions spec.
 
 * :c:macro:`RISCV_HWPROBE_KEY_VENDOR_EXT_THEAD_0`: A bitmask containing the
   thead vendor extensions that are compatible with the
@@ -357,8 +357,8 @@ The following keys are defined:
   * T-HEAD
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XTHEADVECTOR`: The xtheadvector vendor
-        extension is supported in the T-Head ISA extensions spec starting from
-	commit a18c801634 ("Add T-Head VECTOR vendor extension. ").
+      extension is supported in the T-Head ISA extensions spec starting from
+      commit a18c801634 ("Add T-Head VECTOR vendor extension. ").
 
 * :c:macro:`RISCV_HWPROBE_KEY_ZICBOM_BLOCK_SIZE`: An unsigned int which
   represents the size of the Zicbom block in bytes.
@@ -370,20 +370,20 @@ The following keys are defined:
   * SIFIVE
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCDOD`: The Xsfqmaccdod vendor
-        extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
-	Extensions Specification.
+      extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
+      Extensions Specification.
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVQMACCQOQ`: The Xsfqmaccqoq vendor
-        extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
-	Instruction Extensions Specification.
+      extension is supported in version 1.1 of SiFive Int8 Matrix Multiplication
+      Instruction Extensions Specification.
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFNRCLIPXFQF`: The Xsfvfnrclipxfqf
-        vendor extension is supported in version 1.0 of SiFive FP32-to-int8 Ranged
-	Clip Instructions Extensions Specification.
+      vendor extension is supported in version 1.0 of SiFive FP32-to-int8 Ranged
+      Clip Instructions Extensions Specification.
 
     * :c:macro:`RISCV_HWPROBE_VENDOR_EXT_XSFVFWMACCQQQ`: The Xsfvfwmaccqqq
-        vendor extension is supported in version 1.0 of Matrix Multiply Accumulate
-	Instruction Extensions Specification.
+      vendor extension is supported in version 1.0 of Matrix Multiply Accumulate
+      Instruction Extensions Specification.
 
 * :c:macro:`RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE`: An unsigned int which
   represents the size of the Zicbop block in bytes.

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:40 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:40 -0400
Subject: [PATCH v4 03/16] riscv: hwprobe.rst: Document EXT_ZICFISS and
 EXT_ZICFILP
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-3-3f01a2449488@gmail.com>

RISCV_HWPROBE_EXT_ZICFISS and RISCV_HWPROBE_EXT_ZICFILP are defined in
the hwprobe uAPI but are not documented in
Documentation/arch/riscv/hwprobe.rst.  Add documentation for them.

Link: https://github.com/riscv/riscv-cfi/commit/302a2d45c2435940d9a63571c66bc038adc74133
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
Reviewed-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
---
v4:
- Update the commit message.
- Cite riscv-cfi commit 302a2d45c243 (tag v1.0) instead of ff03d8485a04,
  per Andrew.
- Add a Link: tag for this citation.
v3:
- Also document RISCV_HWPROBE_EXT_ZICFILP (bit 63 of IMA_EXT_0), the
  sibling enumeration to ZICFISS (Andrew).
v2: New patch.
---
 Documentation/arch/riscv/hwprobe.rst | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index a09a8f16bd16f..d9928641deb99 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -289,6 +289,11 @@ The following keys are defined:
     defined in the RISC-V ISA manual starting from commit f88abf1 ("Integrating
     load/store pair for RV32 with the main manual") of the riscv-isa-manual.
 
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICFILP`: The Zicfilp extension is supported,
+    as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
+    extensions specification, ratified in commit 302a2d45c243
+    ("Update build-pdf.yml") of riscv-cfi.
+
 * :c:macro:`RISCV_HWPROBE_KEY_CPUPERF_0`: Deprecated.  Returns similar values to
   :c:macro:`RISCV_HWPROBE_KEY_MISALIGNED_SCALAR_PERF`, but the key was
   mistakenly classified as a bitmask rather than a value.
@@ -391,3 +396,8 @@ The following keys are defined:
 * :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_1`: A bitmask containing additional
   extensions that are compatible with the
   :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`: base system behavior.
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICFISS`: The Zicfiss extension is supported,
+    as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
+    extensions specification, ratified in commit 302a2d45c243
+    ("Update build-pdf.yml") of riscv-cfi.

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:41 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:41 -0400
Subject: [PATCH v4 04/16] riscv: Standardize extension capitalization
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-4-3f01a2449488@gmail.com>

From: Charlie Jenkins <charlie at rivosinc.com>

The base extensions are often lowercase and were written as lowercase in
hwcap, but other references to these extensions in the kernel are
uppercase. Standardize the case to make it easier to handle macro
expansion.

Signed-off-by: Charlie Jenkins <thecharlesjenkins at gmail.com>
[Apply KVM_ISA_EXT_ARR(), fixup all KVM use.]
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
Acked-by: Anup Patel <anup at brainfault.org>
Reviewed-by: Anup Patel <anup at brainfault.org>

---
v4: No change.
v3:
- Collected Anup's Acked-by and Reviewed-by.
- Rebased onto v7.1-rc6: two more occurances between -rc2 and -rc6:
   1). isa2hwcap[] indices added by commit 41337097f2823
   2). the T-Head "v" workaround's clear_bit() added by commit d272b8d2dd132
v2:
- Rebased onto v7.1-rc2.
- KVM_ISA_EXT_ARR() consolidation moved to its new upstream location
  (kvm/isa.c); host-side checks now use kvm_riscv_isa_check_host().
---
 arch/riscv/include/asm/hwcap.h     | 18 ++++++++--------
 arch/riscv/include/asm/switch_to.h |  4 ++--
 arch/riscv/kernel/cpufeature.c     | 44 +++++++++++++++++++-------------------
 arch/riscv/kernel/sys_hwprobe.c    |  4 ++--
 arch/riscv/kvm/isa.c               | 16 +++++++-------
 arch/riscv/kvm/main.c              |  2 +-
 arch/riscv/kvm/vcpu_fp.c           | 20 ++++++++---------
 arch/riscv/kvm/vcpu_onereg.c       |  6 +++---
 arch/riscv/kvm/vcpu_vector.c       | 10 ++++-----
 9 files changed, 62 insertions(+), 62 deletions(-)

diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 7ef8e5f55c8dc..44bf8c7d8acc5 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -10,15 +10,15 @@
 
 #include <uapi/asm/hwcap.h>
 
-#define RISCV_ISA_EXT_a		('a' - 'a')
-#define RISCV_ISA_EXT_c		('c' - 'a')
-#define RISCV_ISA_EXT_d		('d' - 'a')
-#define RISCV_ISA_EXT_f		('f' - 'a')
-#define RISCV_ISA_EXT_h		('h' - 'a')
-#define RISCV_ISA_EXT_i		('i' - 'a')
-#define RISCV_ISA_EXT_m		('m' - 'a')
-#define RISCV_ISA_EXT_q		('q' - 'a')
-#define RISCV_ISA_EXT_v		('v' - 'a')
+#define RISCV_ISA_EXT_A		('a' - 'a')
+#define RISCV_ISA_EXT_C		('c' - 'a')
+#define RISCV_ISA_EXT_D		('d' - 'a')
+#define RISCV_ISA_EXT_F		('f' - 'a')
+#define RISCV_ISA_EXT_H		('h' - 'a')
+#define RISCV_ISA_EXT_I		('i' - 'a')
+#define RISCV_ISA_EXT_M		('m' - 'a')
+#define RISCV_ISA_EXT_Q		('q' - 'a')
+#define RISCV_ISA_EXT_V		('v' - 'a')
 
 /*
  * These macros represent the logical IDs of each multi-letter RISC-V ISA
diff --git a/arch/riscv/include/asm/switch_to.h b/arch/riscv/include/asm/switch_to.h
index 0e71eb82f920c..ff35a4d04f85a 100644
--- a/arch/riscv/include/asm/switch_to.h
+++ b/arch/riscv/include/asm/switch_to.h
@@ -60,8 +60,8 @@ static inline void __switch_to_fpu(struct task_struct *prev,
 
 static __always_inline bool has_fpu(void)
 {
-	return riscv_has_extension_likely(RISCV_ISA_EXT_f) ||
-		riscv_has_extension_likely(RISCV_ISA_EXT_d);
+	return riscv_has_extension_likely(RISCV_ISA_EXT_F) ||
+		riscv_has_extension_likely(RISCV_ISA_EXT_D);
 }
 #else
 static __always_inline bool has_fpu(void) { return false; }
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index f46aa5602d74d..686dde3ce3b98 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -84,7 +84,7 @@ EXPORT_SYMBOL_GPL(__riscv_isa_extension_available);
 static int riscv_ext_f_depends(const struct riscv_isa_ext_data *data,
 			       const unsigned long *isa_bitmap)
 {
-	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f))
+	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_F))
 		return 0;
 
 	return -EPROBE_DEFER;
@@ -146,7 +146,7 @@ static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data,
 	 * Due to extension ordering, d is checked before f, so no deferral
 	 * is required.
 	 */
-	if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d)) {
+	if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D)) {
 		pr_warn_once("This kernel does not support systems with F but not D\n");
 		return -EINVAL;
 	}
@@ -189,7 +189,7 @@ static int riscv_ext_vector_float_validate(const struct riscv_isa_ext_data *data
 	 * Since this function validates vector only, and v/Zve* are probed
 	 * after f/d, there's no need for a deferral here.
 	 */
-	if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d))
+	if (!__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D))
 		return -EINVAL;
 
 	return 0;
@@ -224,7 +224,7 @@ static int riscv_ext_zcd_validate(const struct riscv_isa_ext_data *data,
 				  const unsigned long *isa_bitmap)
 {
 	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) &&
-	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_d))
+	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_D))
 		return 0;
 
 	return -EPROBE_DEFER;
@@ -237,7 +237,7 @@ static int riscv_ext_zcf_validate(const struct riscv_isa_ext_data *data,
 		return -EINVAL;
 
 	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZCA) &&
-	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_f))
+	    __riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_F))
 		return 0;
 
 	return -EPROBE_DEFER;
@@ -490,15 +490,15 @@ static const unsigned int riscv_c_exts[] = {
  * New entries to this struct should follow the ordering rules described above.
  */
 const struct riscv_isa_ext_data riscv_isa_ext[] = {
-	__RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_i),
-	__RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_m),
-	__RISCV_ISA_EXT_SUPERSET(a, RISCV_ISA_EXT_a, riscv_a_exts),
-	__RISCV_ISA_EXT_DATA_VALIDATE(f, RISCV_ISA_EXT_f, riscv_ext_f_validate),
-	__RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_d, riscv_ext_d_validate),
-	__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_q),
-	__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_c, riscv_c_exts),
-	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_v, riscv_v_exts, riscv_ext_vector_float_validate),
-	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_h),
+	__RISCV_ISA_EXT_DATA(i, RISCV_ISA_EXT_I),
+	__RISCV_ISA_EXT_DATA(m, RISCV_ISA_EXT_M),
+	__RISCV_ISA_EXT_SUPERSET(a, RISCV_ISA_EXT_A, riscv_a_exts),
+	__RISCV_ISA_EXT_DATA_VALIDATE(f, RISCV_ISA_EXT_F, riscv_ext_f_validate),
+	__RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_D, riscv_ext_d_validate),
+	__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_Q),
+	__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_C, riscv_c_exts),
+	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate),
+	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
@@ -897,7 +897,7 @@ static void __init riscv_fill_hwcap_from_isa_string(unsigned long *isa2hwcap)
 		 * marchid.
 		 */
 		if (acpi_disabled && boot_vendorid == THEAD_VENDOR_ID && boot_archid == 0x0)
-			clear_bit(RISCV_ISA_EXT_v, source_isa);
+			clear_bit(RISCV_ISA_EXT_V, source_isa);
 
 		riscv_resolve_isa(source_isa, isainfo->isa, &this_hwcap, isa2hwcap);
 
@@ -1105,13 +1105,13 @@ void __init riscv_fill_hwcap(void)
 	unsigned long isa2hwcap[RISCV_ISA_EXT_BASE] = {0};
 	int i, j;
 
-	isa2hwcap[RISCV_ISA_EXT_i] = COMPAT_HWCAP_ISA_I;
-	isa2hwcap[RISCV_ISA_EXT_m] = COMPAT_HWCAP_ISA_M;
-	isa2hwcap[RISCV_ISA_EXT_a] = COMPAT_HWCAP_ISA_A;
-	isa2hwcap[RISCV_ISA_EXT_f] = COMPAT_HWCAP_ISA_F;
-	isa2hwcap[RISCV_ISA_EXT_d] = COMPAT_HWCAP_ISA_D;
-	isa2hwcap[RISCV_ISA_EXT_c] = COMPAT_HWCAP_ISA_C;
-	isa2hwcap[RISCV_ISA_EXT_v] = COMPAT_HWCAP_ISA_V;
+	isa2hwcap[RISCV_ISA_EXT_I] = COMPAT_HWCAP_ISA_I;
+	isa2hwcap[RISCV_ISA_EXT_M] = COMPAT_HWCAP_ISA_M;
+	isa2hwcap[RISCV_ISA_EXT_A] = COMPAT_HWCAP_ISA_A;
+	isa2hwcap[RISCV_ISA_EXT_F] = COMPAT_HWCAP_ISA_F;
+	isa2hwcap[RISCV_ISA_EXT_D] = COMPAT_HWCAP_ISA_D;
+	isa2hwcap[RISCV_ISA_EXT_C] = COMPAT_HWCAP_ISA_C;
+	isa2hwcap[RISCV_ISA_EXT_V] = COMPAT_HWCAP_ISA_V;
 
 	if (!acpi_disabled) {
 		riscv_fill_hwcap_from_isa_string(isa2hwcap);
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 1659d31fd288f..f8f68ba781b45 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -88,10 +88,10 @@ static void hwprobe_isa_ext0(struct riscv_hwprobe *pair,
 	if (has_fpu())
 		pair->value |= RISCV_HWPROBE_IMA_FD;
 
-	if (riscv_isa_extension_available(NULL, c))
+	if (riscv_isa_extension_available(NULL, C))
 		pair->value |= RISCV_HWPROBE_IMA_C;
 
-	if (has_vector() && riscv_isa_extension_available(NULL, v))
+	if (has_vector() && riscv_isa_extension_available(NULL, V))
 		pair->value |= RISCV_HWPROBE_IMA_V;
 
 	/*
diff --git a/arch/riscv/kvm/isa.c b/arch/riscv/kvm/isa.c
index 1132d909cc25c..94077117d1136 100644
--- a/arch/riscv/kvm/isa.c
+++ b/arch/riscv/kvm/isa.c
@@ -17,14 +17,14 @@
 /* Mapping between KVM ISA Extension ID & guest ISA extension ID */
 static const unsigned long kvm_isa_ext_arr[] = {
 	/* Single letter extensions (alphabetically sorted) */
-	[KVM_RISCV_ISA_EXT_A] = RISCV_ISA_EXT_a,
-	[KVM_RISCV_ISA_EXT_C] = RISCV_ISA_EXT_c,
-	[KVM_RISCV_ISA_EXT_D] = RISCV_ISA_EXT_d,
-	[KVM_RISCV_ISA_EXT_F] = RISCV_ISA_EXT_f,
-	[KVM_RISCV_ISA_EXT_H] = RISCV_ISA_EXT_h,
-	[KVM_RISCV_ISA_EXT_I] = RISCV_ISA_EXT_i,
-	[KVM_RISCV_ISA_EXT_M] = RISCV_ISA_EXT_m,
-	[KVM_RISCV_ISA_EXT_V] = RISCV_ISA_EXT_v,
+	KVM_ISA_EXT_ARR(A),
+	KVM_ISA_EXT_ARR(C),
+	KVM_ISA_EXT_ARR(D),
+	KVM_ISA_EXT_ARR(F),
+	KVM_ISA_EXT_ARR(H),
+	KVM_ISA_EXT_ARR(I),
+	KVM_ISA_EXT_ARR(M),
+	KVM_ISA_EXT_ARR(V),
 	/* Multi letter extensions (alphabetically sorted) */
 	KVM_ISA_EXT_ARR(SMNPM),
 	KVM_ISA_EXT_ARR(SMSTATEEN),
diff --git a/arch/riscv/kvm/main.c b/arch/riscv/kvm/main.c
index cb8a65273c1f0..70640701310c8 100644
--- a/arch/riscv/kvm/main.c
+++ b/arch/riscv/kvm/main.c
@@ -85,7 +85,7 @@ static int __init riscv_kvm_init(void)
 	char slist[64];
 	const char *str;
 
-	if (!riscv_isa_extension_available(NULL, h)) {
+	if (!riscv_isa_extension_available(NULL, H)) {
 		kvm_info("hypervisor extension not available\n");
 		return -ENODEV;
 	}
diff --git a/arch/riscv/kvm/vcpu_fp.c b/arch/riscv/kvm/vcpu_fp.c
index 6ad6df26a2fd4..bb11e6757d349 100644
--- a/arch/riscv/kvm/vcpu_fp.c
+++ b/arch/riscv/kvm/vcpu_fp.c
@@ -21,8 +21,8 @@ void kvm_riscv_vcpu_fp_reset(struct kvm_vcpu *vcpu)
 	struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
 
 	cntx->sstatus &= ~SR_FS;
-	if (riscv_isa_extension_available(vcpu->arch.isa, f) ||
-	    riscv_isa_extension_available(vcpu->arch.isa, d))
+	if (riscv_isa_extension_available(vcpu->arch.isa, F) ||
+	    riscv_isa_extension_available(vcpu->arch.isa, D))
 		cntx->sstatus |= SR_FS_INITIAL;
 	else
 		cntx->sstatus |= SR_FS_OFF;
@@ -38,9 +38,9 @@ void kvm_riscv_vcpu_guest_fp_save(struct kvm_cpu_context *cntx,
 				  const unsigned long *isa)
 {
 	if ((cntx->sstatus & SR_FS) == SR_FS_DIRTY) {
-		if (riscv_isa_extension_available(isa, d))
+		if (riscv_isa_extension_available(isa, D))
 			__kvm_riscv_fp_d_save(cntx);
-		else if (riscv_isa_extension_available(isa, f))
+		else if (riscv_isa_extension_available(isa, F))
 			__kvm_riscv_fp_f_save(cntx);
 		kvm_riscv_vcpu_fp_clean(cntx);
 	}
@@ -50,9 +50,9 @@ void kvm_riscv_vcpu_guest_fp_restore(struct kvm_cpu_context *cntx,
 				     const unsigned long *isa)
 {
 	if ((cntx->sstatus & SR_FS) != SR_FS_OFF) {
-		if (riscv_isa_extension_available(isa, d))
+		if (riscv_isa_extension_available(isa, D))
 			__kvm_riscv_fp_d_restore(cntx);
-		else if (riscv_isa_extension_available(isa, f))
+		else if (riscv_isa_extension_available(isa, F))
 			__kvm_riscv_fp_f_restore(cntx);
 		kvm_riscv_vcpu_fp_clean(cntx);
 	}
@@ -89,7 +89,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu,
 	void *reg_val;
 
 	if ((rtype == KVM_REG_RISCV_FP_F) &&
-	    riscv_isa_extension_available(vcpu->arch.isa, f)) {
+	    riscv_isa_extension_available(vcpu->arch.isa, F)) {
 		if (KVM_REG_SIZE(reg->id) != sizeof(u32))
 			return -EINVAL;
 		if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr))
@@ -102,7 +102,7 @@ int kvm_riscv_vcpu_get_reg_fp(struct kvm_vcpu *vcpu,
 		} else
 			return -ENOENT;
 	} else if ((rtype == KVM_REG_RISCV_FP_D) &&
-		   riscv_isa_extension_available(vcpu->arch.isa, d)) {
+		   riscv_isa_extension_available(vcpu->arch.isa, D)) {
 		if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) {
 			if (KVM_REG_SIZE(reg->id) != sizeof(u32))
 				return -EINVAL;
@@ -138,7 +138,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu,
 	void *reg_val;
 
 	if ((rtype == KVM_REG_RISCV_FP_F) &&
-	    riscv_isa_extension_available(vcpu->arch.isa, f)) {
+	    riscv_isa_extension_available(vcpu->arch.isa, F)) {
 		if (KVM_REG_SIZE(reg->id) != sizeof(u32))
 			return -EINVAL;
 		if (reg_num == KVM_REG_RISCV_FP_F_REG(fcsr))
@@ -151,7 +151,7 @@ int kvm_riscv_vcpu_set_reg_fp(struct kvm_vcpu *vcpu,
 		} else
 			return -ENOENT;
 	} else if ((rtype == KVM_REG_RISCV_FP_D) &&
-		   riscv_isa_extension_available(vcpu->arch.isa, d)) {
+		   riscv_isa_extension_available(vcpu->arch.isa, D)) {
 		if (reg_num == KVM_REG_RISCV_FP_D_REG(fcsr)) {
 			if (KVM_REG_SIZE(reg->id) != sizeof(u32))
 				return -EINVAL;
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index bb920e8923c93..5cc7ddd4aa276 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -770,7 +770,7 @@ static inline unsigned long num_fp_f_regs(const struct kvm_vcpu *vcpu)
 {
 	const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
 
-	if (riscv_isa_extension_available(vcpu->arch.isa, f))
+	if (riscv_isa_extension_available(vcpu->arch.isa, F))
 		return sizeof(cntx->fp.f) / sizeof(u32);
 	else
 		return 0;
@@ -799,7 +799,7 @@ static inline unsigned long num_fp_d_regs(const struct kvm_vcpu *vcpu)
 {
 	const struct kvm_cpu_context *cntx = &vcpu->arch.guest_context;
 
-	if (riscv_isa_extension_available(vcpu->arch.isa, d))
+	if (riscv_isa_extension_available(vcpu->arch.isa, D))
 		return sizeof(cntx->fp.d.f) / sizeof(u64) + 1;
 	else
 		return 0;
@@ -878,7 +878,7 @@ static inline unsigned long num_sbi_regs(struct kvm_vcpu *vcpu)
 
 static inline unsigned long num_vector_regs(const struct kvm_vcpu *vcpu)
 {
-	if (!riscv_isa_extension_available(vcpu->arch.isa, v))
+	if (!riscv_isa_extension_available(vcpu->arch.isa, V))
 		return 0;
 
 	/* vstart, vl, vtype, vcsr, vlenb and 32 vector regs */
diff --git a/arch/riscv/kvm/vcpu_vector.c b/arch/riscv/kvm/vcpu_vector.c
index 62d2fb77bb9b9..f26108a4e601e 100644
--- a/arch/riscv/kvm/vcpu_vector.c
+++ b/arch/riscv/kvm/vcpu_vector.c
@@ -26,7 +26,7 @@ void kvm_riscv_vcpu_vector_reset(struct kvm_vcpu *vcpu)
 
 	cntx->vector.vlenb = riscv_v_vsize / 32;
 
-	if (riscv_isa_extension_available(isa, v)) {
+	if (riscv_isa_extension_available(isa, V)) {
 		cntx->sstatus |= SR_VS_INITIAL;
 		WARN_ON(!cntx->vector.datap);
 		memset(cntx->vector.datap, 0, riscv_v_vsize);
@@ -45,7 +45,7 @@ void kvm_riscv_vcpu_guest_vector_save(struct kvm_cpu_context *cntx,
 				      unsigned long *isa)
 {
 	if ((cntx->sstatus & SR_VS) == SR_VS_DIRTY) {
-		if (riscv_isa_extension_available(isa, v))
+		if (riscv_isa_extension_available(isa, V))
 			__kvm_riscv_vector_save(cntx);
 		kvm_riscv_vcpu_vector_clean(cntx);
 	}
@@ -55,7 +55,7 @@ void kvm_riscv_vcpu_guest_vector_restore(struct kvm_cpu_context *cntx,
 					 unsigned long *isa)
 {
 	if ((cntx->sstatus & SR_VS) != SR_VS_OFF) {
-		if (riscv_isa_extension_available(isa, v))
+		if (riscv_isa_extension_available(isa, V))
 			__kvm_riscv_vector_restore(cntx);
 		kvm_riscv_vcpu_vector_clean(cntx);
 	}
@@ -154,7 +154,7 @@ int kvm_riscv_vcpu_get_reg_vector(struct kvm_vcpu *vcpu,
 	void *reg_addr;
 	int rc;
 
-	if (!riscv_isa_extension_available(isa, v))
+	if (!riscv_isa_extension_available(isa, V))
 		return -ENOENT;
 
 	rc = kvm_riscv_vcpu_vreg_addr(vcpu, reg_num, reg_size, &reg_addr);
@@ -180,7 +180,7 @@ int kvm_riscv_vcpu_set_reg_vector(struct kvm_vcpu *vcpu,
 	void *reg_addr;
 	int rc;
 
-	if (!riscv_isa_extension_available(isa, v))
+	if (!riscv_isa_extension_available(isa, V))
 		return -ENOENT;
 
 	if (reg_num == KVM_REG_RISCV_VECTOR_CSR_REG(vlenb)) {

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:42 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:42 -0400
Subject: [PATCH v4 05/16] riscv: Add Zicclsm to cpufeature and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-5-3f01a2449488@gmail.com>

From: Jesse Taube <jesse at rivosinc.com>

Zicclsm requires misaligned support for all regular load and store
instructions, both scalar and vector, but not AMOs or other
specialized forms of memory access, to main memory regions with both
the cacheability and coherence PMAs, as defined in the profiles spec.
Even though mandated, misaligned loads and stores might execute
extremely slowly. Standard software distributions should assume their
existence only for correctness, not for performance.

Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
Reviewed-by: Andy Chiu <andy.chiu at sifive.com>
Reviewed-by: Charlie Jenkins <charlie at rivosinc.com>
Tested-by: Charlie Jenkins <charlie at rivosinc.com>
Signed-off-by: Jesse Taube <jesse at rivosinc.com>
[Rebased, rewrote doc text, minor commit message revisions]
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>

---
v4: No change.
v3:
- Move the hwprobe.rst entry to the IMA_EXT_1 section so its
  documentation matches the IMA_EXT_1 bit it was allocated in v2
  (Sashiko, agreed by Andrew).
v2:
- Rebased onto v7.1-rc2; moved ZICCLSM to IMA_EXT_1 and
  allocated a new bit for it
---
 Documentation/arch/riscv/hwprobe.rst  | 4 ++++
 arch/riscv/include/asm/hwcap.h        | 1 +
 arch/riscv/include/uapi/asm/hwprobe.h | 1 +
 arch/riscv/kernel/cpufeature.c        | 1 +
 arch/riscv/kernel/sys_hwprobe.c       | 1 +
 5 files changed, 8 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index d9928641deb99..49d9fb68632d0 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -401,3 +401,7 @@ The following keys are defined:
     as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
     extensions specification, ratified in commit 302a2d45c243
     ("Update build-pdf.yml") of riscv-cfi.
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICCLSM`: The Zicclsm extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 44bf8c7d8acc5..e8f4a7dd96a93 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -112,6 +112,7 @@
 #define RISCV_ISA_EXT_ZCLSD		103
 #define RISCV_ISA_EXT_ZICFILP		104
 #define RISCV_ISA_EXT_ZICFISS		105
+#define RISCV_ISA_EXT_ZICCLSM		106
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 9139edba0aecb..6819df159c51e 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -116,6 +116,7 @@ struct riscv_hwprobe {
 #define RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE	15
 #define RISCV_HWPROBE_KEY_IMA_EXT_1		16
 #define		RISCV_HWPROBE_EXT_ZICFISS	(1ULL << 0)
+#define		RISCV_HWPROBE_EXT_ZICCLSM	(1ULL << 1)
 
 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 686dde3ce3b98..1fb595581adcf 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -502,6 +502,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
+	__RISCV_ISA_EXT_DATA(zicclsm, RISCV_ISA_EXT_ZICCLSM),
 	__RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicfilp, RISCV_ISA_EXT_ZICFILP, riscv_xlinuxenvcfg_exts,
 					  riscv_cfilp_validate),
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index f8f68ba781b45..9cf62266f1890 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -205,6 +205,7 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
 		 * in the hart_isa bitmap, are made.
 		 */
 		EXT_KEY(isainfo->isa, ZICFISS, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZICCLSM, pair->value, missing);
 	}
 
 	/* Now turn off reporting features if any CPU is missing it. */

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:43 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:43 -0400
Subject: [PATCH v4 06/16] riscv: Add Ziccamoa, Ziccif, Ziccrse, and Za64rs
 to cpufeature and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-6-3f01a2449488@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

Add Ziccamoa, Ziccif, and Za64rs to riscv_isa_ext[] so they can be
parsed from devicetree/ACPI ISA strings. Ziccrse is already present
in cpufeature; this patch only adds its hwprobe exposure.

Expose all four extensions via hwprobe through new bits in
RISCV_HWPROBE_KEY_IMA_EXT_1 (RISCV_HWPROBE_EXT_ZICCAMOA, _ZICCIF,
_ZICCRSE, _ZA64RS), so userspace can probe each of these
RVA23U64-mandatory extensions individually.

Rationale for the validation dependencies added for Ziccamoa and Za64rs:

1) Ziccamoa depends on Zaamo.  The RVA23 profile prose was updated
post-ratification to spell out the Zaamo reference: commit
2b218613752d in riscv/riscv-profiles ("Improve description of
Ziccamoa (#224)") reworded the rva23-profile.adoc (and other profiles
that include Ziccamoa) text from "must support all atomics in A" to
"must support all atomics in the Zaamo extension" [1].

2) Za64rs depends on Zalrsc. The unprivileged ISA manual src/zars.adoc,
integrated in commit ebe06adc22cd ("Integrate profiles as Volume III
(#2771)"), defines Za64rs as: "The Za64rs extension requires that the
reservation sets used by the instructions in the Zalrsc extension be
contiguous, naturally aligned, and at most 64 bytes in size" [2].

Link: https://github.com/riscv/riscv-profiles/commit/2b218613752d63287286b5ae801b820cbd8cc10c [1]
Link: https://github.com/riscv/riscv-isa-manual/blob/main/src/unpriv/zars.adoc [2]
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: No change.
v3: Indent the added hwprobe.rst entries to match the normalized style; no other change.
v2:
- Rebased to v7.1-rc2.
- Reworded subject and expanded commit message.
- Validation added for Ziccamoa depending on Zaamo and Za64rs depending
  on Zalrsc.
---
 Documentation/arch/riscv/hwprobe.rst  | 16 ++++++++++++++++
 arch/riscv/include/asm/hwcap.h        |  3 +++
 arch/riscv/include/uapi/asm/hwprobe.h |  4 ++++
 arch/riscv/kernel/cpufeature.c        | 21 +++++++++++++++++++++
 arch/riscv/kernel/sys_hwprobe.c       |  4 ++++
 5 files changed, 48 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index 49d9fb68632d0..893e1a1215d23 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -405,3 +405,19 @@ The following keys are defined:
   * :c:macro:`RISCV_HWPROBE_EXT_ZICCLSM`: The Zicclsm extension is supported,
     as defined in the RISC-V Profiles specification starting from commit
     b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICCAMOA`: The Ziccamoa extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICCIF`: The Ziccif extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZICCRSE`: The Ziccrse extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZA64RS`: The Za64rs extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index e8f4a7dd96a93..0acb7a01ecc0f 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -113,6 +113,9 @@
 #define RISCV_ISA_EXT_ZICFILP		104
 #define RISCV_ISA_EXT_ZICFISS		105
 #define RISCV_ISA_EXT_ZICCLSM		106
+#define RISCV_ISA_EXT_ZICCAMOA		107
+#define RISCV_ISA_EXT_ZICCIF		108
+#define RISCV_ISA_EXT_ZA64RS		109
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 6819df159c51e..58d1e86e47ae7 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -117,6 +117,10 @@ struct riscv_hwprobe {
 #define RISCV_HWPROBE_KEY_IMA_EXT_1		16
 #define		RISCV_HWPROBE_EXT_ZICFISS	(1ULL << 0)
 #define		RISCV_HWPROBE_EXT_ZICCLSM	(1ULL << 1)
+#define		RISCV_HWPROBE_EXT_ZICCAMOA	(1ULL << 2)
+#define		RISCV_HWPROBE_EXT_ZICCIF	(1ULL << 3)
+#define		RISCV_HWPROBE_EXT_ZICCRSE	(1ULL << 4)
+#define		RISCV_HWPROBE_EXT_ZA64RS	(1ULL << 5)
 
 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 1fb595581adcf..b9538e69fa1b3 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -90,6 +90,24 @@ static int riscv_ext_f_depends(const struct riscv_isa_ext_data *data,
 	return -EPROBE_DEFER;
 }
 
+static int riscv_ext_zaamo_depends(const struct riscv_isa_ext_data *data,
+				   const unsigned long *isa_bitmap)
+{
+	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZAAMO))
+		return 0;
+
+	return -EPROBE_DEFER;
+}
+
+static int riscv_ext_zalrsc_depends(const struct riscv_isa_ext_data *data,
+				    const unsigned long *isa_bitmap)
+{
+	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZALRSC))
+		return 0;
+
+	return -EPROBE_DEFER;
+}
+
 static int riscv_ext_zicbom_validate(const struct riscv_isa_ext_data *data,
 				     const unsigned long *isa_bitmap)
 {
@@ -502,6 +520,8 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
+	__RISCV_ISA_EXT_DATA_VALIDATE(ziccamoa, RISCV_ISA_EXT_ZICCAMOA, riscv_ext_zaamo_depends),
+	__RISCV_ISA_EXT_DATA(ziccif, RISCV_ISA_EXT_ZICCIF),
 	__RISCV_ISA_EXT_DATA(zicclsm, RISCV_ISA_EXT_ZICCLSM),
 	__RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicfilp, RISCV_ISA_EXT_ZICFILP, riscv_xlinuxenvcfg_exts,
@@ -516,6 +536,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_DATA(zihintpause, RISCV_ISA_EXT_ZIHINTPAUSE),
 	__RISCV_ISA_EXT_DATA(zihpm, RISCV_ISA_EXT_ZIHPM),
 	__RISCV_ISA_EXT_DATA(zimop, RISCV_ISA_EXT_ZIMOP),
+	__RISCV_ISA_EXT_DATA_VALIDATE(za64rs, RISCV_ISA_EXT_ZA64RS, riscv_ext_zalrsc_depends),
 	__RISCV_ISA_EXT_DATA(zaamo, RISCV_ISA_EXT_ZAAMO),
 	__RISCV_ISA_EXT_DATA(zabha, RISCV_ISA_EXT_ZABHA),
 	__RISCV_ISA_EXT_DATA(zacas, RISCV_ISA_EXT_ZACAS),
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 9cf62266f1890..b15ac9adf7920 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -206,6 +206,10 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
 		 */
 		EXT_KEY(isainfo->isa, ZICFISS, pair->value, missing);
 		EXT_KEY(isainfo->isa, ZICCLSM, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZICCAMOA, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZICCIF, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZICCRSE, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZA64RS, pair->value, missing);
 	}
 
 	/* Now turn off reporting features if any CPU is missing it. */

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:44 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:44 -0400
Subject: [PATCH v4 07/16] riscv: Add B to hwcap and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-7-3f01a2449488@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

Add B to hwcap and ensure when B is present that Zba, Zbb, and Zbs
are all set. Also expose B via hwprobe (RISCV_HWPROBE_EXT_B in
RISCV_HWPROBE_KEY_IMA_EXT_1) so that userspace can probe B directly,
mirroring the F/D/C/V pattern where each is reported via both hwcap
and hwprobe.

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
[Add B to hwprobe]
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: No change.
v3:
- Indent the added hwprobe.rst entry to match the normalized style.
- Rebased onto v7.1-rc6: index isa2hwcap[] via RISCV_ISA_EXT_B to match the
  macro-ization in commit 41337097f2823.
v2:
- Rebased to v7.1-rc2
- Add B to hwprobe (RISCV_HWPROBE_EXT_B at IMA_EXT_1 bit 6) and
  document it in hwprobe.rst, so userspace can probe B directly.
---
 Documentation/arch/riscv/hwprobe.rst  | 4 ++++
 arch/riscv/include/asm/hwcap.h        | 1 +
 arch/riscv/include/uapi/asm/hwcap.h   | 1 +
 arch/riscv/include/uapi/asm/hwprobe.h | 1 +
 arch/riscv/kernel/cpufeature.c        | 8 ++++++++
 arch/riscv/kernel/sys_hwprobe.c       | 1 +
 6 files changed, 16 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index 893e1a1215d23..fc68dea397aae 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -421,3 +421,7 @@ The following keys are defined:
   * :c:macro:`RISCV_HWPROBE_EXT_ZA64RS`: The Za64rs extension is supported,
     as defined in the RISC-V Profiles specification starting from commit
     b1d80660 ("Updated to ratified state.")
+
+  * :c:macro:`RISCV_HWPROBE_EXT_B`: The B extension is supported, as defined
+    in version 1.0 of the Bit-Manipulation ISA extensions, and implies the
+    presence of the Zba, Zbb, and Zbs sub-extensions.
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 0acb7a01ecc0f..58523b3a1998a 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -11,6 +11,7 @@
 #include <uapi/asm/hwcap.h>
 
 #define RISCV_ISA_EXT_A		('a' - 'a')
+#define RISCV_ISA_EXT_B		('b' - 'a')
 #define RISCV_ISA_EXT_C		('c' - 'a')
 #define RISCV_ISA_EXT_D		('d' - 'a')
 #define RISCV_ISA_EXT_F		('f' - 'a')
diff --git a/arch/riscv/include/uapi/asm/hwcap.h b/arch/riscv/include/uapi/asm/hwcap.h
index c52bb7bbbabe9..96b7cf854e090 100644
--- a/arch/riscv/include/uapi/asm/hwcap.h
+++ b/arch/riscv/include/uapi/asm/hwcap.h
@@ -21,6 +21,7 @@
 #define COMPAT_HWCAP_ISA_F	(1 << ('F' - 'A'))
 #define COMPAT_HWCAP_ISA_D	(1 << ('D' - 'A'))
 #define COMPAT_HWCAP_ISA_C	(1 << ('C' - 'A'))
+#define COMPAT_HWCAP_ISA_B	(1 << ('B' - 'A'))
 #define COMPAT_HWCAP_ISA_V	(1 << ('V' - 'A'))
 
 #endif /* _UAPI_ASM_RISCV_HWCAP_H */
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 58d1e86e47ae7..430dc49a82863 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -121,6 +121,7 @@ struct riscv_hwprobe {
 #define		RISCV_HWPROBE_EXT_ZICCIF	(1ULL << 3)
 #define		RISCV_HWPROBE_EXT_ZICCRSE	(1ULL << 4)
 #define		RISCV_HWPROBE_EXT_ZA64RS	(1ULL << 5)
+#define		RISCV_HWPROBE_EXT_B		(1ULL << 6)
 
 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index b9538e69fa1b3..e0197160af6dd 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -468,6 +468,12 @@ static const unsigned int riscv_c_exts[] = {
 	RISCV_ISA_EXT_ZCD,
 };
 
+static const unsigned int riscv_b_exts[] = {
+	RISCV_ISA_EXT_ZBA,
+	RISCV_ISA_EXT_ZBB,
+	RISCV_ISA_EXT_ZBS,
+};
+
 /*
  * The canonical order of ISA extension names in the ISA string is defined in
  * chapter 27 of the unprivileged specification.
@@ -515,6 +521,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_DATA_VALIDATE(d, RISCV_ISA_EXT_D, riscv_ext_d_validate),
 	__RISCV_ISA_EXT_DATA(q, RISCV_ISA_EXT_Q),
 	__RISCV_ISA_EXT_SUPERSET(c, RISCV_ISA_EXT_C, riscv_c_exts),
+	__RISCV_ISA_EXT_SUPERSET(b, RISCV_ISA_EXT_B, riscv_b_exts),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate),
 	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
@@ -1133,6 +1140,7 @@ void __init riscv_fill_hwcap(void)
 	isa2hwcap[RISCV_ISA_EXT_F] = COMPAT_HWCAP_ISA_F;
 	isa2hwcap[RISCV_ISA_EXT_D] = COMPAT_HWCAP_ISA_D;
 	isa2hwcap[RISCV_ISA_EXT_C] = COMPAT_HWCAP_ISA_C;
+	isa2hwcap[RISCV_ISA_EXT_B] = COMPAT_HWCAP_ISA_B;
 	isa2hwcap[RISCV_ISA_EXT_V] = COMPAT_HWCAP_ISA_V;
 
 	if (!acpi_disabled) {
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index b15ac9adf7920..dcc102bf8f183 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -210,6 +210,7 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
 		EXT_KEY(isainfo->isa, ZICCIF, pair->value, missing);
 		EXT_KEY(isainfo->isa, ZICCRSE, pair->value, missing);
 		EXT_KEY(isainfo->isa, ZA64RS, pair->value, missing);
+		EXT_KEY(isainfo->isa, B, pair->value, missing);
 	}
 
 	/* Now turn off reporting features if any CPU is missing it. */

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:45 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:45 -0400
Subject: [PATCH v4 08/16] dt-bindings: riscv: Add Zic64b extension
 description
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-8-3f01a2449488@gmail.com>

Zic64b mandates that cache blocks are 64 bytes in size and naturally
aligned in the address space.  It is a mandatory extension of both the
RVA22 (U64/S64) and RVA23 (U64/S64) profiles, ratified with RISC-V
Profiles Version 1.0.

Document it so it can be described in the riscv,isa-extensions property,
alongside the related Zicbom/Zicbop/Zicboz cache-block extensions. Since
Zic64b fixes the cache block size at 64 bytes, also add a  schema check
requiring any present cbom/cbop/cboz block size to be 64.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: Insert zic64b at its sorted position (before zicbom).
    Update the commit message.
v3: New patch.
---
 .../devicetree/bindings/riscv/extensions.yaml        | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 5ffc40d599c02..1c24999beb59e 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -494,6 +494,12 @@ properties:
             in commit 64074bc ("Update version numbers for Zfh/Zfinx") of
             riscv-isa-manual.
 
+        - const: zic64b
+          description:
+            The standard Zic64b extension for 64-byte naturally aligned cache
+            blocks, as ratified in RISC-V Profiles Version 1.0, with commit
+            b1d806605f87 ("Updated to ratified state.")
+
         - const: zicbom
           description:
             The standard Zicbom extension for base cache management operations as
@@ -1142,6 +1148,20 @@ allOf:
           not:
             contains:
               const: zilsd
+  # Zic64b mandates 64-byte naturally aligned cache blocks
+  - if:
+      properties:
+        riscv,isa-extensions:
+          contains:
+            const: zic64b
+    then:
+      properties:
+        riscv,cbom-block-size:
+          const: 64
+        riscv,cbop-block-size:
+          const: 64
+        riscv,cboz-block-size:
+          const: 64
 
 additionalProperties: true
 ...

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:46 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:46 -0400
Subject: [PATCH v4 09/16] riscv: Add Zic64b to cpufeature and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-9-3f01a2449488@gmail.com>

From: Qingwei Hu <qingwei.hu at bytedance.com>

Zic64b mandates 64-byte naturally aligned cache blocks and is a
mandatory extension of the RVA22 and RVA23 profiles.  Allocate a
RISCV_ISA_EXT_ZIC64B id, parse "zic64b" from the ISA string with a
validate callback that requires each cbom/cbop/cboz cache block size to
be 64 bytes when it is present, and export it through hwprobe.

Link: https://lists.riscv.org/g/tech-unprivileged/topic/question_about_zic64b_and/119631059
Signed-off-by: Qingwei Hu <qingwei.hu at bytedance.com>
Co-developed-by: Guodong Xu <docular.xu at gmail.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4:
- Credit Qingwei Hu's earlier Zic64b cpufeature patch: set him as
  author, with Co-developed-by (Guodong Xu).
- Validate only the cbom/cbop/cboz block sizes that are present; Zic64b
  does not imply the CMO extensions (Conor, Qingwei, Greg).
- Add a Link: to Greg's confirmation on the tech-unprivileged list.
- Add the missing blank line before the ZIC64B hwprobe.rst entry
  (Andrew).
- Did not carry Andrew Jones's v3 Reviewed-by: the validation was
  rewritten (present block sizes only) and the patch is now authored by
  Qingwei, so it warrants a fresh review.
v3: New patch.
---
 Documentation/arch/riscv/hwprobe.rst  |  4 ++++
 arch/riscv/include/asm/hwcap.h        |  1 +
 arch/riscv/include/uapi/asm/hwprobe.h |  1 +
 arch/riscv/kernel/cpufeature.c        | 19 +++++++++++++++++++
 arch/riscv/kernel/sys_hwprobe.c       |  1 +
 5 files changed, 26 insertions(+)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index fc68dea397aae..32a14331eb9de 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -425,3 +425,7 @@ The following keys are defined:
   * :c:macro:`RISCV_HWPROBE_EXT_B`: The B extension is supported, as defined
     in version 1.0 of the Bit-Manipulation ISA extensions, and implies the
     presence of the Zba, Zbb, and Zbs sub-extensions.
+
+  * :c:macro:`RISCV_HWPROBE_EXT_ZIC64B`: The Zic64b extension is supported,
+    as defined in the RISC-V Profiles specification starting from commit
+    b1d80660 ("Updated to ratified state.")
diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
index 58523b3a1998a..36572c1ff438a 100644
--- a/arch/riscv/include/asm/hwcap.h
+++ b/arch/riscv/include/asm/hwcap.h
@@ -117,6 +117,7 @@
 #define RISCV_ISA_EXT_ZICCAMOA		107
 #define RISCV_ISA_EXT_ZICCIF		108
 #define RISCV_ISA_EXT_ZA64RS		109
+#define RISCV_ISA_EXT_ZIC64B		110
 
 #define RISCV_ISA_EXT_XLINUXENVCFG	127
 
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 430dc49a82863..36ec8ab470423 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -122,6 +122,7 @@ struct riscv_hwprobe {
 #define		RISCV_HWPROBE_EXT_ZICCRSE	(1ULL << 4)
 #define		RISCV_HWPROBE_EXT_ZA64RS	(1ULL << 5)
 #define		RISCV_HWPROBE_EXT_B		(1ULL << 6)
+#define		RISCV_HWPROBE_EXT_ZIC64B	(1ULL << 7)
 
 /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
 
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index e0197160af6dd..29dff41313e65 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -154,6 +154,24 @@ static int riscv_ext_zicbop_validate(const struct riscv_isa_ext_data *data,
 	return 0;
 }
 
+static int riscv_ext_zic64b_validate(const struct riscv_isa_ext_data *data,
+				     const unsigned long *isa_bitmap)
+{
+	/*
+	 * Zic64b mandates 64-byte naturally aligned cache blocks; cross-check the
+	 * cbom/cbop/cboz block-size (when declared) device-tree properties to
+	 * avoid inconsistency.
+	 */
+	if ((riscv_cbom_block_size && riscv_cbom_block_size != 64) ||
+	    (riscv_cbop_block_size && riscv_cbop_block_size != 64) ||
+	    (riscv_cboz_block_size && riscv_cboz_block_size != 64)) {
+		pr_err("Zic64b detected in ISA string, disabling as a CBO block size is not 64 bytes\n");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int riscv_ext_f_validate(const struct riscv_isa_ext_data *data,
 				const unsigned long *isa_bitmap)
 {
@@ -524,6 +542,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_SUPERSET(b, RISCV_ISA_EXT_B, riscv_b_exts),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(v, RISCV_ISA_EXT_V, riscv_v_exts, riscv_ext_vector_float_validate),
 	__RISCV_ISA_EXT_DATA(h, RISCV_ISA_EXT_H),
+	__RISCV_ISA_EXT_DATA_VALIDATE(zic64b, RISCV_ISA_EXT_ZIC64B, riscv_ext_zic64b_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
 	__RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
 	__RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index dcc102bf8f183..3e80e5551ae0d 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -211,6 +211,7 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
 		EXT_KEY(isainfo->isa, ZICCRSE, pair->value, missing);
 		EXT_KEY(isainfo->isa, ZA64RS, pair->value, missing);
 		EXT_KEY(isainfo->isa, B, pair->value, missing);
+		EXT_KEY(isainfo->isa, ZIC64B, pair->value, missing);
 	}
 
 	/* Now turn off reporting features if any CPU is missing it. */

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:48 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:48 -0400
Subject: [PATCH v4 11/16] riscv: dts: spacemit: k1: Add Zic64b ISA
 extension
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-11-3f01a2449488@gmail.com>

The K1 X60 cores have 64-byte cache blocks, described by their
cbom/cbop/cboz-block-size of 64, so they implement Zic64b.  Declare it in
each core's riscv,isa-extensions and in the deprecated riscv,isa string.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: No change.
v3: New patch.
---
 arch/riscv/boot/dts/spacemit/k1.dtsi | 80 ++++++++++++++++++------------------
 1 file changed, 40 insertions(+), 40 deletions(-)

diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index f0bad6855c970..e6fc684ad3898 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -54,12 +54,12 @@ cpu_0: cpu at 0 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <0>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -84,12 +84,12 @@ cpu_1: cpu at 1 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <1>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -114,12 +114,12 @@ cpu_2: cpu at 2 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <2>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -144,12 +144,12 @@ cpu_3: cpu at 3 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <3>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -174,12 +174,12 @@ cpu_4: cpu at 4 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <4>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -204,12 +204,12 @@ cpu_5: cpu at 5 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <5>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -234,12 +234,12 @@ cpu_6: cpu at 6 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <6>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;
@@ -264,12 +264,12 @@ cpu_7: cpu at 7 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <7>;
-			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
+			riscv,isa = "rv64imafdcbv_zic64b_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
-			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
-					       "zicbop", "zicboz", "zicntr", "zicond", "zicsr",
-					       "zifencei", "zihintpause", "zihpm", "zfh", "zba",
-					       "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
+			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zic64b",
+					       "zicbom", "zicbop", "zicboz", "zicntr", "zicond",
+					       "zicsr", "zifencei", "zihintpause", "zihpm", "zfh",
+					       "zba", "zbb", "zbc", "zbs", "zkt", "zvfh", "zvkt",
 					       "sscofpmf", "sstc", "svinval", "svnapot", "svpbmt";
 			riscv,cbom-block-size = <64>;
 			riscv,cbop-block-size = <64>;

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:49 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:49 -0400
Subject: [PATCH v4 12/16] riscv: dts: sophgo: sg2044: Add Zic64b ISA
 extension
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-12-3f01a2449488@gmail.com>

The SG2044 cores have 64-byte cache blocks, described by their
cbom/cbop/cboz-block-size of 64, so they implement Zic64b.  Declare it in
each core's riscv,isa-extensions.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
Acked-by: Inochi Amaoto <inochiama at gmail.com>
---
v4: Add Inochi Amaoto's Acked-by.
v3: New patch.
---
 arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi | 128 ++++++++++++++--------------
 1 file changed, 64 insertions(+), 64 deletions(-)

diff --git a/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi b/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
index 3135409c21492..2ac4a41bbc3a7 100644
--- a/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
+++ b/arch/riscv/boot/dts/sophgo/sg2044-cpus.dtsi
@@ -31,7 +31,7 @@ cpu0: cpu at 0 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -67,7 +67,7 @@ cpu1: cpu at 1 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -103,7 +103,7 @@ cpu2: cpu at 2 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -139,7 +139,7 @@ cpu3: cpu at 3 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -175,7 +175,7 @@ cpu4: cpu at 4 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -211,7 +211,7 @@ cpu5: cpu at 5 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -247,7 +247,7 @@ cpu6: cpu at 6 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -283,7 +283,7 @@ cpu7: cpu at 7 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -319,7 +319,7 @@ cpu8: cpu at 8 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -355,7 +355,7 @@ cpu9: cpu at 9 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -391,7 +391,7 @@ cpu10: cpu at 10 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -427,7 +427,7 @@ cpu11: cpu at 11 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -463,7 +463,7 @@ cpu12: cpu at 12 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -499,7 +499,7 @@ cpu13: cpu at 13 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -535,7 +535,7 @@ cpu14: cpu at 14 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -571,7 +571,7 @@ cpu15: cpu at 15 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -607,7 +607,7 @@ cpu16: cpu at 16 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -643,7 +643,7 @@ cpu17: cpu at 17 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -679,7 +679,7 @@ cpu18: cpu at 18 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -715,7 +715,7 @@ cpu19: cpu at 19 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -751,7 +751,7 @@ cpu20: cpu at 20 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -787,7 +787,7 @@ cpu21: cpu at 21 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -823,7 +823,7 @@ cpu22: cpu at 22 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -859,7 +859,7 @@ cpu23: cpu at 23 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -895,7 +895,7 @@ cpu24: cpu at 24 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -931,7 +931,7 @@ cpu25: cpu at 25 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -967,7 +967,7 @@ cpu26: cpu at 26 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1003,7 +1003,7 @@ cpu27: cpu at 27 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1039,7 +1039,7 @@ cpu28: cpu at 28 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1075,7 +1075,7 @@ cpu29: cpu at 29 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1111,7 +1111,7 @@ cpu30: cpu at 30 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1147,7 +1147,7 @@ cpu31: cpu at 31 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1183,7 +1183,7 @@ cpu32: cpu at 32 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1219,7 +1219,7 @@ cpu33: cpu at 33 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1255,7 +1255,7 @@ cpu34: cpu at 34 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1291,7 +1291,7 @@ cpu35: cpu at 35 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1327,7 +1327,7 @@ cpu36: cpu at 36 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1363,7 +1363,7 @@ cpu37: cpu at 37 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1399,7 +1399,7 @@ cpu38: cpu at 38 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1435,7 +1435,7 @@ cpu39: cpu at 39 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1471,7 +1471,7 @@ cpu40: cpu at 40 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1507,7 +1507,7 @@ cpu41: cpu at 41 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1543,7 +1543,7 @@ cpu42: cpu at 42 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1579,7 +1579,7 @@ cpu43: cpu at 43 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1615,7 +1615,7 @@ cpu44: cpu at 44 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1651,7 +1651,7 @@ cpu45: cpu at 45 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1687,7 +1687,7 @@ cpu46: cpu at 46 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1723,7 +1723,7 @@ cpu47: cpu at 47 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1759,7 +1759,7 @@ cpu48: cpu at 48 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1795,7 +1795,7 @@ cpu49: cpu at 49 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1831,7 +1831,7 @@ cpu50: cpu at 50 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1867,7 +1867,7 @@ cpu51: cpu at 51 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1903,7 +1903,7 @@ cpu52: cpu at 52 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1939,7 +1939,7 @@ cpu53: cpu at 53 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -1975,7 +1975,7 @@ cpu54: cpu at 54 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2011,7 +2011,7 @@ cpu55: cpu at 55 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2047,7 +2047,7 @@ cpu56: cpu at 56 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2083,7 +2083,7 @@ cpu57: cpu at 57 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2119,7 +2119,7 @@ cpu58: cpu at 58 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2155,7 +2155,7 @@ cpu59: cpu at 59 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2191,7 +2191,7 @@ cpu60: cpu at 60 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2227,7 +2227,7 @@ cpu61: cpu at 61 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2263,7 +2263,7 @@ cpu62: cpu at 62 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",
@@ -2299,7 +2299,7 @@ cpu63: cpu at 63 {
 					       "svinval", "svnapot", "svpbmt",
 					       "zawrs", "zba", "zbb", "zbc",
 					       "zbs", "zca", "zcb", "zcd",
-					       "zfa", "zfbfmin", "zfh", "zfhmin",
+					       "zfa", "zfbfmin", "zfh", "zfhmin", "zic64b",
 					       "zicbom", "zicbop", "zicboz", "ziccrse",
 					       "zicntr", "zicond","zicsr", "zifencei",
 					       "zihintntl", "zihintpause", "zihpm",

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:47 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:47 -0400
Subject: [PATCH v4 10/16] riscv: dts: spacemit: k3: Add Zic64b ISA
 extension
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-10-3f01a2449488@gmail.com>

The K3 X100 cores have 64-byte cache blocks, already described by their
cbom/cbop/cboz-block-size of 64, so they implement Zic64b, a mandatory
RVA23 extension.  Declare it in each core's riscv,isa-extensions.

Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: No change.
v3: New patch.
---
 arch/riscv/boot/dts/spacemit/k3.dtsi | 48 ++++++++++++++++++------------------
 1 file changed, 24 insertions(+), 24 deletions(-)

diff --git a/arch/riscv/boot/dts/spacemit/k3.dtsi b/arch/riscv/boot/dts/spacemit/k3.dtsi
index 4ac457399b583..b5aa983f0bfa1 100644
--- a/arch/riscv/boot/dts/spacemit/k3.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k3.dtsi
@@ -35,9 +35,9 @@ cpu_0: cpu at 0 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -76,9 +76,9 @@ cpu_1: cpu at 1 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -117,9 +117,9 @@ cpu_2: cpu at 2 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -158,9 +158,9 @@ cpu_3: cpu at 3 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -199,9 +199,9 @@ cpu_4: cpu at 4 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -240,9 +240,9 @@ cpu_5: cpu at 5 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -281,9 +281,9 @@ cpu_6: cpu at 6 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
@@ -322,9 +322,9 @@ cpu_7: cpu at 7 {
 					       "svinval", "svnapot", "svpbmt", "za64rs",
 					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
 					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
-					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
-					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
-					       "zicond", "zicsr", "zifencei", "zihintntl",
+					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
+					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
+					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
 					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
 					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
 					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:50 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:50 -0400
Subject: [PATCH v4 13/16] riscv: Add a getter for user PMLEN support
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-13-3f01a2449488@gmail.com>

From: Andrew Jones <andrew.jones at oss.qualcomm.com>

Querying whether a given user PMLEN is supported is needed for
RVA23U64 base detection from outside arch/riscv/kernel/process.c.
Add riscv_have_user_pmlen() to expose this.

Link: https://lore.kernel.org/linux-riscv/rfuwa7a3ebe76udmnwyrssjy7shkkgxntvhwzn6oquysj4tuyp at xzvpylcfhz53/
Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
[Guodong: replace exported booleans with getter per Andrew's suggestion]
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: No change.
v3: No change.
v2: Add a getter for user PMLEN.
---
 arch/riscv/include/asm/processor.h |  4 ++++
 arch/riscv/kernel/process.c        | 12 ++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/arch/riscv/include/asm/processor.h b/arch/riscv/include/asm/processor.h
index 812517b2cec13..febf51e127f70 100644
--- a/arch/riscv/include/asm/processor.h
+++ b/arch/riscv/include/asm/processor.h
@@ -214,6 +214,10 @@ long set_tagged_addr_ctrl(struct task_struct *task, unsigned long arg);
 long get_tagged_addr_ctrl(struct task_struct *task);
 #define SET_TAGGED_ADDR_CTRL(arg)	set_tagged_addr_ctrl(current, arg)
 #define GET_TAGGED_ADDR_CTRL()		get_tagged_addr_ctrl(current)
+
+bool riscv_have_user_pmlen(u8 len);
+#else
+static inline bool riscv_have_user_pmlen(u8 len) { return false; }
 #endif
 
 #endif /* __ASSEMBLER__ */
diff --git a/arch/riscv/kernel/process.c b/arch/riscv/kernel/process.c
index b2df7f72241a5..5d9cb108a6232 100644
--- a/arch/riscv/kernel/process.c
+++ b/arch/riscv/kernel/process.c
@@ -302,6 +302,18 @@ enum {
 static bool have_user_pmlen_7;
 static bool have_user_pmlen_16;
 
+bool riscv_have_user_pmlen(u8 len)
+{
+	switch (len) {
+	case PMLEN_7:
+		return have_user_pmlen_7;
+	case PMLEN_16:
+		return have_user_pmlen_16;
+	default:
+		return false;
+	}
+}
+
 /*
  * Control the relaxed ABI allowing tagged user addresses into the kernel.
  */

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:51 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:51 -0400
Subject: [PATCH v4 14/16] riscv: cpufeature: Introduce ISA bases bitmap and
 rva23u64 detection
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-14-3f01a2449488@gmail.com>

Introduce a per-hart and host-wide bitmap of conformant ISA "bases"
(named profile-class sets such as IMA and RVA23U64), computed at init
time by riscv_init_isa_bases().

Register riscv_init_isa_bases() as a subsys_initcall so it executes
after core_initcall(tagged_addr_init), which probes senvcfg.PMM and
populates have_user_pmlen_*.  Without that ordering,
riscv_have_user_pmlen(7) would still return its default false and the
RVA23U64 detection path would always bail.

Consider this as the cache that subsequent consumers (hwprobe's
RVA23U64 base behavior bit, /proc/cpuinfo's "isa bases" lines, etc.)
can read without recomputing. System-wide consistency are ensured.

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4:
- In riscv_set_isa_base(), reorder those __setbit(RISCV_ISA_EXT_X,m)
  lines to make them conform to the order they appear in the RVA23 1.0
  Profile.
v3:
- Add a blank line before the subsys_initcall() registration (Andrew).
- Set the local ext_mask with __set_bit() and test the mandate set with
  !bitmap_subset() (Sashiko).
- Require the Zic64b ISA extension in the RVA23U64 mask,
  instead of open-coded cache block-size check. (New, thoughts from Andrew)
v2:
- Implement riscv_init_isa_bases() that runs at system init time,
  after tagged_addr_init() populates have_user_pmlen_*.
- Split RVA23S64 placeholder into a future patch.
---
 arch/riscv/include/asm/cpufeature.h | 14 ++++++
 arch/riscv/kernel/cpufeature.c      | 90 +++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 739fcc84bf7b2..facc31b2960c6 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -25,10 +25,24 @@ struct riscv_cpuinfo {
 	unsigned long mimpid;
 };
 
+enum {
+	RISCV_ISA_BASE_IMA,
+	RISCV_ISA_BASE_RVA23U64,
+	RISCV_NR_ISA_BASES,
+};
+
+/**
+ * struct riscv_isainfo - per-hart ISA state
+ * @isa: bitmap of ISA extensions this hart implements
+ * @isa_bases: bitmap of profile bases this hart conforms to
+ */
 struct riscv_isainfo {
 	DECLARE_BITMAP(isa, RISCV_ISA_EXT_MAX);
+	DECLARE_BITMAP(isa_bases, RISCV_NR_ISA_BASES);
 };
 
+extern unsigned long riscv_isa_bases[BITS_TO_LONGS(RISCV_NR_ISA_BASES)];
+
 DECLARE_PER_CPU(struct riscv_cpuinfo, riscv_cpuinfo);
 
 extern const struct seq_operations cpuinfo_op;
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index 29dff41313e65..f398e522a71d2 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -41,6 +41,9 @@ unsigned long elf_hwcap __read_mostly;
 /* Host ISA bitmap */
 static DECLARE_BITMAP(riscv_isa, RISCV_ISA_EXT_MAX) __read_mostly;
 
+/* Host ISA bases bitmap */
+DECLARE_BITMAP(riscv_isa_bases, RISCV_NR_ISA_BASES) __read_mostly;
+
 /* Per-cpu ISA extensions. */
 struct riscv_isainfo hart_isa[NR_CPUS];
 
@@ -1322,3 +1325,90 @@ void __init_or_module riscv_cpufeature_patch_func(struct alt_entry *begin,
 	}
 }
 #endif
+
+/*
+ * Compute the set of profile bases (IMA, RVA23U64, ...) a hart
+ * conforms to, given its resolved ISA bitmap.
+ *
+ * If @isa_bitmap is NULL, the host ISA bitmap (the AND across all harts) is
+ * used.
+ */
+static void riscv_set_isa_bases(unsigned long *bases, const unsigned long *isa_bitmap)
+{
+	const unsigned long *isa = isa_bitmap ? isa_bitmap : riscv_isa;
+	DECLARE_BITMAP(ext_mask, RISCV_ISA_EXT_MAX) = { 0 };
+
+	/* IMA */
+	__set_bit(RISCV_ISA_EXT_I, ext_mask);
+	__set_bit(RISCV_ISA_EXT_M, ext_mask);
+	__set_bit(RISCV_ISA_EXT_A, ext_mask);
+
+	if (!bitmap_subset(ext_mask, isa, RISCV_ISA_EXT_MAX))
+		return;
+
+	set_bit(RISCV_ISA_BASE_IMA, bases);
+
+	/* RVA23U64 */
+
+	/* Supm with PMLEN=7 */
+	if (!riscv_have_user_pmlen(7))
+		return;
+
+	__set_bit(RISCV_ISA_EXT_F, ext_mask);
+	__set_bit(RISCV_ISA_EXT_D, ext_mask);
+	__set_bit(RISCV_ISA_EXT_C, ext_mask);
+	__set_bit(RISCV_ISA_EXT_B, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICSR, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICNTR, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIHPM, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICCIF, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICCRSE, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICCAMOA, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICCLSM, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZA64RS, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIHINTPAUSE, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIC64B, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICBOM, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICBOP, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICBOZ, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZFHMIN, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZKT, ext_mask);
+	__set_bit(RISCV_ISA_EXT_V, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZVFHMIN, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZVBB, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZVKT, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIHINTNTL, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZICOND, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZIMOP, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZCMOP, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZCB, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZFA, ext_mask);
+	__set_bit(RISCV_ISA_EXT_ZAWRS, ext_mask);
+	__set_bit(RISCV_ISA_EXT_SUPM, ext_mask);
+
+	if (!bitmap_subset(ext_mask, isa, RISCV_ISA_EXT_MAX))
+		return;
+
+	set_bit(RISCV_ISA_BASE_RVA23U64, bases);
+}
+
+/*
+ * Populate the host ISA bases bitmap (riscv_isa_bases) and each
+ * hart's per-cpu isa_bases.
+ */
+static int __init riscv_init_isa_bases(void)
+{
+	int cpu;
+
+	for_each_possible_cpu(cpu)
+		riscv_set_isa_bases(hart_isa[cpu].isa_bases, hart_isa[cpu].isa);
+
+	riscv_set_isa_bases(riscv_isa_bases, NULL);
+	return 0;
+}
+
+/*
+ * Registered as subsys_initcall so it runs after
+ * core_initcall(tagged_addr_init) populates have_user_pmlen_*.
+ */
+subsys_initcall(riscv_init_isa_bases);

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:53 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:53 -0400
Subject: [PATCH v4 16/16] riscv: hwprobe: Introduce rva23u64 base behavior
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-16-3f01a2449488@gmail.com>

Provide a hwprobe base-behavior bit so userspace can check RVA23U64
support in one call.  Without it, a consumer needs five hwprobe
calls and four prctl calls, which is error-prone to require of every
caller.  Most software treats RVA23U64 as a new base anyway, so
expose it directly.

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: No change.
v3: No change.
v2:
- Detect RVA23U64 by reading from the cached hart_isa[].isa_bases
  bitmap populated by riscv_init_isa_bases() at init time, sharing
  one source of truth with /proc/cpuinfo.
---
 Documentation/arch/riscv/hwprobe.rst               |  8 ++++++++
 arch/riscv/include/uapi/asm/hwprobe.h              |  3 ++-
 arch/riscv/kernel/sys_hwprobe.c                    | 23 +++++++++++++++-------
 tools/testing/selftests/riscv/hwprobe/which-cpus.c |  2 +-
 4 files changed, 27 insertions(+), 9 deletions(-)

diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
index 32a14331eb9de..dc70470093b1b 100644
--- a/Documentation/arch/riscv/hwprobe.rst
+++ b/Documentation/arch/riscv/hwprobe.rst
@@ -67,6 +67,14 @@ The following keys are defined:
       programs (it may still be executed in userspace via a
       kernel-controlled mechanism such as the vDSO).
 
+  * :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64`: Support for all mandatory
+    extensions of RVA23U64, as defined in the RISC-V Profiles specification
+    starting from commit 0273f3c921b6 ("rva23/rvb23 ratified").
+
+    The RVA23U64 base is based upon the IMA base and therefore IMA extension
+    keys (e.g. :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`:) may be used to probe
+    optional extensions.
+
 * :c:macro:`RISCV_HWPROBE_KEY_IMA_EXT_0`: A bitmask containing extensions
   that are compatible with the :c:macro:`RISCV_HWPROBE_BASE_BEHAVIOR_IMA`:
   base system behavior.
diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
index 36ec8ab470423..50733d3db7633 100644
--- a/arch/riscv/include/uapi/asm/hwprobe.h
+++ b/arch/riscv/include/uapi/asm/hwprobe.h
@@ -21,7 +21,8 @@ struct riscv_hwprobe {
 #define RISCV_HWPROBE_KEY_MARCHID	1
 #define RISCV_HWPROBE_KEY_MIMPID	2
 #define RISCV_HWPROBE_KEY_BASE_BEHAVIOR	3
-#define		RISCV_HWPROBE_BASE_BEHAVIOR_IMA	(1 << 0)
+#define		RISCV_HWPROBE_BASE_BEHAVIOR_IMA		(1 << 0)
+#define		RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64	(1 << 1)
 #define RISCV_HWPROBE_KEY_IMA_EXT_0	4
 #define		RISCV_HWPROBE_IMA_FD		(1 << 0)
 #define		RISCV_HWPROBE_IMA_C		(1 << 1)
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 3e80e5551ae0d..3f66f2e99d41a 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -226,6 +226,17 @@ static bool hwprobe_ext0_has(const struct cpumask *cpus, u64 ext)
 	return (pair.value & ext);
 }
 
+static bool hwprobe_has_isa_base(const struct cpumask *cpus, unsigned int base)
+{
+	int cpu;
+
+	for_each_cpu(cpu, cpus) {
+		if (!test_bit(base, hart_isa[cpu].isa_bases))
+			return false;
+	}
+	return true;
+}
+
 #if defined(CONFIG_RISCV_PROBE_UNALIGNED_ACCESS)
 static u64 hwprobe_misaligned(const struct cpumask *cpus)
 {
@@ -308,14 +319,12 @@ static void hwprobe_one_pair(struct riscv_hwprobe *pair,
 	case RISCV_HWPROBE_KEY_MIMPID:
 		hwprobe_arch_id(pair, cpus);
 		break;
-	/*
-	 * The kernel already assumes that the base single-letter ISA
-	 * extensions are supported on all harts, and only supports the
-	 * IMA base, so just cheat a bit here and tell that to
-	 * userspace.
-	 */
 	case RISCV_HWPROBE_KEY_BASE_BEHAVIOR:
-		pair->value = RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
+		pair->value = 0;
+		if (hwprobe_has_isa_base(cpus, RISCV_ISA_BASE_IMA))
+			pair->value |= RISCV_HWPROBE_BASE_BEHAVIOR_IMA;
+		if (hwprobe_has_isa_base(cpus, RISCV_ISA_BASE_RVA23U64))
+			pair->value |= RISCV_HWPROBE_BASE_BEHAVIOR_RVA23U64;
 		break;
 
 	case RISCV_HWPROBE_KEY_IMA_EXT_0:
diff --git a/tools/testing/selftests/riscv/hwprobe/which-cpus.c b/tools/testing/selftests/riscv/hwprobe/which-cpus.c
index 587feb198c049..f8c797b1d0fd9 100644
--- a/tools/testing/selftests/riscv/hwprobe/which-cpus.c
+++ b/tools/testing/selftests/riscv/hwprobe/which-cpus.c
@@ -105,7 +105,7 @@ int main(int argc, char **argv)
 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_BASE_BEHAVIOR, };
 	rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);
 	assert(rc == 0 && pairs[0].key == RISCV_HWPROBE_KEY_BASE_BEHAVIOR &&
-	       pairs[0].value == RISCV_HWPROBE_BASE_BEHAVIOR_IMA);
+	       (pairs[0].value & RISCV_HWPROBE_BASE_BEHAVIOR_IMA));
 
 	pairs[0] = (struct riscv_hwprobe){ .key = RISCV_HWPROBE_KEY_IMA_EXT_0, };
 	rc = riscv_hwprobe(pairs, 1, 0, NULL, 0);

-- 
2.43.0



From docular.xu at gmail.com  Thu Jun 11 13:12:52 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Thu, 11 Jun 2026 16:12:52 -0400
Subject: [PATCH v4 15/16] riscv: cpu: Output isa bases lines in cpuinfo
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
Message-ID: <20260611-rva23u64-hwprobe-v2-v4-15-3f01a2449488@gmail.com>

Output two new lines per processor in /proc/cpuinfo:

  isa bases       : <bases that all harts conform to>
  hart isa bases  : <bases that this specific hart conforms to>

These read directly from the cached riscv_isa_bases and
hart_isa[cpu].isa_bases bitmaps populated at boot by
riscv_init_isa_bases().

Example output on qemu booted with -cpu rva23s64,sv39=on,pmp=on
(showing only the new lines plus their neighbors for context):

  processor       : 0
  hart            : 4
  isa bases       : rv64ima rva23u64
  isa             : rv64imafdcbvh_zicbom_zicbop_...
  mmu             : sv39
  ...
  mimpid          : 0x0
  hart isa bases  : rv64ima rva23u64
  hart isa        : rv64imafdcbvh_zicbom_zicbop_...

Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
Signed-off-by: Guodong Xu <docular.xu at gmail.com>
---
v4: No change.
v3: No change.
v2:
- Read from the cached riscv_isa_bases and hart_isa[cpu_id].isa_bases
  bitmaps populated by riscv_init_isa_bases() at init time.
---
 arch/riscv/kernel/cpu.c | 26 ++++++++++++++++++++++++++
 1 file changed, 26 insertions(+)

diff --git a/arch/riscv/kernel/cpu.c b/arch/riscv/kernel/cpu.c
index 3dbc8cc557dd1..31e2857dcdcf1 100644
--- a/arch/riscv/kernel/cpu.c
+++ b/arch/riscv/kernel/cpu.c
@@ -305,6 +305,26 @@ static void print_mmu(struct seq_file *f)
 	seq_printf(f, "mmu\t\t: %s\n", sv_type);
 }
 
+static const char * const riscv_isa_base_names[] = {
+#ifdef CONFIG_32BIT
+	[RISCV_ISA_BASE_IMA] = "rv32ima",
+#else
+	[RISCV_ISA_BASE_IMA] = "rv64ima",
+#endif
+	[RISCV_ISA_BASE_RVA23U64] = "rva23u64",
+};
+
+static void print_isa_bases(struct seq_file *m, const unsigned long *isa_bases)
+{
+	unsigned int i;
+
+	for (i = 0; i < RISCV_NR_ISA_BASES; i++) {
+		if (test_bit(i, isa_bases))
+			seq_printf(m, " %s", riscv_isa_base_names[i]);
+	}
+	seq_puts(m, "\n");
+}
+
 static void *c_start(struct seq_file *m, loff_t *pos)
 {
 	if (*pos == nr_cpu_ids)
@@ -336,6 +356,9 @@ static int c_show(struct seq_file *m, void *v)
 	seq_printf(m, "processor\t: %lu\n", cpu_id);
 	seq_printf(m, "hart\t\t: %lu\n", cpuid_to_hartid_map(cpu_id));
 
+	seq_puts(m, "isa bases\t:");
+	print_isa_bases(m, riscv_isa_bases);
+
 	/*
 	 * For historical raisins, the isa: line is limited to the lowest common
 	 * denominator of extensions supported across all harts. A true list of
@@ -360,6 +383,9 @@ static int c_show(struct seq_file *m, void *v)
 	seq_printf(m, "marchid\t\t: 0x%lx\n", ci->marchid);
 	seq_printf(m, "mimpid\t\t: 0x%lx\n", ci->mimpid);
 
+	seq_puts(m, "hart isa bases\t:");
+	print_isa_bases(m, hart_isa[cpu_id].isa_bases);
+
 	/*
 	 * Print the ISA extensions specific to this hart, which may show
 	 * additional extensions not present across all harts.

-- 
2.43.0



From andrew.jones at oss.qualcomm.com  Thu Jun 11 13:50:07 2026
From: andrew.jones at oss.qualcomm.com (Andrew Jones)
Date: Thu, 11 Jun 2026 15:50:07 -0500
Subject: [PATCH v4 09/16] riscv: Add Zic64b to cpufeature and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-9-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
 <20260611-rva23u64-hwprobe-v2-v4-9-3f01a2449488@gmail.com>
Message-ID: <uttb7qknse5hk6suato3nelqatkrkoyo7r342pqay4wh6vyr4x@xestyyhoygtn>

On Thu, Jun 11, 2026 at 04:12:46PM -0400, Guodong Xu wrote:
> From: Qingwei Hu <qingwei.hu at bytedance.com>
> 
> Zic64b mandates 64-byte naturally aligned cache blocks and is a
> mandatory extension of the RVA22 and RVA23 profiles.  Allocate a
> RISCV_ISA_EXT_ZIC64B id, parse "zic64b" from the ISA string with a
> validate callback that requires each cbom/cbop/cboz cache block size to
> be 64 bytes when it is present, and export it through hwprobe.
> 
> Link: https://lists.riscv.org/g/tech-unprivileged/topic/question_about_zic64b_and/119631059
> Signed-off-by: Qingwei Hu <qingwei.hu at bytedance.com>
> Co-developed-by: Guodong Xu <docular.xu at gmail.com>
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> ---
> v4:
> - Credit Qingwei Hu's earlier Zic64b cpufeature patch: set him as
>   author, with Co-developed-by (Guodong Xu).
> - Validate only the cbom/cbop/cboz block sizes that are present; Zic64b
>   does not imply the CMO extensions (Conor, Qingwei, Greg).
> - Add a Link: to Greg's confirmation on the tech-unprivileged list.
> - Add the missing blank line before the ZIC64B hwprobe.rst entry
>   (Andrew).
> - Did not carry Andrew Jones's v3 Reviewed-by: the validation was
>   rewritten (present block sizes only) and the patch is now authored by
>   Qingwei, so it warrants a fresh review.
> v3: New patch.
> ---
>  Documentation/arch/riscv/hwprobe.rst  |  4 ++++
>  arch/riscv/include/asm/hwcap.h        |  1 +
>  arch/riscv/include/uapi/asm/hwprobe.h |  1 +
>  arch/riscv/kernel/cpufeature.c        | 19 +++++++++++++++++++
>  arch/riscv/kernel/sys_hwprobe.c       |  1 +
>  5 files changed, 26 insertions(+)
>

Reviewed-by: Andrew Jones <andrew.jones at oss.qualcomm.com>


From thorsten.blum at linux.dev  Thu Jun 11 16:25:38 2026
From: thorsten.blum at linux.dev (Thorsten Blum)
Date: Fri, 12 Jun 2026 01:25:38 +0200
Subject: [PATCH] riscv: smp: use secs_to_jiffies in __cpu_up
Message-ID: <20260611232537.467398-3-thorsten.blum@linux.dev>

Use secs_to_jiffies() to simplify the code. Drop the redundant zero
initialization while at it.

Signed-off-by: Thorsten Blum <thorsten.blum at linux.dev>
---
 arch/riscv/kernel/smpboot.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index 8b628580fe11..f6ef57930b50 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -189,13 +189,12 @@ int arch_cpuhp_kick_ap_alive(unsigned int cpu, struct task_struct *tidle)
 #else
 int __cpu_up(unsigned int cpu, struct task_struct *tidle)
 {
-	int ret = 0;
+	int ret;
 	tidle->thread_info.cpu = cpu;
 
 	ret = start_secondary_cpu(cpu, tidle);
 	if (!ret) {
-		wait_for_completion_timeout(&cpu_running,
-					    msecs_to_jiffies(1000));
+		wait_for_completion_timeout(&cpu_running, secs_to_jiffies(1));
 
 		if (!cpu_online(cpu)) {
 			pr_crit("CPU%u: failed to come online\n", cpu);


From xujiakai2025 at iscas.ac.cn  Thu Jun 11 18:41:07 2026
From: xujiakai2025 at iscas.ac.cn (Jiakai Xu)
Date: Fri, 12 Jun 2026 01:41:07 +0000
Subject: [PATCH v2] riscv: stacktrace: fix stack-out-of-bounds in walk_stackframe()
In-Reply-To: <20260517143704.659416-1-xujiakai2025@iscas.ac.cn>
References: <20260517143704.659416-1-xujiakai2025@iscas.ac.cn>
Message-ID: <20260612014107.3278497-1-xujiakai2025@iscas.ac.cn>

Hi all,

Gentle ping on this patch.

Thanks,
Jiakai



From mark.hsj at gmail.com  Thu Jun 11 21:55:02 2026
From: mark.hsj at gmail.com (Mark Harris)
Date: Thu, 11 Jun 2026 21:55:02 -0700
Subject: [PATCH] riscv: hwprobe: Avoid uninitialized read in hwprobe_get_cpus()
Message-ID: <20260612045502.70850-1-mark.hsj@gmail.com>

When cpusetsize < cpumask_size(), hwprobe_get_cpus() did not fully
initialize its copy of the cpu mask, which could cause non-deterministic
results from the riscv_hwprobe syscall on a system with more than 8 CPUs
when the supplied cpu mask is empty.  Address this by fully initializing
the cpu mask.

Signed-off-by: Mark Harris <mark.hsj at gmail.com>
---
 arch/riscv/kernel/sys_hwprobe.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 1659d31fd288..caf6762427c8 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -450,6 +450,7 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,
 	if (cpusetsize > cpumask_size())
 		cpusetsize = cpumask_size();
 
+	cpumask_clear(&cpus);
 	ret = copy_from_user(&cpus, cpus_user, cpusetsize);
 	if (ret)
 		return -EFAULT;
-- 
2.54.0



From chenwandun1 at gmail.com  Fri Jun 12 00:28:24 2026
From: chenwandun1 at gmail.com (Wandun)
Date: Fri, 12 Jun 2026 15:28:24 +0800
Subject: [PATCH v3 00/11] kdump: reduce vmcore size and capture time
In-Reply-To: <aiqkKe1gXPZ5LZ7t@MiWiFi-R3L-srv>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <7ed207fa-4c86-426a-8570-495902ce04c3@gmail.com>
 <a3993db0-6975-455d-9674-4fd7cfcf80fc@gmail.com>
 <aiqkKe1gXPZ5LZ7t@MiWiFi-R3L-srv>
Message-ID: <27a06e00-ac47-4e5f-8033-4e89f15d0411@gmail.com>



On 6/11/26 20:03, Baoquan He wrote:
> On 06/11/26 at 11:09am, Wandun wrote:
>>
>>
>> On 6/11/26 10:09, Wandun wrote:
>>>
>>>
>>> On 5/27/26 11:29, Wandun Chen wrote:
>>>> From: Wandun Chen <chenwandun at lixiang.com>
>>>>
>>>> On SoCs that carve out large firmware-owned reserved memory (GPU
>>>> firmware, DSP, modem, camera ISP, NPU, ...), kdump currently dumps
>>>> those carveouts as part of system RAM even though their contents are
>>>> firmware state that is not useful for kernel crash analysis.
>>>>
>>>> This series introduces an opt-in 'dumpable' flag [1] on struct
>>>> reserved_mem and uses it to filter the elfcorehdr PT_LOAD ranges on
>>>> DT-based architectures (arm64, riscv, loongarch). By default reserved
>>>> regions are treated as non-dumpable; CMA regions are explicitly opted
>>>> in because their pages are returned to the buddy allocator and may
>>>> carry key crash-analysis data.
>>>>
>>>> The series is organized as follows:
>>>> Patches 1-3: Pre-existing fixes and a small prep change.
>>>> Patches 4-5: Restructure to allow appending /memreserve/ entries.
>>>> Patches 6-7: Add a dumpable flag and append /memreserve/ entries.
>>>> Patch 8: Add generic kdump helpers.
>>>> Patches 9-11: Wire the helpers into arm64, riscv and loongarch kdump
>>>> ?????????????? elfcorehdr preparation.
>>> Hi,
>>>
>>> Gentle ping on this series.
>>>
>>> Status summary:
>>> -patch 03: respun separately per Rob's suggestion, picked up for 7.2
>>> -patch 06: Acked-by: Marek Szyprowski -patch 09: Acked-by: Will Deacon
>>> The remaining patches (01, 02, 04, 05, 07, 08, 10, 11) are still
>>> awaiting review. your feedback would be greately appreciated. I know we
>>> are at the end of 7.1 -rc cycle, I don't want to rush this series, just
>>> collecting more feedback, and will send next version based on 7.2-rc1.
>>> If spliting the series into smaller logical group would make review
>>> easier, please let me know. Best regards, Wandun
>>
>> Apologies for the formatting issue in my previous email.
>> Here is the properly formatted version.
>>
>> Gentle ping on this series.
> 
> Thanks for the effort, the overral looks good to me at 1st glance. I will
> check if there's concern on generic part. And meanwhile, I am wondering
> if there's any chance x86 or other ARCH-es w/o OF/FDT can also choose to
> not dump some areas, e.g GPU stolen memory. Surely, that's another story.

Thanks for the review, Baoquan.

IIUC, reserved memory is already excluded from vmcore on x86.

Reserved memory is typed as E820_TYPE_RESERVED in the e820 table, and
insert into iomem resource tree with IORESOURCE_MEM flag. The x86 kdump
patch uses walk_system_ram_res() which scan iomem resource tree, and
only collects ranges with IORESOURCE_SYSTEM_RAM flag, so reserved
regions are excluded.


Best regards,
Wandun
> 
>>
>> Status summary:
>> - patch 03: respun separately per Rob's suggestion, picked up for 7.2
>> - patch 06: Acked-by: Marek Szyprowski
>> - patch 09: Acked-by: Will Deacon
>>
>> The remaining patches (01, 02, 04, 05, 07, 08, 10, 11) are still
>> awaiting review. Your feedback would be greatly appreciated.
>>
>> I know we are at the end of 7.1-rc cycle, I don't want to rush this
>> series, just collecting more feedback, and will send next version based
>> on 7.2-rc1.
>>
>> If splitting the series into smaller logical groups would make review
>> easier, please let me know.
>>
>> Best regards,
>> Wandun
>>
>>
>>>>
>>>> v2 --> v3:
>>>> 1. Fix out-of-bounds issue if device tree lacks /reserved-memory node.[2]
>>>> 2. Fix UAF issue when alloc_reserved_mem_array() fails.
>>>> 3. Add some prepare patches.
>>>>
>>>> v1 --> v2:
>>>> 1. v1 added an opt-out DT property ('linux,no-dump'). Per Rob's
>>>> ??? feedback [1], v2 drop that property and exclude reserve memory
>>>> ??? by default.
>>>> 2. Split some prepared patches from the original patches.
>>>> 3. Address coding-style comments on patch 5 from Rob.
>>>>
>>>> [1] https://lore.kernel.org/lkml/20260506144542.GA2072596-
>>>> robh at kernel.org/
>>>> [2] https://sashiko.dev/#/patchset/20260520091844.592753-1-
>>>> chenwandun%40lixiang.com?part=4
>>>>
>>>> Wandun Chen (11):
>>>> ?? of: reserved_mem: handle NULL name in of_reserved_mem_lookup()
>>>> ?? kexec/crash: provide crash_exclude_mem_range() stub when
>>>> ???? CONFIG_CRASH_DUMP=n
>>>> ?? of: reserved_mem: avoid post-init UAF when alloc_reserved_mem_array()
>>>> ???? fails
>>>> ?? of: reserved_mem: zero total_reserved_mem_cnt if no valid
>>>> ???? /reserved-memory entry
>>>> ?? of: reserved_mem: split alloc_reserved_mem_array() from
>>>> ???? fdt_scan_reserved_mem_late()
>>>> ?? of: reserved_mem: add dumpable flag to opt-in vmcore
>>>> ?? of: reserved_mem: save /memreserve/ entries into the reserved_mem
>>>> ???? array
>>>> ?? of: reserved_mem: add kdump helpers to exclude non-dumpable regions
>>>> ?? arm64: kdump: exclude non-dumpable reserved memory regions from vmcore
>>>> ?? riscv: kdump: exclude non-dumpable reserved memory regions from vmcore
>>>> ?? loongarch: kdump: exclude non-dumpable reserved memory regions from
>>>> ???? vmcore
>>>>
>>>> ? arch/arm64/kernel/machine_kexec_file.c???? |?? 6 ++
>>>> ? arch/loongarch/kernel/machine_kexec_file.c |?? 6 ++
>>>> ? arch/riscv/kernel/machine_kexec_file.c???? |?? 4 +
>>>> ? drivers/of/fdt.c?????????????????????????? |? 11 +-
>>>> ? drivers/of/of_private.h??????????????????? |?? 3 +
>>>> ? drivers/of/of_reserved_mem.c?????????????? | 117 +++++++++++++++++++--
>>>> ? include/linux/crash_core.h???????????????? |?? 6 ++
>>>> ? include/linux/of_reserved_mem.h??????????? |? 15 +++
>>>> ? kernel/dma/contiguous.c??????????????????? |?? 1 +
>>>> ? 9 files changed, 157 insertions(+), 12 deletions(-)
>>>>
>>>
>>



From lpieralisi at kernel.org  Fri Jun 12 00:46:41 2026
From: lpieralisi at kernel.org (Lorenzo Pieralisi)
Date: Fri, 12 Jun 2026 09:46:41 +0200
Subject: [PATCH v2 6/6] irqchip/gic-v5: Enable GICv5 IWB ACPI probe
 ordering detection
In-Reply-To: <CAJZ5v0ibZKfzJwGyUb92-K1N9C_ab0QujpAKCrvMdyygquS1Vw@mail.gmail.com>
References: <20260603-gic-v5-acpi-iwb-probe-deferral-v2-0-23ffa16b6ebb@kernel.org>
 <20260603-gic-v5-acpi-iwb-probe-deferral-v2-6-23ffa16b6ebb@kernel.org>
 <CAJZ5v0ibZKfzJwGyUb92-K1N9C_ab0QujpAKCrvMdyygquS1Vw@mail.gmail.com>
Message-ID: <aiu5YU+Yn1DekE+E@lpieralisi>

On Mon, Jun 08, 2026 at 07:18:15PM +0200, Rafael J. Wysocki wrote:
> On Wed, Jun 3, 2026 at 10:21?AM Lorenzo Pieralisi <lpieralisi at kernel.org> wrote:
> >
> > Register an ACPI hook in the ACPI interrupt management code for GICv5 to
> > retrieve the ACPI interrupt controller handle (if any) of the controller
> > handling a specific GSI, by updating the acpi_set_irq_model() call with
> > the gic_v5_get_gsi_handle() function pointer parameter.
> >
> > gicv5_get_gsi_handle() allows ACPI core to detect the ACPI handle
> > of the controller that manages a specific GSI interrupt.
> >
> > Update the IWB driver to clear device dependencies in ACPI core once the
> > IWB driver has probed.
> >
> > Signed-off-by: Lorenzo Pieralisi <lpieralisi at kernel.org>
> > Cc: Thomas Gleixner <tglx at kernel.org>
> > Cc: Marc Zyngier <maz at kernel.org>
> > ---
> >  drivers/irqchip/irq-gic-v5-iwb.c |  5 +++++
> >  drivers/irqchip/irq-gic-v5.c     | 13 +++++++++++--
> >  2 files changed, 16 insertions(+), 2 deletions(-)
> >
> > diff --git a/drivers/irqchip/irq-gic-v5-iwb.c b/drivers/irqchip/irq-gic-v5-iwb.c
> > index 9103feb70ce8..a02cb9537b15 100644
> > --- a/drivers/irqchip/irq-gic-v5-iwb.c
> > +++ b/drivers/irqchip/irq-gic-v5-iwb.c
> > @@ -269,6 +269,11 @@ static int gicv5_iwb_device_probe(struct platform_device *pdev)
> >         if (IS_ERR(iwb_node))
> >                 return PTR_ERR(iwb_node);
> >
> > +#ifdef CONFIG_ACPI
> > +       if (has_acpi_companion(&pdev->dev))
> > +               acpi_dev_clear_dependencies(ACPI_COMPANION(&pdev->dev));
> > +#endif
> 
> I would rather add a wrapper for this, along with an empty stub for
> the !CONFIG_ACPI case.

Given that this has no OF counterpart, I'd rather add an empty stub
for acpi_dev_clear_dependencies() and remove the ifdef - I am not
sure that adding a FW agnostic:

dev_clear_dependencies()

would help much but that's just my opinion. Then the question is whether I
should convert all other acpi_dev_clear_dependencies() users (with ifdeffery
included) in tree.

Thanks,
Lorenzo

> 
> > +
> >         return 0;
> >  }
> >
> > diff --git a/drivers/irqchip/irq-gic-v5.c b/drivers/irqchip/irq-gic-v5.c
> > index 03cc2830b260..26cfaea1af41 100644
> > --- a/drivers/irqchip/irq-gic-v5.c
> > +++ b/drivers/irqchip/irq-gic-v5.c
> > @@ -1217,11 +1217,19 @@ static struct fwnode_handle *gsi_domain_handle;
> >  static struct fwnode_handle *gic_v5_get_gsi_domain_id(u32 gsi)
> >  {
> >         if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
> > -               return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> > +               return iort_iwb_handle_fwnode(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> 
> Why is this change needed?
> 
> >
> >         return gsi_domain_handle;
> >  }
> >
> > +static acpi_handle gic_v5_get_gsi_handle(u32 gsi)
> > +{
> > +       if (FIELD_GET(GICV5_GSI_IC_TYPE, gsi) == GICV5_GSI_IWB_TYPE)
> > +               return iort_iwb_handle(FIELD_GET(GICV5_GSI_IWB_FRAME_ID, gsi));
> > +
> > +       return NULL;
> > +}
> > +
> >  static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsigned long end)
> >  {
> >         struct acpi_madt_gicv5_irs *irs = (struct acpi_madt_gicv5_irs *)header;
> > @@ -1242,7 +1250,8 @@ static int __init gic_acpi_init(union acpi_subtable_headers *header, const unsig
> >         if (ret)
> >                 goto out_irs;
> >
> > -       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id, NULL);
> > +       acpi_set_irq_model(ACPI_IRQ_MODEL_GIC_V5, gic_v5_get_gsi_domain_id,
> > +                          gic_v5_get_gsi_handle);
> >
> >         return 0;
> >
> >
> > --


From conor.dooley at microchip.com  Fri Jun 12 01:02:34 2026
From: conor.dooley at microchip.com (Conor Dooley)
Date: Fri, 12 Jun 2026 09:02:34 +0100
Subject: [PATCH v4 01/16] dt-bindings: riscv: sort multi-letter Z
 extensions alphanumerically
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-1-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
 <20260611-rva23u64-hwprobe-v2-v4-1-3f01a2449488@gmail.com>
Message-ID: <20260612-strength-body-303e6a57218d@wendy>

On Thu, Jun 11, 2026 at 04:12:38PM -0400, Guodong Xu wrote:
> The multi-letter extension enum is documented as being sorted
> alphanumerically (see the "multi-letter extensions, sorted
> alphanumerically" comment), but several Z entries have drifted out of
> order.
> 
> Reorder the affected entries so the multi-letter Z list is sorted
> alphanumerically again.
> 
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: na
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260612/d971a6f7/attachment.sig>

From conor.dooley at microchip.com  Fri Jun 12 01:10:28 2026
From: conor.dooley at microchip.com (Conor Dooley)
Date: Fri, 12 Jun 2026 09:10:28 +0100
Subject: [PATCH v4 06/16] riscv: Add Ziccamoa, Ziccif, Ziccrse, and
 Za64rs to cpufeature and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-6-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
 <20260611-rva23u64-hwprobe-v2-v4-6-3f01a2449488@gmail.com>
Message-ID: <20260612-revered-statue-793228111bf1@wendy>

On Thu, Jun 11, 2026 at 04:12:43PM -0400, Guodong Xu wrote:
> From: Andrew Jones <andrew.jones at oss.qualcomm.com>
> 
> Add Ziccamoa, Ziccif, and Za64rs to riscv_isa_ext[] so they can be
> parsed from devicetree/ACPI ISA strings. Ziccrse is already present
> in cpufeature; this patch only adds its hwprobe exposure.
> 
> Expose all four extensions via hwprobe through new bits in
> RISCV_HWPROBE_KEY_IMA_EXT_1 (RISCV_HWPROBE_EXT_ZICCAMOA, _ZICCIF,
> _ZICCRSE, _ZA64RS), so userspace can probe each of these
> RVA23U64-mandatory extensions individually.
> 
> Rationale for the validation dependencies added for Ziccamoa and Za64rs:
> 
> 1) Ziccamoa depends on Zaamo.  The RVA23 profile prose was updated
> post-ratification to spell out the Zaamo reference: commit
> 2b218613752d in riscv/riscv-profiles ("Improve description of
> Ziccamoa (#224)") reworded the rva23-profile.adoc (and other profiles
> that include Ziccamoa) text from "must support all atomics in A" to
> "must support all atomics in the Zaamo extension" [1].
> 
> 2) Za64rs depends on Zalrsc. The unprivileged ISA manual src/zars.adoc,
> integrated in commit ebe06adc22cd ("Integrate profiles as Volume III
> (#2771)"), defines Za64rs as: "The Za64rs extension requires that the
> reservation sets used by the instructions in the Zalrsc extension be
> contiguous, naturally aligned, and at most 64 bytes in size" [2].

I think I made the point on either an earlier version of this, or a
similar thread, that the point of the validate callback stuff is to make
sure that the kernel is correctly configured to use the extension in
question or an extension it depends on. It's not the kernel's job to
make sure that the firmware has not reported having an extension without
one that it depends on (at least it is not in devicetree land, and I can
only assume that ACPI is by and large the same.

ziccamoa and za64rs don't depend on kernel configuration and neither do
zaamo and zalrsc, so these validate callbacks should be removed.

Cheers,
Conor.

> +static int riscv_ext_zaamo_depends(const struct riscv_isa_ext_data *data,
> +				   const unsigned long *isa_bitmap)
> +{
> +	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZAAMO))
> +		return 0;
> +
> +	return -EPROBE_DEFER;
> +}
> +
> +static int riscv_ext_zalrsc_depends(const struct riscv_isa_ext_data *data,
> +				    const unsigned long *isa_bitmap)
> +{
> +	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_ZALRSC))
> +		return 0;
> +
> +	return -EPROBE_DEFER;
> +}
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260612/27d8a75c/attachment.sig>

From conor.dooley at microchip.com  Fri Jun 12 01:12:30 2026
From: conor.dooley at microchip.com (Conor Dooley)
Date: Fri, 12 Jun 2026 09:12:30 +0100
Subject: [PATCH v4 07/16] riscv: Add B to hwcap and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-7-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
 <20260611-rva23u64-hwprobe-v2-v4-7-3f01a2449488@gmail.com>
Message-ID: <20260612-unsorted-sequester-6a4ec6b9d583@wendy>

On Thu, Jun 11, 2026 at 04:12:44PM -0400, Guodong Xu wrote:
> From: Andrew Jones <andrew.jones at oss.qualcomm.com>
> 
> Add B to hwcap and ensure when B is present that Zba, Zbb, and Zbs
> are all set. Also expose B via hwprobe (RISCV_HWPROBE_EXT_B in
> RISCV_HWPROBE_KEY_IMA_EXT_1) so that userspace can probe B directly,
> mirroring the F/D/C/V pattern where each is reported via both hwcap
> and hwprobe.
> 
> Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
> [Add B to hwprobe]
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>

Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260612/e571cd1b/attachment.sig>

From conor.dooley at microchip.com  Fri Jun 12 01:23:12 2026
From: conor.dooley at microchip.com (Conor Dooley)
Date: Fri, 12 Jun 2026 09:23:12 +0100
Subject: [PATCH v4 08/16] dt-bindings: riscv: Add Zic64b extension
 description
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-8-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
 <20260611-rva23u64-hwprobe-v2-v4-8-3f01a2449488@gmail.com>
Message-ID: <20260612-scarcity-willow-c073342b5ac2@wendy>

On Thu, Jun 11, 2026 at 04:12:45PM -0400, Guodong Xu wrote:
> Zic64b mandates that cache blocks are 64 bytes in size and naturally
> aligned in the address space.  It is a mandatory extension of both the
> RVA22 (U64/S64) and RVA23 (U64/S64) profiles, ratified with RISC-V
> Profiles Version 1.0.
> 
> Document it so it can be described in the riscv,isa-extensions property,
> alongside the related Zicbom/Zicbop/Zicboz cache-block extensions. Since
> Zic64b fixes the cache block size at 64 bytes, also add a  schema check
                                                           ^^
Not that it matters, but there's an extra space here.

> requiring any present cbom/cbop/cboz block size to be 64.
> 
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> ---
> v4: Insert zic64b at its sorted position (before zicbom).
>     Update the commit message.
> v3: New patch.
> ---
>  .../devicetree/bindings/riscv/extensions.yaml        | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
> index 5ffc40d599c02..1c24999beb59e 100644
> --- a/Documentation/devicetree/bindings/riscv/extensions.yaml
> +++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
> @@ -494,6 +494,12 @@ properties:
>              in commit 64074bc ("Update version numbers for Zfh/Zfinx") of
>              riscv-isa-manual.
>  
> +        - const: zic64b
> +          description:
> +            The standard Zic64b extension for 64-byte naturally aligned cache
> +            blocks, as ratified in RISC-V Profiles Version 1.0, with commit
> +            b1d806605f87 ("Updated to ratified state.")
> +
>          - const: zicbom
>            description:
>              The standard Zicbom extension for base cache management operations as
> @@ -1142,6 +1148,20 @@ allOf:
>            not:
>              contains:
>                const: zilsd
> +  # Zic64b mandates 64-byte naturally aligned cache blocks
> +  - if:
> +      properties:
> +        riscv,isa-extensions:
> +          contains:
> +            const: zic64b
> +    then:
> +      properties:
> +        riscv,cbom-block-size:
> +          const: 64
> +        riscv,cbop-block-size:
> +          const: 64
> +        riscv,cboz-block-size:
> +          const: 64

I think we also need to have
diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 1c24999beb59e..bbd442cfbd904 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -1162,6 +1162,32 @@ allOf:
           const: 64
         riscv,cboz-block-size:
           const: 64
+  # All three Zicbo* extensions require their block size property as there's no
+  # default.
+  - if:
+      properties:
+        riscv,isa-extensions:
+          contains:
+            const: zicbom
+    then:
+      required:
+        - riscv,cbom-block-size
+  - if:
+      properties:
+        riscv,isa-extensions:
+          contains:
+            const: zicbop
+    then:
+      required:
+        - riscv,cbop-block-size
+  - if:
+      properties:
+        riscv,isa-extensions:
+          contains:
+            const: zicboz
+    then:
+      required:
+        - riscv,cboz-block-size
 
 additionalProperties: true
 ...

because I don't think there's a warning generated at present* if someone
does "zicbom" + "zic64b" and doesn't have a riscv,cbom-block-size property,
only if they have one and it isn't 64. I think the former is a bigger
problem than the latter.

Probably needs to be an additional patch, because it has value whether
or not we permit zic64b.

pwbot: cr

Cheers,
Conor.

*: the kernel will warn at runtime, but nothing in dtbs_check etc.

>  
>  additionalProperties: true
>  ...
> 
> -- 
> 2.43.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260612/91c0e99c/attachment.sig>

From conor.dooley at microchip.com  Fri Jun 12 01:41:02 2026
From: conor.dooley at microchip.com (Conor Dooley)
Date: Fri, 12 Jun 2026 09:41:02 +0100
Subject: [PATCH v4 09/16] riscv: Add Zic64b to cpufeature and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-9-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
 <20260611-rva23u64-hwprobe-v2-v4-9-3f01a2449488@gmail.com>
Message-ID: <20260612-frays-feast-e631e3aa047d@wendy>

On Thu, Jun 11, 2026 at 04:12:46PM -0400, Guodong Xu wrote:
> From: Qingwei Hu <qingwei.hu at bytedance.com>
> 
> Zic64b mandates 64-byte naturally aligned cache blocks and is a
> mandatory extension of the RVA22 and RVA23 profiles.  Allocate a
> RISCV_ISA_EXT_ZIC64B id, parse "zic64b" from the ISA string with a
> validate callback that requires each cbom/cbop/cboz cache block size to
> be 64 bytes when it is present, and export it through hwprobe.
> 
> Link: https://lists.riscv.org/g/tech-unprivileged/topic/question_about_zic64b_and/119631059
> Signed-off-by: Qingwei Hu <qingwei.hu at bytedance.com>
> Co-developed-by: Guodong Xu <docular.xu at gmail.com>
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>

> +static int riscv_ext_zic64b_validate(const struct riscv_isa_ext_data *data,
> +				     const unsigned long *isa_bitmap)
> +{
> +	/*
> +	 * Zic64b mandates 64-byte naturally aligned cache blocks; cross-check the
> +	 * cbom/cbop/cboz block-size (when declared) device-tree properties to
> +	 * avoid inconsistency.
> +	 */
> +	if ((riscv_cbom_block_size && riscv_cbom_block_size != 64) ||
> +	    (riscv_cbop_block_size && riscv_cbop_block_size != 64) ||
> +	    (riscv_cboz_block_size && riscv_cboz_block_size != 64)) {
> +		pr_err("Zic64b detected in ISA string, disabling as a CBO block size is not 64 bytes\n");
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}

I'm inclined to object to this, but we don't have validation on ACPI
stuff to be able to mandate that people fill in the rhct entries.
Reviewed-by: Conor Dooley <conor.dooley at microchip.com>

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260612/6088a95d/attachment.sig>

From shuwei.wu at mailbox.org  Fri Jun 12 02:51:00 2026
From: shuwei.wu at mailbox.org (Shuwei Wu)
Date: Fri, 12 Jun 2026 17:51:00 +0800
Subject: [PATCH v3 0/2] cpufreq: spacemit: Add cpufreq support for K1 SoC
Message-ID: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>

This series enables CPU frequency scaling for the SpacemiT K1 SoC.

K1 has two CPU cluster clocks but one shared CPU voltage rail. Add a
small K1-specific cpufreq driver so the two clocks and the shared OPP
transition can be handled together.

Tested on Banana Pi BPI-F3. The system boots with all eight CPUs online,
the K1 cpufreq driver registers one policy for CPUs 0-7, and both CPU
cluster clocks follow the selected cpufreq rate.

~ # cat /sys/devices/system/cpu/online
0-7

~ # ls /sys/devices/system/cpu/cpufreq
policy0

~ # cat /sys/devices/system/cpu/cpufreq/policy0/affected_cpus
0 1 2 3 4 5 6 7

~ # cat /sys/devices/system/cpu/cpufreq/policy0/scaling_available_frequencies
614400 819000 1000000 1228800 1600000

With the userspace governor:
----------------------------------------------------------------------------
Frequency    | scaling_cur | cpu_c0_core | cpu_c1_core | Real    | User
(kHz)        | (kHz)       | (Hz)        | (Hz)        | (s)     | (s)
-------------+-------------+-------------+-------------+---------+----------
1,600,000    | 1,600,000   | 1600000000  | 1600000000  | 1.80s   | 1.80s
1,228,800    | 1,228,800   | 1228800000  | 1228800000  | 2.33s   | 2.33s
1,000,000    | 1,000,000   | 1000000000  | 1000000000  | 2.88s   | 2.87s
  819,000    |   819,000   |  819200000  |  819200000  | 3.53s   | 3.52s
  614,400    |   614,400   |  614400000  |  614400000  | 4.72s   | 4.72s
----------------------------------------------------------------------------

Signed-off-by: Shuwei Wu <shuwei.wu at mailbox.org>
---
Changes in v3:
- Add a K1-specific cpufreq driver for the shared-rail, dual-clock topology
- Use one shared CPU OPP table and one cpufreq policy for all CPUs
- Link to v2: https://lore.kernel.org/r/20260410-shadow-deps-v2-0-4e16b8c0f60e at mailbox.org

Changes in v2:
- Move OPP tables to dedicated k1-opp.dtsi
- Enable OPP only on BPI-F3 with cpu-supply present
- Link to v1: https://lore.kernel.org/r/20260308-shadow-deps-v1-0-0ceb5c7c07eb at mailbox.org

---
Shuwei Wu (2):
      cpufreq: spacemit: Add K1 cpufreq driver
      riscv: dts: spacemit: Add cpu scaling for K1 SoC

 arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts |  35 +++-
 arch/riscv/boot/dts/spacemit/k1-opp.dtsi        |  70 +++++++
 arch/riscv/boot/dts/spacemit/k1.dtsi            |   8 +
 drivers/cpufreq/Kconfig                         |   4 +
 drivers/cpufreq/Kconfig.riscv                   |  15 ++
 drivers/cpufreq/Makefile                        |   3 +
 drivers/cpufreq/cpufreq-dt-platdev.c            |   2 +
 drivers/cpufreq/spacemit-k1-cpufreq.c           | 251 ++++++++++++++++++++++++
 8 files changed, 387 insertions(+), 1 deletion(-)
---
base-commit: 5164e95565d3fd508ca8a95351323f5716dfb695
change-id: 20260307-shadow-deps-3582a78aa756
prerequisite-patch-id: 154bd4f720ce5065d58b988de8f273207b44572e
prerequisite-message-id: <20260206-spacemit-p1-v4-0-8f695d93811e at riscstar.com>
prerequisite-patch-id: 5da3e75b18291a5540d4f66d7a0600fb8975ef62
prerequisite-patch-id: bcf41917414ecef8cf743095d130f6004c32f6a5
prerequisite-patch-id: cfe3800f8c791ec4c63e070af9628e88e0fc31b9
prerequisite-message-id: <20260305-k1-clk-fix-v1-1-abca85d6e266 at mailbox.org>
prerequisite-patch-id: 7c7fb9f87dba019ece4c97c45750349a7cd28f3a

Best regards,
-- 
Shuwei Wu <shuwei.wu at mailbox.org>



From shuwei.wu at mailbox.org  Fri Jun 12 02:51:01 2026
From: shuwei.wu at mailbox.org (Shuwei Wu)
Date: Fri, 12 Jun 2026 17:51:01 +0800
Subject: [PATCH v3 1/2] cpufreq: spacemit: Add K1 cpufreq driver
In-Reply-To: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
Message-ID: <20260612-shadow-deps-v3-1-2f3ba88611ff@mailbox.org>

K1 has two CPU cluster clocks but one shared CPU voltage rail. Use one
cpufreq policy for all CPUs, let the OPP core handle the shared regulator
and the cluster0 clock, and update the cluster1 clock explicitly.

Block spacemit,k1 from cpufreq-dt probing when OPP v2 nodes are present,
as K1 needs the dedicated driver for safe transitions.

Signed-off-by: Shuwei Wu <shuwei.wu at mailbox.org>
---
Changes in v3:
- Add a K1-specific cpufreq driver for the shared-rail, dual-clock topology
- Add spacemit,k1 to the cpufreq-dt blocklist
---
 drivers/cpufreq/Kconfig               |   4 +
 drivers/cpufreq/Kconfig.riscv         |  15 ++
 drivers/cpufreq/Makefile              |   3 +
 drivers/cpufreq/cpufreq-dt-platdev.c  |   2 +
 drivers/cpufreq/spacemit-k1-cpufreq.c | 251 ++++++++++++++++++++++++++++++++++
 5 files changed, 275 insertions(+)

diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 78702a08364f..19bbd1bd2f36 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -259,6 +259,10 @@ endif
 
 source "drivers/cpufreq/Kconfig.arm"
 
+if RISCV
+source "drivers/cpufreq/Kconfig.riscv"
+endif
+
 if PPC32 || PPC64
 source "drivers/cpufreq/Kconfig.powerpc"
 endif
diff --git a/drivers/cpufreq/Kconfig.riscv b/drivers/cpufreq/Kconfig.riscv
new file mode 100644
index 000000000000..3d5b59fbcd4c
--- /dev/null
+++ b/drivers/cpufreq/Kconfig.riscv
@@ -0,0 +1,15 @@
+# SPDX-License-Identifier: GPL-2.0-only
+#
+# RISC-V CPU Frequency scaling drivers
+#
+
+config RISCV_SPACEMIT_K1_CPUFREQ
+	tristate "SpacemiT K1 CPUFreq driver"
+	depends on ARCH_SPACEMIT || COMPILE_TEST
+	depends on OF && COMMON_CLK
+	select PM_OPP
+	help
+	  Enable CPU frequency scaling for SpacemiT K1 SoC.
+	  K1 has two CPU cluster clocks and one shared CPU voltage rail.
+	  The driver keeps all CPUs in one policy and updates both cluster
+	  clocks with the shared OPP transition.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 385c9fcc65c6..9680f420e824 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -89,6 +89,9 @@ obj-$(CONFIG_ARM_TEGRA194_CPUFREQ)	+= tegra194-cpufreq.o
 obj-$(CONFIG_ARM_TI_CPUFREQ)		+= ti-cpufreq.o
 obj-$(CONFIG_ARM_VEXPRESS_SPC_CPUFREQ)	+= vexpress-spc-cpufreq.o
 
+##################################################################################
+# RISC-V SoC drivers
+obj-$(CONFIG_RISCV_SPACEMIT_K1_CPUFREQ)	+= spacemit-k1-cpufreq.o
 
 ##################################################################################
 # PowerPC platform drivers
diff --git a/drivers/cpufreq/cpufreq-dt-platdev.c b/drivers/cpufreq/cpufreq-dt-platdev.c
index 25fd3b191b7e..69bbe739a627 100644
--- a/drivers/cpufreq/cpufreq-dt-platdev.c
+++ b/drivers/cpufreq/cpufreq-dt-platdev.c
@@ -185,6 +185,8 @@ static const struct of_device_id blocklist[] __initconst = {
 	{ .compatible = "qcom,sm8550", },
 	{ .compatible = "qcom,sm8650", },
 
+	{ .compatible = "spacemit,k1", },
+
 	{ .compatible = "st,stih407", },
 	{ .compatible = "st,stih410", },
 	{ .compatible = "st,stih418", },
diff --git a/drivers/cpufreq/spacemit-k1-cpufreq.c b/drivers/cpufreq/spacemit-k1-cpufreq.c
new file mode 100644
index 000000000000..631897eb8022
--- /dev/null
+++ b/drivers/cpufreq/spacemit-k1-cpufreq.c
@@ -0,0 +1,251 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * CPU frequency scaling driver for SpacemiT K1 SoC.
+ *
+ * Copyright (c) 2026 Shuwei Wu <shuwei.wu at mailbox.org>
+ */
+
+#include <linux/clk.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/cpumask.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pm_opp.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+struct k1_cpufreq_priv {
+	struct device *cpu_dev;
+	struct clk *cluster0_clk;
+	struct clk *cluster1_clk;
+	struct cpufreq_frequency_table *freq_table;
+	cpumask_var_t cpus;
+	int opp_token;
+};
+
+static struct platform_device *k1_cpufreq_pdev;
+
+static int k1_cpufreq_set_target(struct cpufreq_policy *policy,
+				 unsigned int index)
+{
+	struct k1_cpufreq_priv *priv = policy->driver_data;
+	unsigned long old_freq = policy->cur * 1000UL;
+	unsigned long new_freq = policy->freq_table[index].frequency * 1000UL;
+	int ret;
+
+	if (!old_freq)
+		old_freq = clk_get_rate(priv->cluster0_clk);
+
+	if (new_freq > old_freq) {
+		ret = dev_pm_opp_set_rate(priv->cpu_dev, new_freq);
+		if (ret)
+			return ret;
+
+		ret = clk_set_rate(priv->cluster1_clk, new_freq);
+		if (ret)
+			dev_pm_opp_set_rate(priv->cpu_dev, old_freq);
+
+		return ret;
+	}
+
+	ret = clk_set_rate(priv->cluster1_clk, new_freq);
+	if (ret)
+		return ret;
+
+	ret = dev_pm_opp_set_rate(priv->cpu_dev, new_freq);
+	if (ret)
+		clk_set_rate(priv->cluster1_clk, old_freq);
+
+	return ret;
+}
+
+static int k1_cpufreq_init_policy(struct cpufreq_policy *policy)
+{
+	struct k1_cpufreq_priv *priv = cpufreq_get_driver_data();
+	unsigned int transition_latency;
+
+	cpumask_copy(policy->cpus, priv->cpus);
+	policy->clk = priv->cluster0_clk;
+	policy->freq_table = priv->freq_table;
+	policy->driver_data = priv;
+	policy->dvfs_possible_from_any_cpu = true;
+
+	transition_latency = dev_pm_opp_get_max_transition_latency(priv->cpu_dev);
+	if (!transition_latency)
+		transition_latency = CPUFREQ_DEFAULT_TRANSITION_LATENCY_NS;
+	policy->cpuinfo.transition_latency = transition_latency;
+
+	return 0;
+}
+
+static struct cpufreq_driver k1_cpufreq_driver = {
+	.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK | CPUFREQ_IS_COOLING_DEV,
+	.verify = cpufreq_generic_frequency_table_verify,
+	.target_index = k1_cpufreq_set_target,
+	.get = cpufreq_generic_get,
+	.init = k1_cpufreq_init_policy,
+	.register_em = cpufreq_register_em_with_opp,
+	.name = "k1-cpufreq",
+};
+
+static int k1_cpufreq_probe(struct platform_device *pdev)
+{
+	struct k1_cpufreq_priv *priv;
+	struct device *cpu4_dev;
+	static const char * const reg_names[] = { "cpu", NULL };
+	int cpu, ret;
+
+	priv = kzalloc_obj(*priv);
+	if (!priv)
+		return -ENOMEM;
+
+	if (!zalloc_cpumask_var(&priv->cpus, GFP_KERNEL)) {
+		ret = -ENOMEM;
+		goto free_data;
+	}
+
+	priv->cpu_dev = get_cpu_device(0);
+	cpu4_dev = get_cpu_device(4);
+	if (!priv->cpu_dev || !cpu4_dev) {
+		ret = -EPROBE_DEFER;
+		goto free_cpumask;
+	}
+
+	for_each_present_cpu(cpu)
+		cpumask_set_cpu(cpu, priv->cpus);
+
+	priv->cluster0_clk = clk_get(priv->cpu_dev, NULL);
+	if (IS_ERR(priv->cluster0_clk)) {
+		ret = PTR_ERR(priv->cluster0_clk);
+		dev_err_probe(priv->cpu_dev, ret, "failed to get cluster0 clock\n");
+		goto free_cpumask;
+	}
+
+	priv->cluster1_clk = clk_get(cpu4_dev, NULL);
+	if (IS_ERR(priv->cluster1_clk)) {
+		ret = PTR_ERR(priv->cluster1_clk);
+		dev_err_probe(cpu4_dev, ret, "failed to get cluster1 clock\n");
+		goto put_clk_c0;
+	}
+
+	priv->opp_token = dev_pm_opp_set_regulators(priv->cpu_dev, reg_names);
+	if (priv->opp_token < 0) {
+		ret = priv->opp_token;
+		dev_err_probe(priv->cpu_dev, ret, "failed to set regulators\n");
+		goto put_clk_c1;
+	}
+
+	ret = dev_pm_opp_of_cpumask_add_table(priv->cpus);
+	if (ret) {
+		dev_err_probe(priv->cpu_dev, ret, "failed to add OPP table\n");
+		goto put_opp_regulators;
+	}
+
+	ret = dev_pm_opp_get_opp_count(priv->cpu_dev);
+	if (ret <= 0) {
+		dev_err(priv->cpu_dev, "OPP table can't be empty\n");
+		ret = -ENODEV;
+		goto remove_opp_table;
+	}
+
+	ret = dev_pm_opp_init_cpufreq_table(priv->cpu_dev, &priv->freq_table);
+	if (ret) {
+		dev_err(priv->cpu_dev, "failed to init cpufreq table: %d\n", ret);
+		goto remove_opp_table;
+	}
+
+	k1_cpufreq_driver.driver_data = priv;
+	ret = cpufreq_register_driver(&k1_cpufreq_driver);
+	if (ret)
+		goto free_freq_table;
+
+	platform_set_drvdata(pdev, priv);
+
+	return 0;
+
+free_freq_table:
+	k1_cpufreq_driver.driver_data = NULL;
+	dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &priv->freq_table);
+remove_opp_table:
+	dev_pm_opp_of_cpumask_remove_table(priv->cpus);
+put_opp_regulators:
+	dev_pm_opp_put_regulators(priv->opp_token);
+put_clk_c1:
+	clk_put(priv->cluster1_clk);
+put_clk_c0:
+	clk_put(priv->cluster0_clk);
+free_cpumask:
+	free_cpumask_var(priv->cpus);
+free_data:
+	kfree(priv);
+
+	return ret;
+}
+
+static void k1_cpufreq_remove(struct platform_device *pdev)
+{
+	struct k1_cpufreq_priv *priv = platform_get_drvdata(pdev);
+
+	if (!priv)
+		return;
+
+	cpufreq_unregister_driver(&k1_cpufreq_driver);
+	k1_cpufreq_driver.driver_data = NULL;
+	dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &priv->freq_table);
+	dev_pm_opp_of_cpumask_remove_table(priv->cpus);
+	dev_pm_opp_put_regulators(priv->opp_token);
+	clk_put(priv->cluster1_clk);
+	clk_put(priv->cluster0_clk);
+	free_cpumask_var(priv->cpus);
+	kfree(priv);
+}
+
+static struct platform_driver k1_cpufreq_platdrv = {
+	.probe = k1_cpufreq_probe,
+	.remove = k1_cpufreq_remove,
+	.driver = {
+		.name = "spacemit-k1-cpufreq",
+	},
+};
+
+static const struct of_device_id k1_cpufreq_match_list[] __initconst = {
+	{ .compatible = "spacemit,k1" },
+	{ }
+};
+MODULE_DEVICE_TABLE(of, k1_cpufreq_match_list);
+
+/*
+ * K1 has no dedicated cpufreq controller device. Register a logical platform
+ * device so clock/regulator dependencies can defer probe.
+ */
+static int __init k1_cpufreq_init(void)
+{
+	int ret;
+
+	if (!of_machine_device_match(k1_cpufreq_match_list))
+		return -ENODEV;
+
+	ret = platform_driver_register(&k1_cpufreq_platdrv);
+	if (ret)
+		return ret;
+
+	k1_cpufreq_pdev = platform_device_register_simple("spacemit-k1-cpufreq", -1, NULL, 0);
+	ret = PTR_ERR_OR_ZERO(k1_cpufreq_pdev);
+	if (ret)
+		platform_driver_unregister(&k1_cpufreq_platdrv);
+
+	return ret;
+}
+module_init(k1_cpufreq_init);
+
+static void __exit k1_cpufreq_exit(void)
+{
+	platform_device_unregister(k1_cpufreq_pdev);
+	platform_driver_unregister(&k1_cpufreq_platdrv);
+}
+module_exit(k1_cpufreq_exit);
+
+MODULE_DESCRIPTION("SpacemiT K1 CPUFreq driver");
+MODULE_AUTHOR("Shuwei Wu <shuwei.wu at mailbox.org>");
+MODULE_LICENSE("GPL");

-- 
2.53.0



From shuwei.wu at mailbox.org  Fri Jun 12 02:51:02 2026
From: shuwei.wu at mailbox.org (Shuwei Wu)
Date: Fri, 12 Jun 2026 17:51:02 +0800
Subject: [PATCH v3 2/2] riscv: dts: spacemit: Add cpu scaling for K1 SoC
In-Reply-To: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
Message-ID: <20260612-shadow-deps-v3-2-2f3ba88611ff@mailbox.org>

Use one shared CPU OPP table for all CPUs and add CPU clock properties
for the two CPU clock clusters.

Enable CPU DVFS on Banana Pi BPI-F3 by including the OPP table and
wiring the CPU nodes to the CPU regulator supply.

Signed-off-by: Shuwei Wu <shuwei.wu at mailbox.org>
---
Changes in v3:
- Use one shared CPU OPP table for all CPUs

Changes in v2:
- Add k1-opp.dtsi with OPP tables for both CPU clusters
- Assign CPU supplies and include OPP table for Banana Pi BPI-F3
---
 arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts | 35 ++++++++++++-
 arch/riscv/boot/dts/spacemit/k1-opp.dtsi        | 70 +++++++++++++++++++++++++
 arch/riscv/boot/dts/spacemit/k1.dtsi            |  8 +++
 3 files changed, 112 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
index 444c3b1e6f44..81ab5f70176b 100644
--- a/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-bananapi-f3.dts
@@ -5,6 +5,7 @@
 
 #include "k1.dtsi"
 #include "k1-pinctrl.dtsi"
+#include "k1-opp.dtsi"
 
 / {
 	model = "Banana Pi BPI-F3";
@@ -86,6 +87,38 @@ &combo_phy {
 	status = "okay";
 };
 
+&cpu_0 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_1 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_2 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_3 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_4 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_5 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_6 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_7 {
+	cpu-supply = <&buck1_0v9>;
+};
+
 &emmc {
 	bus-width = <8>;
 	mmc-hs400-1_8v;
@@ -201,7 +234,7 @@ pmic at 41 {
 		dldoin2-supply = <&buck5>;
 
 		regulators {
-			buck1 {
+			buck1_0v9: buck1 {
 				regulator-min-microvolt = <500000>;
 				regulator-max-microvolt = <3450000>;
 				regulator-ramp-delay = <5000>;
diff --git a/arch/riscv/boot/dts/spacemit/k1-opp.dtsi b/arch/riscv/boot/dts/spacemit/k1-opp.dtsi
new file mode 100644
index 000000000000..3627812e1344
--- /dev/null
+++ b/arch/riscv/boot/dts/spacemit/k1-opp.dtsi
@@ -0,0 +1,70 @@
+// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
+
+/ {
+	cpu_opp_table: opp-table-cpu {
+		compatible = "operating-points-v2";
+		opp-shared;
+
+		opp-614400000 {
+			opp-hz = /bits/ 64 <614400000>;
+			opp-microvolt = <950000>;
+			clock-latency-ns = <200000>;
+		};
+
+		opp-819000000 {
+			opp-hz = /bits/ 64 <819000000>;
+			opp-microvolt = <950000>;
+			clock-latency-ns = <200000>;
+		};
+
+		opp-1000000000 {
+			opp-hz = /bits/ 64 <1000000000>;
+			opp-microvolt = <950000>;
+			clock-latency-ns = <200000>;
+		};
+
+		opp-1228800000 {
+			opp-hz = /bits/ 64 <1228800000>;
+			opp-microvolt = <950000>;
+			clock-latency-ns = <200000>;
+		};
+
+		opp-1600000000 {
+			opp-hz = /bits/ 64 <1600000000>;
+			opp-microvolt = <1050000>;
+			clock-latency-ns = <200000>;
+		};
+	};
+};
+
+&cpu_0 {
+	operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu_1 {
+	operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu_2 {
+	operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu_3 {
+	operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu_4 {
+	operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu_5 {
+	operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu_6 {
+	operating-points-v2 = <&cpu_opp_table>;
+};
+
+&cpu_7 {
+	operating-points-v2 = <&cpu_opp_table>;
+};
diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
index 529ec68e9c23..bdd109b81730 100644
--- a/arch/riscv/boot/dts/spacemit/k1.dtsi
+++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
@@ -54,6 +54,7 @@ cpu_0: cpu at 0 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <0>;
+			clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
 			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
 			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -84,6 +85,7 @@ cpu_1: cpu at 1 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <1>;
+			clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
 			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
 			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -114,6 +116,7 @@ cpu_2: cpu at 2 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <2>;
+			clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
 			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
 			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -144,6 +147,7 @@ cpu_3: cpu at 3 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <3>;
+			clocks = <&syscon_apmu CLK_CPU_C0_CORE>;
 			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
 			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -174,6 +178,7 @@ cpu_4: cpu at 4 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <4>;
+			clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
 			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
 			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -204,6 +209,7 @@ cpu_5: cpu at 5 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <5>;
+			clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
 			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
 			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -234,6 +240,7 @@ cpu_6: cpu at 6 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <6>;
+			clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
 			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
 			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",
@@ -264,6 +271,7 @@ cpu_7: cpu at 7 {
 			compatible = "spacemit,x60", "riscv";
 			device_type = "cpu";
 			reg = <7>;
+			clocks = <&syscon_apmu CLK_CPU_C1_CORE>;
 			riscv,isa = "rv64imafdcbv_zicbom_zicbop_zicboz_zicntr_zicond_zicsr_zifencei_zihintpause_zihpm_zfh_zba_zbb_zbc_zbs_zkt_zvfh_zvkt_sscofpmf_sstc_svinval_svnapot_svpbmt";
 			riscv,isa-base = "rv64i";
 			riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "b", "v", "zicbom",

-- 
2.53.0



From jtaubepe at redhat.com  Fri Jun 12 06:51:22 2026
From: jtaubepe at redhat.com (Jesse Taube)
Date: Fri, 12 Jun 2026 09:51:22 -0400
Subject: [PATCH v4 05/16] riscv: Add Zicclsm to cpufeature and hwprobe
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-5-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com> <20260611-rva23u64-hwprobe-v2-v4-5-3f01a2449488@gmail.com>
Message-ID: <CADRr4bd10AYwAZwHxEiuSJEOwD5qv68L1r5DRjxXFM8pmrG+WA@mail.gmail.com>

On Thu, Jun 11, 2026 at 4:14?PM Guodong Xu <docular.xu at gmail.com> wrote:
>
> From: Jesse Taube <jesse at rivosinc.com>
>
> Zicclsm requires misaligned support for all regular load and store
> instructions, both scalar and vector, but not AMOs or other
> specialized forms of memory access, to main memory regions with both
> the cacheability and coherence PMAs, as defined in the profiles spec.
> Even though mandated, misaligned loads and stores might execute
> extremely slowly. Standard software distributions should assume their
> existence only for correctness, not for performance.
>
> Reviewed-by: Conor Dooley <conor.dooley at microchip.com>
> Reviewed-by: Andy Chiu <andy.chiu at sifive.com>
> Reviewed-by: Charlie Jenkins <charlie at rivosinc.com>
> Tested-by: Charlie Jenkins <charlie at rivosinc.com>
> Signed-off-by: Jesse Taube <jesse at rivosinc.com>

Thanks for the update! Just an fyi email has changed to
jtaubepe at redhat.com though.
No need to change the signoff though.

Thanks,
Jesse Taube

> [Rebased, rewrote doc text, minor commit message revisions]
> Signed-off-by: Andrew Jones <andrew.jones at oss.qualcomm.com>
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
>
> ---
> v4: No change.
> v3:
> - Move the hwprobe.rst entry to the IMA_EXT_1 section so its
>   documentation matches the IMA_EXT_1 bit it was allocated in v2
>   (Sashiko, agreed by Andrew).
> v2:
> - Rebased onto v7.1-rc2; moved ZICCLSM to IMA_EXT_1 and
>   allocated a new bit for it
> ---
>  Documentation/arch/riscv/hwprobe.rst  | 4 ++++
>  arch/riscv/include/asm/hwcap.h        | 1 +
>  arch/riscv/include/uapi/asm/hwprobe.h | 1 +
>  arch/riscv/kernel/cpufeature.c        | 1 +
>  arch/riscv/kernel/sys_hwprobe.c       | 1 +
>  5 files changed, 8 insertions(+)
>
> diff --git a/Documentation/arch/riscv/hwprobe.rst b/Documentation/arch/riscv/hwprobe.rst
> index d9928641deb99..49d9fb68632d0 100644
> --- a/Documentation/arch/riscv/hwprobe.rst
> +++ b/Documentation/arch/riscv/hwprobe.rst
> @@ -401,3 +401,7 @@ The following keys are defined:
>      as defined in version 1.0 of the RISC-V Control-flow Integrity (CFI)
>      extensions specification, ratified in commit 302a2d45c243
>      ("Update build-pdf.yml") of riscv-cfi.
> +
> +  * :c:macro:`RISCV_HWPROBE_EXT_ZICCLSM`: The Zicclsm extension is supported,
> +    as defined in the RISC-V Profiles specification starting from commit
> +    b1d80660 ("Updated to ratified state.")
> diff --git a/arch/riscv/include/asm/hwcap.h b/arch/riscv/include/asm/hwcap.h
> index 44bf8c7d8acc5..e8f4a7dd96a93 100644
> --- a/arch/riscv/include/asm/hwcap.h
> +++ b/arch/riscv/include/asm/hwcap.h
> @@ -112,6 +112,7 @@
>  #define RISCV_ISA_EXT_ZCLSD            103
>  #define RISCV_ISA_EXT_ZICFILP          104
>  #define RISCV_ISA_EXT_ZICFISS          105
> +#define RISCV_ISA_EXT_ZICCLSM          106
>
>  #define RISCV_ISA_EXT_XLINUXENVCFG     127
>
> diff --git a/arch/riscv/include/uapi/asm/hwprobe.h b/arch/riscv/include/uapi/asm/hwprobe.h
> index 9139edba0aecb..6819df159c51e 100644
> --- a/arch/riscv/include/uapi/asm/hwprobe.h
> +++ b/arch/riscv/include/uapi/asm/hwprobe.h
> @@ -116,6 +116,7 @@ struct riscv_hwprobe {
>  #define RISCV_HWPROBE_KEY_ZICBOP_BLOCK_SIZE    15
>  #define RISCV_HWPROBE_KEY_IMA_EXT_1            16
>  #define                RISCV_HWPROBE_EXT_ZICFISS       (1ULL << 0)
> +#define                RISCV_HWPROBE_EXT_ZICCLSM       (1ULL << 1)
>
>  /* Increase RISCV_HWPROBE_MAX_KEY when adding items. */
>
> diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
> index 686dde3ce3b98..1fb595581adcf 100644
> --- a/arch/riscv/kernel/cpufeature.c
> +++ b/arch/riscv/kernel/cpufeature.c
> @@ -502,6 +502,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
>         __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicbom, RISCV_ISA_EXT_ZICBOM, riscv_xlinuxenvcfg_exts, riscv_ext_zicbom_validate),
>         __RISCV_ISA_EXT_DATA_VALIDATE(zicbop, RISCV_ISA_EXT_ZICBOP, riscv_ext_zicbop_validate),
>         __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicboz, RISCV_ISA_EXT_ZICBOZ, riscv_xlinuxenvcfg_exts, riscv_ext_zicboz_validate),
> +       __RISCV_ISA_EXT_DATA(zicclsm, RISCV_ISA_EXT_ZICCLSM),
>         __RISCV_ISA_EXT_DATA(ziccrse, RISCV_ISA_EXT_ZICCRSE),
>         __RISCV_ISA_EXT_SUPERSET_VALIDATE(zicfilp, RISCV_ISA_EXT_ZICFILP, riscv_xlinuxenvcfg_exts,
>                                           riscv_cfilp_validate),
> diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
> index f8f68ba781b45..9cf62266f1890 100644
> --- a/arch/riscv/kernel/sys_hwprobe.c
> +++ b/arch/riscv/kernel/sys_hwprobe.c
> @@ -205,6 +205,7 @@ static void hwprobe_isa_ext1(struct riscv_hwprobe *pair,
>                  * in the hart_isa bitmap, are made.
>                  */
>                 EXT_KEY(isainfo->isa, ZICFISS, pair->value, missing);
> +               EXT_KEY(isainfo->isa, ZICCLSM, pair->value, missing);
>         }
>
>         /* Now turn off reporting features if any CPU is missing it. */
>
> --
> 2.43.0
>
>
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv
>



From thomas.weissschuh at linutronix.de  Fri Jun 12 07:24:46 2026
From: thomas.weissschuh at linutronix.de (Thomas =?utf-8?Q?Wei=C3=9Fschuh?=)
Date: Fri, 12 Jun 2026 16:24:46 +0200
Subject: [PATCH] mm/page_table_check: do not track special (PFN-mapped)
 PTEs
In-Reply-To: <20260608155758.1220420-1-andrey.smirnov@siderolabs.com>
References: <20260608155758.1220420-1-andrey.smirnov@siderolabs.com>
Message-ID: <20260612162031-b4731d21-b293-4d36-8582-26394bd55a1f@linutronix.de>

On Mon, Jun 08, 2026 at 07:57:58PM +0400, Andrey Smirnov wrote:
> The vDSO data store ("[vvar]") special mapping is created as a VM_PFNMAP
> mapping and its pages are installed into userspace with vmf_insert_pfn(),
> which produces special PTEs (pte_special()). On x86 and arm64 (and riscv)
> pte_user_accessible_page() only tests the PRESENT/USER bits and does not
> exclude special PTEs, so page_table_check accounts these PFN mappings in
> the per-page anon/file map counters even though they are not rmap-managed
> pages (vm_normal_page() returns NULL for them).
> 
> Most of these data pages live in the kernel image and are never freed, so
> the stray accounting is invisible. The time-namespace VVAR page is the
> exception: it is a real alloc_page() page that is released with
> __free_page() in free_time_ns() when the last task of a time namespace
> exits. Across the map / unmap / vdso_join_timens() zap transitions the
> special-PTE accounting is not balanced for this page, so a non-zero
> file_map_count survives to the free path and trips:
> 
>   kernel BUG at mm/page_table_check.c:143!
>   __page_table_check_zero+0xfb/0x130
>   __free_frozen_pages+0x52f/0x650
>   free_time_ns+0x85/0xc0
>   free_nsproxy+0x7f/0x130
>   do_exit+0x313/0xa60
>   do_group_exit+0x77/0x90
> 
> This is reliably reproducible on x86_64 and arm64 under heavy container/CI
> churn that rapidly creates and destroys time namespaces (CLONE_NEWTIME via
> runc / docker-init / tini), and was independently reported by syzbot on
> riscv. It only manifests when CONFIG_PAGE_TABLE_CHECK is active.
> 
> Special PTEs have no struct-page rmap semantics and must never have been
> tracked by page table check. Skip them in both the set and clear paths so
> the counters stay balanced (always zero) for PFN-mapped pages, regardless
> of how the architecture defines pte_user_accessible_page(). pte_special()
> is available generically (it is a no-op returning false on architectures
> without ARCH_HAS_PTE_SPECIAL), so this is a single, arch-independent fix.
> 
> Note that the v7.0 generic vDSO datastore rework in commit 05988dba1179
> ("vdso/datastore: Allocate data pages dynamically") incidentally avoids
> the problem by switching the mapping to VM_MIXEDMAP + vmf_insert_page()
> with balanced struct-page accounting. This patch fixes the still-affected
> VM_PFNMAP path used by 6.18.y and earlier, and additionally makes
> page_table_check robust against any future PFN-mapped user pages.
> 
> Fixes: df4e817b7108 ("mm: page table check")
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Thomas Wei?schuh <thomas.weissschuh at linutronix.de>
> Cc: Andrei Vagin <avagin at gmail.com>
> Cc: Andy Lutomirski <luto at kernel.org>
> Cc: Vincenzo Frascino <vincenzo.frascino at arm.com>
> Reported-by: syzbot+2b5fe617654be3d8848b at syzkaller.appspotmail.com
> Closes: https://github.com/siderolabs/talos/issues/13496
> Cc: stable at vger.kernel.org
> Signed-off-by: Andrey Smirnov <andrey.smirnov at siderolabs.com>
> ---
>  mm/page_table_check.c | 13 ++++++++++---
>  1 file changed, 10 insertions(+), 3 deletions(-)
> 
> diff --git a/mm/page_table_check.c b/mm/page_table_check.c
> index 4eeca782b888..ee492d5389b9 100644
> --- a/mm/page_table_check.c
> +++ b/mm/page_table_check.c
> @@ -150,9 +150,16 @@ void __page_table_check_pte_clear(struct mm_struct *mm, pte_t pte)
>  	if (&init_mm == mm)
>  		return;
>  
> -	if (pte_user_accessible_page(pte)) {
> +	/*
> +	 * PFN-mapped (special) PTEs - e.g. the vDSO/time-namespace "[vvar]"
> +	 * mapping installed via vmf_insert_pfn() - are not rmap-managed and
> +	 * must not be tracked here. Tracking them can leave a non-zero map
> +	 * count on a struct page that is later freed (the time namespace VVAR
> +	 * page in free_time_ns()), tripping the BUG_ON() in
> +	 * __page_table_check_zero().

As this comment mentioning the [vvar] pages is already stale, IMO this should
not be mentioned specifically. It is also not clear to me why this only happens
now and where the non-zero map count comes from.

> +	 */
> +	if (pte_user_accessible_page(pte) && !pte_special(pte))
>  		page_table_check_clear(pte_pfn(pte), PAGE_SIZE >> PAGE_SHIFT);
> -	}
>  }
>  EXPORT_SYMBOL(__page_table_check_pte_clear);
>  
> @@ -205,7 +212,7 @@ void __page_table_check_ptes_set(struct mm_struct *mm, pte_t *ptep, pte_t pte,
>  
>  	for (i = 0; i < nr; i++)
>  		__page_table_check_pte_clear(mm, ptep_get(ptep + i));
> -	if (pte_user_accessible_page(pte))
> +	if (pte_user_accessible_page(pte) && !pte_special(pte))
>  		page_table_check_set(pte_pfn(pte), nr, pte_write(pte));
>  }
>  EXPORT_SYMBOL(__page_table_check_ptes_set);
> -- 
> 2.53.0
> 


From robh at kernel.org  Fri Jun 12 07:41:22 2026
From: robh at kernel.org (Rob Herring)
Date: Fri, 12 Jun 2026 09:41:22 -0500
Subject: [PATCH v3 05/11] of: reserved_mem: split
 alloc_reserved_mem_array() from fdt_scan_reserved_mem_late()
In-Reply-To: <20260527032917.3385849-6-chenwandun1@gmail.com>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <20260527032917.3385849-6-chenwandun1@gmail.com>
Message-ID: <20260612144122.GA974326-robh@kernel.org>

On Wed, May 27, 2026 at 11:29:11AM +0800, Wandun Chen wrote:
> From: Wandun Chen <chenwandun at lixiang.com>
> 
> Prepare for storing /memreserve/ entries in the reserved_mem array.
> alloc_reserved_mem_array is skipped if the device tree lacks a
> /reserved-memory node, pointer 'reserved_mem' continues to reference
> the reserved_mem_array which lives in __initdata, storing
> /memreserve/ entries into reserved_mem_array would result in metadata
> loss, and an out-of-bounds memory access will occur if the device
> tree contains more than MAX_RESERVED_REGIONS /memreserve/ entries.
> 
> So split alloc_reserved_mem_array() from fdt_scan_reserved_mem_late(),
> and call alloc_reserved_mem_array() whether or not there is a
> /reserved-memory node.
> 
> No functional change.
> The actual /memreserve/ population is added in a follow-up patch.
> 
> Signed-off-by: Wandun Chen <chenwandun at lixiang.com>
> ---
>  drivers/of/fdt.c             | 7 +++++--
>  drivers/of/of_private.h      | 1 +
>  drivers/of/of_reserved_mem.c | 6 +-----
>  3 files changed, 7 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
> index 82f7327c59ea..83a2a474831e 100644
> --- a/drivers/of/fdt.c
> +++ b/drivers/of/fdt.c
> @@ -1284,8 +1284,11 @@ void __init unflatten_device_tree(void)
>  {
>  	void *fdt = initial_boot_params;
>  
> -	/* Save the statically-placed regions in the reserved_mem array */
> -	fdt_scan_reserved_mem_late();
> +	/* Attempt dynamic allocation of a new reserved_mem array */
> +	if (fdt && alloc_reserved_mem_array()) {
> +		/* Save the statically-placed regions in the reserved_mem array */
> +		fdt_scan_reserved_mem_late();

Can we make this just:

alloc_reserved_mem_array();
fdt_scan_reserved_mem_late();

We already check !fdt in fdt_scan_reserved_mem_late().

Rob


From robh at kernel.org  Fri Jun 12 07:42:52 2026
From: robh at kernel.org (Rob Herring)
Date: Fri, 12 Jun 2026 09:42:52 -0500
Subject: [PATCH v3 00/11] kdump: reduce vmcore size and capture time
In-Reply-To: <20260527032917.3385849-1-chenwandun1@gmail.com>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
Message-ID: <20260612144252.GB974326-robh@kernel.org>

On Wed, May 27, 2026 at 11:29:06AM +0800, Wandun Chen wrote:
> From: Wandun Chen <chenwandun at lixiang.com>
> 
> On SoCs that carve out large firmware-owned reserved memory (GPU
> firmware, DSP, modem, camera ISP, NPU, ...), kdump currently dumps
> those carveouts as part of system RAM even though their contents are
> firmware state that is not useful for kernel crash analysis.
> 
> This series introduces an opt-in 'dumpable' flag [1] on struct
> reserved_mem and uses it to filter the elfcorehdr PT_LOAD ranges on
> DT-based architectures (arm64, riscv, loongarch). By default reserved
> regions are treated as non-dumpable; CMA regions are explicitly opted
> in because their pages are returned to the buddy allocator and may
> carry key crash-analysis data.
> 
> The series is organized as follows:
> Patches 1-3: Pre-existing fixes and a small prep change.
> Patches 4-5: Restructure to allow appending /memreserve/ entries.
> Patches 6-7: Add a dumpable flag and append /memreserve/ entries.
> Patch 8: Add generic kdump helpers.
> Patches 9-11: Wire the helpers into arm64, riscv and loongarch kdump
>               elfcorehdr preparation.
> 
> v2 --> v3:
> 1. Fix out-of-bounds issue if device tree lacks /reserved-memory node.[2]
> 2. Fix UAF issue when alloc_reserved_mem_array() fails.
> 3. Add some prepare patches.
> 
> v1 --> v2:
> 1. v1 added an opt-out DT property ('linux,no-dump'). Per Rob's
>    feedback [1], v2 drop that property and exclude reserve memory
>    by default.
> 2. Split some prepared patches from the original patches.
> 3. Address coding-style comments on patch 5 from Rob.
> 
> [1] https://lore.kernel.org/lkml/20260506144542.GA2072596-robh at kernel.org/
> [2] https://sashiko.dev/#/patchset/20260520091844.592753-1-chenwandun%40lixiang.com?part=4
> 
> Wandun Chen (11):
>   of: reserved_mem: handle NULL name in of_reserved_mem_lookup()

>   of: reserved_mem: zero total_reserved_mem_cnt if no valid
>     /reserved-memory entry

I applied these 2 for 7.2.

Rob


From mhklinux at outlook.com  Fri Jun 12 08:45:19 2026
From: mhklinux at outlook.com (Michael Kelley)
Date: Fri, 12 Jun 2026 15:45:19 +0000
Subject: [PATCH RFC 3/3] arm64: Add HOTPLUG_PARALLEL support for secondary
 CPUs
In-Reply-To: <20260611133809.3854977-4-ruanjinjie@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
 <20260611133809.3854977-4-ruanjinjie@huawei.com>
Message-ID: <SN6PR02MB41575306521E6223561F476FD4182@SN6PR02MB4157.namprd02.prod.outlook.com>

From: Jinjie Ruan <ruanjinjie at huawei.com> Sent: Thursday, June 11, 2026 6:38 AM
> 
> Support for parallel secondary CPU bringup is already utilized by x86,
> MIPS, and RISC-V. This patch brings this capability to the arm64
> architecture.
> 
> Rework the global `secondary_data` accessed during early boot into
> a per-CPU array. This array maps logical CPU IDs to MPIDR_EL1 values,
> enabling the early boot code in head.S to resolve each secondary CPU's
> logical ID concurrently.
> 
> To fully enable HOTPLUG_PARALLEL, this patch implements:
> 1) An arm64-specific arch_cpuhp_kick_ap_alive() handler.
> 2) Callbacks to cpuhp_ap_sync_alive() inside secondary_start_kernel().
> 
> Successfully tested on QEMU ARM64 virt machine (KVM on, 128 vCPUs).
> 
> |     test kernel	   | secondary CPUs boot time |
> |  ---------------------   |	--------------------  |
> |   Without this patch     |		155.672	      |
> |   cpuhp.parallel=0	   |		62.897	      |
> |   cpuhp.parallel=1	   |		166.703	      |

The last two rows seem mixed up. I would expect parallel=0 to
result in a longer boot time.

Michael

> 
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/arm64/Kconfig           |  1 +
>  arch/arm64/include/asm/smp.h |  8 ++++++++
>  arch/arm64/kernel/head.S     | 23 +++++++++++++++++++++++
>  arch/arm64/kernel/smp.c      | 27 +++++++++++++++++++++++++++
>  4 files changed, 59 insertions(+)
> 



From mhklinux at outlook.com  Fri Jun 12 08:51:51 2026
From: mhklinux at outlook.com (Michael Kelley)
Date: Fri, 12 Jun 2026 15:51:51 +0000
Subject: [PATCH RFC 0/3] arm64: Add HOTPLUG_PARALLEL support for secondary
 CPUs
In-Reply-To: <20260611133809.3854977-1-ruanjinjie@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
Message-ID: <SN6PR02MB41575CD5883C01FCB7F35E2DD4182@SN6PR02MB4157.namprd02.prod.outlook.com>

From: Jinjie Ruan <ruanjinjie at huawei.com> Sent: Thursday, June 11, 2026 6:38 AM
> 
> Support for parallel secondary CPU bringup is already utilized by x86,
> MIPS, and RISC-V. This patch brings this capability to the arm64
> architecture.
> 
> Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST to avoid primary SMT threads
> to boot first constraint.
> 
> And Add a 'cpu' parameter to update_cpu_boot_status() to allow updating the
> boot status at a per-CPU granularity during parallel bringup.
> 
> Rework the global `secondary_data` accessed during early boot into
> a per-CPU array. This array maps logical CPU IDs to MPIDR_EL1 values,
> enabling the early boot code in head.S to resolve each secondary CPU's
> logical ID concurrently.

I tested the series on an ARM64 VM running on Hyper-V in the Azure cloud.
Tested with 16 vCPUs in the VM and with 96 vCPUs in the VM. No issues.
I mainly wanted to make sure nothing expected happened with Hyper-V as
the host.

With 96 vCPUs, the secondary CPU startup time drops from ~140 milliseconds
to ~130 milliseconds. That improvement is not as dramatic as you saw on
QEMU, so I presume the difference is due to the hypervisor implementation
of the PSCI calls.

Tested-by: Michael Kelley <mhklinux at outlook.com>

> 
> Jinjie Ruan (3):
>   cpu/hotplug: Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST
>   arm64: smp: Pass CPU ID to update_cpu_boot_status()
>   arm64: Add HOTPLUG_PARALLEL support for secondary CPUs
> 
>  arch/Kconfig                   |  4 ++++
>  arch/arm64/Kconfig             |  1 +
>  arch/arm64/include/asm/smp.h   | 14 +++++++++++---
>  arch/arm64/kernel/cpufeature.c |  2 +-
>  arch/arm64/kernel/head.S       | 23 ++++++++++++++++++++++
>  arch/arm64/kernel/smp.c        | 35 ++++++++++++++++++++++++++++++----
>  arch/arm64/mm/context.c        |  2 +-
>  arch/mips/Kconfig              |  1 +
>  arch/riscv/Kconfig             |  1 +
>  arch/x86/Kconfig               |  1 +
>  kernel/cpu.c                   |  6 +++++-
>  11 files changed, 80 insertions(+), 10 deletions(-)
> 
> --
> 2.34.1
> 



From asrinivasan at oss.tenstorrent.com  Fri Jun 12 09:24:43 2026
From: asrinivasan at oss.tenstorrent.com (Anirudh Srinivasan)
Date: Fri, 12 Jun 2026 11:24:43 -0500
Subject: [PATCH] riscv: drop __init from
 vec_check_unaligned_access_speed_all_cpus
Message-ID: <20260612-vec_unaligned_drop_init-v1-1-df969210ae34@oss.tenstorrent.com>

This function runs within a kthread and need not necessarily finish
before system finishes boot and free_initmem() unmaps the .init.text
section. This function makes calls to SBI for probing unaligned access
speed, and if this is slow for some reason (say some debug prints were
added to SBI), the kthread can still be running at this point and result
in an instruction page fault when trying to fetch from the freed region.

[   25.642087] Unable to handle kernel paging request at virtual address ffffffff80a04ef8
[   25.646694] Current vec_check_unali pgtable: 4K pagesize, 48-bit VAs, pgdp=0x00004000316e9000
[   25.653170] [ffffffff80a04ef8] pgd=000010004be7e401, p4d=000010004be7e401, pud=000010004be7e001, pmd=000010000c3000e3
[   25.661244] Oops [#1]
[   25.662997] Modules linked in:
[   25.665357] CPU: 3 UID: 0 PID: 42 Comm: vec_check_unali Not tainted 7.0.0-tt-blackhole-asrinivasan-00007-g30ff73f18211 #570 PREEMPTLAZY
[   25.674669] Hardware name: Tenstorrent Blackhole (DT)
[   25.678545] epc : vec_check_unaligned_access_speed_all_cpus+0x18/0x2c
[   25.683458]  ra : vec_check_unaligned_access_speed_all_cpus+0x18/0x2c
[   25.688372] epc : ffffffff80a04ef8 ra : ffffffff80a04ef8 sp : ffff8f8000203e20
[   25.693874]  gp : ffffffff814dc168 tp : ffffaf8001ad9900 t0 : 0000000000000000
[   25.699401]  t1 : fffffffffffffff0 t2 : ffffaf8001ad9a10 s0 : ffff8f8000203e30
[   25.704912]  s1 : ffffaf80018dc780 a0 : 0000000000000000 a1 : 0000000000000002
[   25.710407]  a2 : 00000000000001f0 a3 : 0000000000000018 a4 : 0000000000000000
[   25.715917]  a5 : 0000000000000000 a6 : ffffaf8001c03d98 a7 : ffffaf8001c03e30
[   25.721419]  s2 : ffff8f8000023c98 s3 : ffffaf8001aa1240 s4 : ffffffff80a04ee0
[   25.726937]  s5 : 0000000000000000 s6 : 0000000000000000 s7 : 0000000000000000
[   25.732450]  s8 : 0000000000000000 s9 : 0000000000000000 s10: 0000000000000000
[   25.737944]  s11: 0000000000000000 t3 : 0000000000000002 t4 : 0000000000000402
[   25.743481]  t5 : 0000000000000040 t6 : 0000000000000004 ssp : 0000000000000000
[   25.749024] status: 0000000200000120 badaddr: ffffffff80a04ef8 cause: 000000000000000c
[   25.755060] [<ffffffff80a04ef8>] vec_check_unaligned_access_speed_all_cpus+0x18/0x2c
[   25.760964] [<ffffffff80047a10>] kthread+0xd8/0xfc
[   25.764660] [<ffffffff80010c48>] ret_from_fork_kernel+0x18/0x1c4
[   25.769220] [<ffffffff80895fe6>] ret_from_fork_kernel_asm+0x16/0x18
[   25.774018] Code: cccc cccc cccc cccc cccc cccc cccc cccc cccc cccc (cccc) cccc

Drop __init from its signature so that this doesn't happen.

Fixes: a00e022be531 ("riscv: Annotate unaligned access init functions")
Signed-off-by: Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>
Assisted-by: Claude:claude-opus-4-6
---
 arch/riscv/kernel/unaligned_access_speed.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c
index 485ab1d105d36..366baca73dc27 100644
--- a/arch/riscv/kernel/unaligned_access_speed.c
+++ b/arch/riscv/kernel/unaligned_access_speed.c
@@ -325,7 +325,7 @@ static void check_vector_unaligned_access(struct work_struct *work __always_unus
 }
 
 /* Measure unaligned access speed on all CPUs present at boot in parallel. */
-static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
+static int vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
 {
 	schedule_on_each_cpu(check_vector_unaligned_access);
 	riscv_hwprobe_complete_async_probe();
@@ -333,7 +333,7 @@ static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __alway
 	return 0;
 }
 #else /* CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS */
-static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
+static int vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
 {
 	return 0;
 }

---
base-commit: 863f9b49d618e02e3ecadeb89ebd39064ba8c2fd
change-id: 20260612-vec_unaligned_drop_init-c7af506a375e

Best regards,
--  
Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>



From robh at kernel.org  Fri Jun 12 09:28:56 2026
From: robh at kernel.org (Rob Herring (Arm))
Date: Fri, 12 Jun 2026 11:28:56 -0500
Subject: [PATCH net-next v8 1/6] dt-bindings: ethernet: eswin: relax
 internal delay model to range-based constraints
In-Reply-To: <20260610012849.874-1-lizhi2@eswincomputing.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
 <20260610012849.874-1-lizhi2@eswincomputing.com>
Message-ID: <178128173639.1162200.4235173600332300329.robh@kernel.org>


On Wed, 10 Jun 2026 09:28:49 +0800, lizhi2 at eswincomputing.com wrote:
> From: Zhi Li <lizhi2 at eswincomputing.com>
> 
> Relax internal delay constraints for EIC7700 Ethernet binding.
> 
> Replace fixed enumeration of rx-internal-delay-ps and tx-internal-delay-ps
> with a range-based definition (0-2540 ps, 20 ps steps) to reflect actual
> hardware capability.
> 
> Mark rx/tx internal delay properties as optional, as they are board-
> specific tuning parameters rather than mandatory configuration.
> 
> Update the device tree example to align with the relaxed constraint model
> and remove delay properties from the example to avoid implying they are
> required.
> 
> No functional change to existing DT users.
> 
> Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
> ---
>  .../bindings/net/eswin,eic7700-eth.yaml       | 25 ++++++++++---------
>  1 file changed, 13 insertions(+), 12 deletions(-)
> 

Reviewed-by: Rob Herring (Arm) <robh at kernel.org>



From wangruikang at iscas.ac.cn  Fri Jun 12 11:36:51 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Sat, 13 Jun 2026 02:36:51 +0800
Subject: riscv: Heads up: If 7.1 hangs on boot near "vector unaligned word
 access speed"
Message-ID: <edcf9101-8ae5-49c8-a2be-82fd7a5cb3a8@iscas.ac.cn>

Hi Linux 7.1 on riscv users,

If you get boot hangs and/or panics near where the kernel says:

    cpuN: vector unaligned word access speed is 0.01x byte access speed (slow)

Possibly with additional messages such as these:

    sbi_trap_error: hart1: trap1: load fault handler failed (error -3)

    sbi_trap_error: hart1: trap1: store fault handler failed (error -3)

    [    0.252142] Oops - instruction access fault [#1]

You're likely running into a now exposed OpenSBI stack overrun bug in
misaligned vector access emulation.

As a quick fix, apply this patch to OpenSBI 1.7 or 1.8 to increase the
stack size:

? ? https://lore.kernel.org/opensbi/edbce78c-71a7-41d7-aa81-3fa57241644a at iscas.ac.cn

What happened?
--------------

Commit b69bcb13ed70 ("riscv: misaligned: Make enabling delegation depend
on NONPORTABLE") made it so that the in-kernel misaligned access
emulation handler is disabled for now, since it is very
feature-incomplete and crashes KVM guests, and userspace and kernel
vector users.

However, this means that the firmware emulation is now in use, which
exposed this latent issue. It turns out the vector misaligned access
handler uses a 8192-byte stack buffer, whereas the entire per-hart stack
in OpenSBI defaults to 8192 bytes. This is a straightforward stack
overrun and either crashes OpenSBI or worse, causes it to misbehave and
creating further errors.

Currently, I believe it is the right thing to ask affected users to fix
their OpenSBI, since as far as I can find, no generally available
hardware ships with the affected OpenSBI versions (specifically, 1.7+
with stack size 8192), neither as factory default nor as separately
provided by the vendor. All possible cases I've been able to gather
affect either in-development platforms, or boards where the user has
replaced their firmware to have new OpenSBI (e.g. SpacemiT K1).

What do I do now?
-----------------

Apply that patch and replace your firmware's OpenSBI, probably the same
way you put it there in the first place. If you can't or don't know how,
please get in touch.

If it is convenient for you, I would appreciate if anyone who runs into
this can get in touch with me if you haven't done so. Feedback from
affected users on how to proceed is appreciated.

Also possible check out previous discussions:

- https://lore.kernel.org/linux-riscv/nrvt74qnojaubiwjo37ums4lnclu466hovwrhmtbag6f5uhrql at q6msoe2oto4b/T
- https://lore.kernel.org/opensbi/edbce78c-71a7-41d7-aa81-3fa57241644a at iscas.ac.cn/T

Furthermore, there is work in progress to make the vector misaligned
access handler not to use so much stack, thanks to Bo Gan:

- https://lore.kernel.org/opensbi/20260609060024.706-1-ganboing at gmail.com/

Thanks and with apologies,
Vivian "dramforever" Wang



From namcao at linutronix.de  Fri Jun 12 14:23:57 2026
From: namcao at linutronix.de (Nam Cao)
Date: Fri, 12 Jun 2026 23:23:57 +0200
Subject: [PATCH] riscv: drop __init from
 vec_check_unaligned_access_speed_all_cpus
In-Reply-To: <20260612-vec_unaligned_drop_init-v1-1-df969210ae34@oss.tenstorrent.com>
References: <20260612-vec_unaligned_drop_init-v1-1-df969210ae34@oss.tenstorrent.com>
Message-ID: <87ecibwiz6.fsf@yellow.woof>

Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com> writes:
> This function runs within a kthread and need not necessarily finish
> before system finishes boot and free_initmem() unmaps the .init.text
> section. This function makes calls to SBI for probing unaligned access
> speed, and if this is slow for some reason (say some debug prints were
> added to SBI), the kthread can still be running at this point and result
> in an instruction page fault when trying to fetch from the freed region.
...
> Drop __init from its signature so that this doesn't happen.

That should work.

But we should really take a step back and reconsider whether running the
vector access speed probe in a kthread is really a good idea.

We have a problem in the past that the kthread may not complete before
user reads vdso, and user gets incorrect values. That was addressed by
5d15d2ad36b0 ("riscv: hwprobe: Fix stale vDSO data for late-initialized
keys at boot") which complicates things.

And now you discover another issue.

The motivation for using a kthread is to avoid boot time slow down. But
this has been bothering me for quite a while now, because I am not sure
if using kthread really speeds things up. Sooner or later, the kthread
has to run. If it runs before the kernel is done booting, then the boot
is even slower due to overhead of the kthread. If it runs after the
kernel finishes booting, then we run into these kinds of
headache. Unfortunately I do not have a riscv cpu with vector to confirm
my suspicion.

Furthermore, the vector access speed probe takes the same amount of time
as scalar access speed probe. The scalar one is done without any
kthread, and no one ever complained about boot time issue (well, someone
did complain but that has nothing to do with kthread. Their 64-core (?)
system is slower because the probe was done serially, and we switched to
parallel probe and it was fine).

So I think we should really get rid of that kthread entirely, the
headache is not worth. That also allows reverting 5d15d2ad36b0 ("riscv:
hwprobe: Fix stale vDSO data for late-initialized keys at boot"), making
the code simplier.

Below is a patch that has only been tested with qemu. It reverts the
mentioned commit and removes the kthread.

diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h
index 8c572a464719..2f278c395af9 100644
--- a/arch/riscv/include/asm/hwprobe.h
+++ b/arch/riscv/include/asm/hwprobe.h
@@ -42,11 +42,4 @@ static inline bool riscv_hwprobe_pair_cmp(struct riscv_hwprobe *pair,
 	return pair->value == other_pair->value;
 }
 
-#ifdef CONFIG_MMU
-void riscv_hwprobe_register_async_probe(void);
-void riscv_hwprobe_complete_async_probe(void);
-#else
-static inline void riscv_hwprobe_register_async_probe(void) {}
-static inline void riscv_hwprobe_complete_async_probe(void) {}
-#endif
 #endif
diff --git a/arch/riscv/include/asm/vdso/arch_data.h b/arch/riscv/include/asm/vdso/arch_data.h
index 88b37af55175..da57a3786f7a 100644
--- a/arch/riscv/include/asm/vdso/arch_data.h
+++ b/arch/riscv/include/asm/vdso/arch_data.h
@@ -12,12 +12,6 @@ struct vdso_arch_data {
 
 	/* Boolean indicating all CPUs have the same static hwprobe values. */
 	__u8 homogeneous_cpus;
-
-	/*
-	 * A gate to check and see if the hwprobe data is actually ready, as
-	 * probing is deferred to avoid boot slowdowns.
-	 */
-	__u8 ready;
 };
 
 #endif /* __RISCV_ASM_VDSO_ARCH_DATA_H */
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 0f701ace3bb9..f3ed4fd396fb 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -5,9 +5,6 @@
  * more details.
  */
 #include <linux/syscalls.h>
-#include <linux/completion.h>
-#include <linux/atomic.h>
-#include <linux/once.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
 #include <asm/hwprobe.h>
@@ -470,32 +467,28 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,
 	return 0;
 }
 
-#ifdef CONFIG_MMU
-
-static DECLARE_COMPLETION(boot_probes_done);
-static atomic_t pending_boot_probes = ATOMIC_INIT(1);
-
-void riscv_hwprobe_register_async_probe(void)
+static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs,
+			    size_t pair_count, size_t cpusetsize,
+			    unsigned long __user *cpus_user,
+			    unsigned int flags)
 {
-	atomic_inc(&pending_boot_probes);
-}
+	if (flags & RISCV_HWPROBE_WHICH_CPUS)
+		return hwprobe_get_cpus(pairs, pair_count, cpusetsize,
+					cpus_user, flags);
 
-void riscv_hwprobe_complete_async_probe(void)
-{
-	if (atomic_dec_and_test(&pending_boot_probes))
-		complete(&boot_probes_done);
+	return hwprobe_get_values(pairs, pair_count, cpusetsize,
+				  cpus_user, flags);
 }
 
-static int complete_hwprobe_vdso_data(void)
+#ifdef CONFIG_MMU
+
+static int __init init_hwprobe_vdso_data(void)
 {
 	struct vdso_arch_data *avd = vdso_k_arch_data;
 	u64 id_bitsmash = 0;
 	struct riscv_hwprobe pair;
 	int key;
 
-	if (unlikely(!atomic_dec_and_test(&pending_boot_probes)))
-		wait_for_completion(&boot_probes_done);
-
 	/*
 	 * Initialize vDSO data with the answers for the "all CPUs" case, to
 	 * save a syscall in the common case.
@@ -523,52 +516,13 @@ static int complete_hwprobe_vdso_data(void)
 	 * vDSO should defer to the kernel for exotic cpu masks.
 	 */
 	avd->homogeneous_cpus = id_bitsmash != 0 && id_bitsmash != -1;
-
-	/*
-	 * Make sure all the VDSO values are visible before we look at them.
-	 * This pairs with the implicit "no speculativly visible accesses"
-	 * barrier in the VDSO hwprobe code.
-	 */
-	smp_wmb();
-	avd->ready = true;
-	return 0;
-}
-
-static int __init init_hwprobe_vdso_data(void)
-{
-	struct vdso_arch_data *avd = vdso_k_arch_data;
-
-	/*
-	 * Prevent the vDSO cached values from being used, as they're not ready
-	 * yet.
-	 */
-	avd->ready = false;
 	return 0;
 }
 
 arch_initcall_sync(init_hwprobe_vdso_data);
 
-#else
-
-static int complete_hwprobe_vdso_data(void) { return 0; }
-
 #endif /* CONFIG_MMU */
 
-static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs,
-			    size_t pair_count, size_t cpusetsize,
-			    unsigned long __user *cpus_user,
-			    unsigned int flags)
-{
-	DO_ONCE_SLEEPABLE(complete_hwprobe_vdso_data);
-
-	if (flags & RISCV_HWPROBE_WHICH_CPUS)
-		return hwprobe_get_cpus(pairs, pair_count, cpusetsize,
-					cpus_user, flags);
-
-	return hwprobe_get_values(pairs, pair_count, cpusetsize,
-				cpus_user, flags);
-}
-
 SYSCALL_DEFINE5(riscv_hwprobe, struct riscv_hwprobe __user *, pairs,
 		size_t, pair_count, size_t, cpusetsize, unsigned long __user *,
 		cpus, unsigned int, flags)
diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c
index 70b5e6927620..6a725eee5acd 100644
--- a/arch/riscv/kernel/unaligned_access_speed.c
+++ b/arch/riscv/kernel/unaligned_access_speed.c
@@ -375,19 +375,6 @@ static void check_vector_unaligned_access(struct work_struct *work __always_unus
 	__free_pages(page, MISALIGNED_BUFFER_ORDER);
 }
 
-/* Measure unaligned access speed on all CPUs present at boot in parallel. */
-static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
-{
-	schedule_on_each_cpu(check_vector_unaligned_access);
-	riscv_hwprobe_complete_async_probe();
-
-	return 0;
-}
-#else /* CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS */
-static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
-{
-	return 0;
-}
 #endif
 
 static int riscv_online_cpu_vec(unsigned int cpu)
@@ -474,12 +461,7 @@ static int __init check_unaligned_access_all_cpus(void)
 			per_cpu(vector_misaligned_access, cpu) = unaligned_vector_speed_param;
 	} else if (!check_vector_unaligned_access_emulated_all_cpus() &&
 		   IS_ENABLED(CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS)) {
-		riscv_hwprobe_register_async_probe();
-		if (IS_ERR(kthread_run(vec_check_unaligned_access_speed_all_cpus,
-				       NULL, "vec_check_unaligned_access_speed_all_cpus"))) {
-			pr_warn("Failed to create vec_unalign_check kthread\n");
-			riscv_hwprobe_complete_async_probe();
-		}
+		schedule_on_each_cpu(check_vector_unaligned_access);
 	}
 
 	/*
diff --git a/arch/riscv/kernel/vdso/hwprobe.c b/arch/riscv/kernel/vdso/hwprobe.c
index 8f45500d0a6e..2ddeba6c68dd 100644
--- a/arch/riscv/kernel/vdso/hwprobe.c
+++ b/arch/riscv/kernel/vdso/hwprobe.c
@@ -27,7 +27,7 @@ static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count,
 	 * homogeneous, then this function can handle requests for arbitrary
 	 * masks.
 	 */
-	if (flags != 0 || (!all_cpus && !avd->homogeneous_cpus) || unlikely(!avd->ready))
+	if ((flags != 0) || (!all_cpus && !avd->homogeneous_cpus))
 		return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
 
 	/* This is something we can handle, fill out the pairs. */


From namcao at linutronix.de  Fri Jun 12 14:50:13 2026
From: namcao at linutronix.de (Nam Cao)
Date: Fri, 12 Jun 2026 23:50:13 +0200
Subject: [PATCH] riscv: hwprobe: Avoid uninitialized read in
 hwprobe_get_cpus()
In-Reply-To: <20260612045502.70850-1-mark.hsj@gmail.com>
References: <20260612045502.70850-1-mark.hsj@gmail.com>
Message-ID: <87qzmbe8dm.fsf@yellow.woof>

Mark Harris <mark.hsj at gmail.com> writes:
> When cpusetsize < cpumask_size(), hwprobe_get_cpus() did not fully
> initialize its copy of the cpu mask, which could cause non-deterministic
> results from the riscv_hwprobe syscall on a system with more than 8 CPUs
> when the supplied cpu mask is empty.  Address this by fully initializing
> the cpu mask.
>
> Signed-off-by: Mark Harris <mark.hsj at gmail.com>

Reviewed-by: Nam Cao <namcao at linutronix.de>


From andrew at lunn.ch  Sat Jun 13 00:48:46 2026
From: andrew at lunn.ch (Andrew Lunn)
Date: Sat, 13 Jun 2026 09:48:46 +0200
Subject: [PATCH net-next v8 3/6] net: stmmac: eic7700: make RGMII delay
 properties optional
In-Reply-To: <eaa645fc-be06-4a15-8c2f-6e82129c4715@bootlin.com>
References: <20260610012727.848-1-lizhi2@eswincomputing.com>
 <20260610012937.911-1-lizhi2@eswincomputing.com>
 <eaa645fc-be06-4a15-8c2f-6e82129c4715@bootlin.com>
Message-ID: <30229cfe-b395-4d0f-81ef-eb780ac26599@lunn.ch>

On Wed, Jun 10, 2026 at 10:26:50AM +0200, Maxime Chevallier wrote:
> Hi,
> 
> On 6/10/26 03:29, lizhi2 at eswincomputing.com wrote:
> > From: Zhi Li <lizhi2 at eswincomputing.com>
> > 
> > Make rx-internal-delay-ps and tx-internal-delay-ps optional in the
> > EIC7700 DWMAC driver.
> > 
> > The driver previously required both properties to be present and would
> > fail probe when they were missing. This restricts valid hardware
> > configurations where RGMII timing is instead provided by the PHY or
> > board design.
> > 
> > Update the driver to treat missing delay properties as zero delay,
> > allowing systems without explicit MAC-side delay tuning to operate
> > correctly.
> > 
> > This aligns the driver behavior with the updated device tree binding
> > and provides a safe default configuration when MAC-side delay
> > programming is not required.
> > 
> > Signed-off-by: Zhi Li <lizhi2 at eswincomputing.com>
> > ---
> >  drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c | 6 ------
> >  1 file changed, 6 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> > index 4ac979d874d6..ec99b597aeaf 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-eic7700.c
> > @@ -165,9 +165,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
> >  		dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_RX_ADJ_DELAY;
> >  		dwc_priv->eth_clk_dly_param |=
> >  				 FIELD_PREP(EIC7700_ETH_RX_ADJ_DELAY, val);
> > -	} else {
> > -		return dev_err_probe(&pdev->dev, -EINVAL,
> > -			"missing required property rx-internal-delay-ps\n");
> >  	}
> >  
> >  	/* Read tx-internal-delay-ps and update tx_clk delay */
> > @@ -187,9 +184,6 @@ static int eic7700_dwmac_probe(struct platform_device *pdev)
> >  		dwc_priv->eth_clk_dly_param &= ~EIC7700_ETH_TX_ADJ_DELAY;
> >  		dwc_priv->eth_clk_dly_param |=
> >  				 FIELD_PREP(EIC7700_ETH_TX_ADJ_DELAY, val);
> > -	} else {
> > -		return dev_err_probe(&pdev->dev, -EINVAL,
> > -			"missing required property tx-internal-delay-ps\n");
> >  	}
> 
> I think then you need to handle RGMII, RGMII_ID, RGMII_RXID and RGMII_TXID,
> by using default delays for these (usually around 2ns), as here all delays
> will be set to 0, regardless of the RGMII mode in use.

No. By default, the MAC adds 0ns delay, and passes the phy-mode to the
PHY. It will then add the 2ns delay. It is possible to use the
tx-internal-delay-ps and rx-internal-delay-ps in the MAC to add small
tuning delays, but not the full 2ns.

https://elixir.bootlin.com/linux/v6.15/source/Documentation/devicetree/bindings/net/ethernet-controller.yaml#L287

	Andrew


From jernej.skrabec at gmail.com  Sat Jun 13 04:04:54 2026
From: jernej.skrabec at gmail.com (Jernej =?UTF-8?B?xaBrcmFiZWM=?=)
Date: Sat, 13 Jun 2026 13:04:54 +0200
Subject: [PATCH v4 3/3] ARM: dts: sunxi: add support for NetCube Systems OpenNMC
 (dobermann)
In-Reply-To: <20260606205452.2386930-4-lukas.schmid@netcube.li>
References: <20260606205452.2386930-1-lukas.schmid@netcube.li>
 <20260606205452.2386930-4-lukas.schmid@netcube.li>
Message-ID: <sTX6E5Y2SsWfe6WORpTiCA@gmail.com>

Dne sobota, 6. junij 2026 ob 22:54:43 Srednjeevropski poletni ?as je Lukas Schmid napisal(a):
> NetCube Systems OpenNMC is an open replacement for APC SmartSlot Management
> Cards. It is based on the Nagami System-on-Module. It breaks out the
> following interfaces:
> 
> - 10/100 Mbps Ethernet
> - USB Type-C OTG using a TUSB320 (usb0)
> - USB Type-C Console Port using a CH340 (uart3)
> - USB Type-A Host with internal CH334 USB-Hub (usb1)
> - MicroSD Slot with Card-Detect (mmc0)
> - WiFi/Bluetooth using the modules built-in ESP32
> - SmartSlot serial interface (uart4)
> - DS3232 RTC with CR1220 Battery Backup
> - Extension connector providing SPI,I2C,USB,CAN,UART for future use.
> 
> Signed-off-by: Lukas Schmid <lukas.schmid at netcube.li>

DT Check passes, so:
Acked-by: Jernej Skrabec <jernej.skrabec at gmail.com>

Best regards,
Jernej




From sboyd at kernel.org  Sat Jun 13 14:52:11 2026
From: sboyd at kernel.org (Stephen Boyd)
Date: Sat, 13 Jun 2026 14:52:11 -0700
Subject: [GIT PULL] canaan clk changes for 7.2
In-Reply-To: <20260602-latitude-unroasted-d88074ae2ebc@spud>
References: <20260602-latitude-unroasted-d88074ae2ebc@spud>
Message-ID: <178138753189.819343.1420937117273276704@localhost.localdomain>

Quoting Conor Dooley (2026-06-02 02:09:42)
> Hey Stephen,
> 
> Please pull the addition of a new driver for the Canaan k230 SoC.
> 
> It's been on the list for quite a while, with minimal feedback received
> on recent versions, so I figured I'd grab it and send a PR so that I can
> merge the rest of the SoC support for 7.2. It's been in linux-next for
> about two weeks with no issues that I am aware of.
> 
> Thanks,
> Conor.
> 
> 
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> 
>   Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> 
> are available in the Git repository at:
> 
>   https://git.kernel.org/pub/scm/linux/kernel/git/conor/linux.git/ clk-canaan-7.2
> 
> for you to fetch changes up to a7b7c7c6c01679efef0fd2f2ca1c5114f303e4f5:
> 
>   clk: canaan: Add clock driver for Canaan K230 (2026-05-22 17:13:10 +0100)
> 
> ----------------------------------------------------------------

Thanks. Pulled into clk-next


From sboyd at kernel.org  Sat Jun 13 14:55:19 2026
From: sboyd at kernel.org (Stephen Boyd)
Date: Sat, 13 Jun 2026 14:55:19 -0700
Subject: [GIT PULL] clk: spacemit: Updates for v7.2
In-Reply-To: <20260609052422-KYC4837748@kernel.org>
References: <20260609052422-KYC4837748@kernel.org>
Message-ID: <178138771970.819343.13341743695486361093@localhost.localdomain>

Quoting Yixun Lan (2026-06-08 22:28:09)
> From: Yixun Lan <dlan at gentoo.org>
> 
> Hi Stephen,
> 
>    Please pull SpacemiT's clock changes for v7.2
> All clock changes are related to PCIe for K3 SoC.
>    Hope this isn't too late..
> 
> Yixun Lan
> 
> The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:
> 
>   Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)
> 
> are available in the Git repository at:
> 
>   https://github.com/spacemit-com/linux spacemit-clk-for-7.2-1
> 
> for you to fetch changes up to a37c75d7b5bb7f3344b0e639b313ac5ace6244ff:
> 
>   clk: spacemit: k3: Add PCIe DBI clock (2026-06-02 07:16:59 +0000)
> 
> ----------------------------------------------------------------

Thanks. Pulled into clk-next


From anup at brainfault.org  Sat Jun 13 23:00:38 2026
From: anup at brainfault.org (Anup Patel)
Date: Sun, 14 Jun 2026 11:30:38 +0530
Subject: [PATCH v1] riscv: kvm: Use endian-specific __lelong for NACL
 shared memory
In-Reply-To: <20260608155252.4292-1-seanwascoding@gmail.com>
References: <20260608155252.4292-1-seanwascoding@gmail.com>
Message-ID: <CAAhSdy3KxyhejM5J46pXMyQwVzaZ6USY_-ZHVeuBSEyCxwZJdw@mail.gmail.com>

On Mon, Jun 8, 2026 at 9:22?PM Sean Chang <seanwascoding at gmail.com> wrote:
>
> When compiling with sparse enabled (C=2), bitwise type warnings are
> triggered in the RISC-V KVM implementation. This occurs because the
> user-space data unboxing macro '__get_user_asm' performs implicit
> casting on restricted types without forcing the compiler's compliance.
>
> Additionally, raw 'unsigned long *' pointers are used to access the
> SBI NACL shared memory, whereas the RISC-V SBI specification mandates
> that these structures must follow little-endian byte ordering.
>
> Fix these by:
> 1. Adding a '__force' cast to '__get_user_asm()' to safely suppress
>    implicit cast warnings during user-space data fetching.
> 2. Introducing the '__lelong' type macro, which dynamically resolves to
>    '__le32' or '__le64' depending on XLEN, and replacing 'unsigned long *'
>    with '__lelong *' to enforce proper compile-time endianness checks.
>
> Signed-off-by: Sean Chang <seanwascoding at gmail.com>

LGTM.

Reviewed-by: Anup Patel <anup at brainfault.org>

Queued this patch for Linux-7.2

Thanks,
Anup

> ---
>  arch/riscv/include/asm/kvm_nacl.h | 14 ++++++++------
>  arch/riscv/include/asm/uaccess.h  |  2 +-
>  arch/riscv/kvm/nacl.c             |  2 +-
>  3 files changed, 10 insertions(+), 8 deletions(-)
>
> diff --git a/arch/riscv/include/asm/kvm_nacl.h b/arch/riscv/include/asm/kvm_nacl.h
> index 4124d5e06a0f..f45407bcaa26 100644
> --- a/arch/riscv/include/asm/kvm_nacl.h
> +++ b/arch/riscv/include/asm/kvm_nacl.h
> @@ -60,9 +60,11 @@ int kvm_riscv_nacl_init(void);
>  #ifdef CONFIG_32BIT
>  #define lelong_to_cpu(__x)     le32_to_cpu(__x)
>  #define cpu_to_lelong(__x)     cpu_to_le32(__x)
> +#define __lelong                __le32
>  #else
>  #define lelong_to_cpu(__x)     le64_to_cpu(__x)
>  #define cpu_to_lelong(__x)     cpu_to_le64(__x)
> +#define __lelong                __le64
>  #endif
>
>  #define nacl_shmem()                                                   \
> @@ -70,7 +72,7 @@ int kvm_riscv_nacl_init(void);
>
>  #define nacl_scratch_read_long(__shmem, __offset)                      \
>  ({                                                                     \
> -       unsigned long *__p = (__shmem) +                                \
> +       __lelong *__p = (__shmem) +                                     \
>                              SBI_NACL_SHMEM_SCRATCH_OFFSET +            \
>                              (__offset);                                \
>         lelong_to_cpu(*__p);                                            \
> @@ -78,7 +80,7 @@ int kvm_riscv_nacl_init(void);
>
>  #define nacl_scratch_write_long(__shmem, __offset, __val)              \
>  do {                                                                   \
> -       unsigned long *__p = (__shmem) +                                \
> +       __lelong *__p = (__shmem) +                                     \
>                              SBI_NACL_SHMEM_SCRATCH_OFFSET +            \
>                              (__offset);                                \
>         *__p = cpu_to_lelong(__val);                                    \
> @@ -87,7 +89,7 @@ do {                                                                  \
>  #define nacl_scratch_write_longs(__shmem, __offset, __array, __count)  \
>  do {                                                                   \
>         unsigned int __i;                                               \
> -       unsigned long *__p = (__shmem) +                                \
> +       __lelong *__p = (__shmem) +                                     \
>                              SBI_NACL_SHMEM_SCRATCH_OFFSET +            \
>                              (__offset);                                \
>         for (__i = 0; __i < (__count); __i++)                           \
> @@ -168,7 +170,7 @@ __kvm_riscv_nacl_hfence(__shmem,                                    \
>
>  #define nacl_csr_read(__shmem, __csr)                                  \
>  ({                                                                     \
> -       unsigned long *__a = (__shmem) + SBI_NACL_SHMEM_CSR_OFFSET;     \
> +       __lelong *__a = (__shmem) + SBI_NACL_SHMEM_CSR_OFFSET;          \
>         lelong_to_cpu(__a[SBI_NACL_SHMEM_CSR_INDEX(__csr)]);            \
>  })
>
> @@ -176,7 +178,7 @@ __kvm_riscv_nacl_hfence(__shmem,                                    \
>  do {                                                                   \
>         void *__s = (__shmem);                                          \
>         unsigned int __i = SBI_NACL_SHMEM_CSR_INDEX(__csr);             \
> -       unsigned long *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET;         \
> +       __lelong *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET;              \
>         u8 *__b = (__s) + SBI_NACL_SHMEM_DBITMAP_OFFSET;                \
>         __a[__i] = cpu_to_lelong(__val);                                \
>         __b[__i >> 3] |= 1U << (__i & 0x7);                             \
> @@ -186,7 +188,7 @@ do {                                                                        \
>  ({                                                                     \
>         void *__s = (__shmem);                                          \
>         unsigned int __i = SBI_NACL_SHMEM_CSR_INDEX(__csr);             \
> -       unsigned long *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET;         \
> +       __lelong *__a = (__s) + SBI_NACL_SHMEM_CSR_OFFSET;              \
>         u8 *__b = (__s) + SBI_NACL_SHMEM_DBITMAP_OFFSET;                \
>         unsigned long __r = lelong_to_cpu(__a[__i]);                    \
>         __a[__i] = cpu_to_lelong(__val);                                \
> diff --git a/arch/riscv/include/asm/uaccess.h b/arch/riscv/include/asm/uaccess.h
> index 11c9886c3b70..5d4ec15584cf 100644
> --- a/arch/riscv/include/asm/uaccess.h
> +++ b/arch/riscv/include/asm/uaccess.h
> @@ -112,7 +112,7 @@ do {                                                                \
>                 _ASM_EXTABLE_UACCESS_ERR(1b, %l2, %0)           \
>                 : "=&r" (__tmp)                                 \
>                 : "m" (*(ptr)) : : label);                      \
> -       (x) = (__typeof__(x))(unsigned long)__tmp;              \
> +       (x) = (__force __typeof__(x))(unsigned long)__tmp;      \
>  } while (0)
>  #else /* !CONFIG_CC_HAS_ASM_GOTO_OUTPUT */
>  #define __get_user_asm(insn, x, ptr, label)                    \
> diff --git a/arch/riscv/kvm/nacl.c b/arch/riscv/kvm/nacl.c
> index 08a95ad9ada2..6f9f8963e9dd 100644
> --- a/arch/riscv/kvm/nacl.c
> +++ b/arch/riscv/kvm/nacl.c
> @@ -20,7 +20,7 @@ void __kvm_riscv_nacl_hfence(void *shmem,
>                              unsigned long page_count)
>  {
>         int i, ent = -1, try_count = 5;
> -       unsigned long *entp;
> +       __lelong *entp;
>
>  again:
>         for (i = 0; i < SBI_NACL_SHMEM_HFENCE_ENTRY_MAX; i++) {
> --
> 2.43.0
>


From legoll at online.fr  Sat Jun 13 23:50:13 2026
From: legoll at online.fr (Vincent Legoll)
Date: Sun, 14 Jun 2026 08:50:13 +0200
Subject: [PATCH] riscv: dts: spacemit: orangepi-rv2: Add cpu scaling for K1,
 SoC
In-Reply-To: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
Message-ID: <f031e13e-d9f5-414a-b90e-a3d5a60b8d05@online.fr>

[RESEND] as I cannot see yesterday's


Hello,



I tested (on OrangePi RV2) the attached patch applied over

spacemit/for-next + Shuwei Wu's V3 series.


This is a copy/paste of Shuwei Wu's work, so I don't know

if I can submit this with my SoB or if it should be done

differently, please advise.


Anyways, you can add my:

Tested-by: Vincent Legoll <vincent.legoll at gmail.com> # OrangePi-RV2


To the relevant patches from your series, if that's useful,

because it looks like it is working properly:


On Void linux (musl libc):


uname -a
Linux opirv2 7.1.0-rc1-00043-gb860bca13be4 #14 SMP PREEMPT Sat Jun 13 
11:02:13 CEST 2026 riscv64 GNU/Linux

awk --version | head -1
GNU Awk 5.3.2, API 4.0

echo userspace > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor

echo 1600000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real? ? 0m0.300s
user? ? 0m0.299s
sys? ? ?0m0.001s

echo 1228800 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real? ? 0m0.432s
user? ? 0m0.429s
sys? ? ?0m0.004s

echo 1000000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real? ? 0m0.476s
user? ? 0m0.476s
sys? ? ?0m0.001s

echo 819000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real? ? 0m0.582s
user? ? 0m0.581s
sys? ? ?0m0.001s

echo 614400 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real? ? 0m0.778s
user? ? 0m0.773s
sys? ? ?0m0.005s

-- 

Vincent Legoll

-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-riscv-dts-spacemit-orangepi-rv2-Add-cpu-scaling-for-.patch
Type: text/x-patch
Size: 1660 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260614/ddbba5d5/attachment.bin>

From anup at brainfault.org  Sun Jun 14 02:49:53 2026
From: anup at brainfault.org (Anup Patel)
Date: Sun, 14 Jun 2026 15:19:53 +0530
Subject: [GIT PULL] KVM/riscv changes for 7.2
Message-ID: <CAAhSdy0WTa-jDxg0cQxwqfGM+Det+WxM-ELV3F2ktrcbw8g7Bw@mail.gmail.com>

Hi Paolo,

We have the following KVM RISC-V changes for 7.2:
1) Batch G-stage TLB flushes for GPA range based page table updates
2) Convert HGEI line management to fully per-HART
3) Speed up dirty logging write faults using MMU rwlock and atomic
    PTE updates for permission-only changes
4) Use flexible array for APLIC IRQ state
5) FWFT fixes for missing CSR dirty marking and stale feature
    exposure to Guest/VM
6) Fix logging enable check on a memslot by using
    kvm_slot_dirty_track_enabled()
7) Fixes to avoid skipping valid pages in kvm_riscv_gstage_wp_range()
    and kvm_riscv_gstage_unmap_range()

Please pull.

Regards,
Anup

The following changes since commit e7ae89a0c97ce2b68b0983cd01eda67cf373517d:

  Linux 7.1-rc5 (2026-05-24 13:48:06 -0700)

are available in the Git repository at:

  https://github.com/kvm-riscv/linux.git tags/kvm-riscv-7.2-1

for you to fetch changes up to 52738352a6f29279e15285fcb7b50241ef867e27:

  riscv: kvm: Use endian-specific __lelong for NACL shared memory
(2026-06-14 11:09:41 +0530)

----------------------------------------------------------------
KVM/riscv changes for 7.2

- Batch G-stage TLB flushes for GPA range based page table updates
- Convert HGEI line management to fully per-HART
- Fix missing CSR dirty marking when FWFT state updated via ONE_REG
- Fix stale FWFT feature exposure to Guest/VM
- Speed up dirty logging write faults using MMU rwlock and atomic
  PTE updates using cmpxchg() for permission-only changes
- Use flexible array for APLIC IRQ state
- Use kvm_slot_dirty_track_enabled() for logging enable check on
  a memslot
- Avoid skipping valid pages in kvm_riscv_gstage_wp_range()
- Avoid skipping valid pages in kvm_riscv_gstage_unmap_range()
- Use endian-specific __lelong for NACL shared memory

----------------------------------------------------------------
Guo Ren (Alibaba DAMO Academy) (2):
      irqchip/riscv-imsic: Add nr_guest_files in per-HART local config
      RISC-V: KVM: AIA: Make HGEI number management fully per-CPU

Inochi Amaoto (1):
      RISC-V: KVM: Enhance the logging check for mmu mapping

Jiakai Xu (2):
      RISC-V: KVM: Document a TOCTOU race in SBI system suspend handler
      RISC-V: KVM: Fix NULL pointer dereference in AIA IMSIC functions

Jinyu Tang (8):
      RISC-V: KVM: Batch stage-2 TLB flushes
      KVM: riscv: Rely on common MMU notifier locking
      KVM: riscv: Use an rwlock for mmu_lock
      KVM: riscv: Add a G-stage PTE cmpxchg helper
      KVM: riscv: Update G-stage PTE permissions atomically
      KVM: riscv: Fast-path dirty logging write faults
      KVM: riscv: Check hugetlb block mappings against memslot bounds
      KVM: selftests: Add a hugetlb memslot alignment test mode

Mayuresh Chitale (1):
      RISC-V: KVM: Fix ebreak self test failure

Qiang Ma (1):
      RISC-V: KVM: Fix timer state restore

Rosen Penev (1):
      RISC-V: KVM: Use flexible array for APLIC IRQ state

Sean Chang (1):
      riscv: kvm: Use endian-specific __lelong for NACL shared memory

Wu Fei (2):
      RISC-V: KVM: Fix skip of valid pages in kvm_riscv_gstage_wp_range
      RISC-V: KVM: Fix skip of valid pages in kvm_riscv_gstage_unmap_range

Yong-Xuan Wang (5):
      KVM: RISC-V: SBI FWFT: Mark vCPU CSRs dirty after setting feature value
      KVM: RISC-V: SBI FWFT: Add optional init() callback for hardware probing
      KVM: RISC-V: SBI FWFT: Fix stale feature exposure after runtime
extension changes
      KVM: riscv: selftests: Refactor ISA and SBI extension sublist macros
      KVM: riscv: selftests: Split SBI FWFT into separate
feature-specific sublists

 arch/riscv/include/asm/kvm_aia.h                  |   2 +-
 arch/riscv/include/asm/kvm_gstage.h               |  10 +-
 arch/riscv/include/asm/kvm_host.h                 |   2 +
 arch/riscv/include/asm/kvm_nacl.h                 |  14 +-
 arch/riscv/include/asm/uaccess.h                  |   2 +-
 arch/riscv/kvm/aia.c                              |  88 +++++----
 arch/riscv/kvm/aia_aplic.c                        |  15 +-
 arch/riscv/kvm/aia_device.c                       |   4 +-
 arch/riscv/kvm/aia_imsic.c                        |   9 +
 arch/riscv/kvm/gstage.c                           | 100 ++++++----
 arch/riscv/kvm/main.c                             |   8 +-
 arch/riscv/kvm/mmu.c                              | 211 ++++++++++++++++++----
 arch/riscv/kvm/nacl.c                             |   2 +-
 arch/riscv/kvm/vcpu.c                             |   1 +
 arch/riscv/kvm/vcpu_sbi_fwft.c                    |  44 ++++-
 arch/riscv/kvm/vcpu_sbi_system.c                  |  14 ++
 arch/riscv/kvm/vcpu_timer.c                       |   2 +-
 drivers/irqchip/irq-riscv-imsic-state.c           |   9 +-
 include/linux/irqchip/riscv-imsic.h               |   5 +-
 tools/testing/selftests/kvm/kvm_page_table_test.c |  28 ++-
 tools/testing/selftests/kvm/riscv/get-reg-list.c  | 138 ++++++++------
 21 files changed, 499 insertions(+), 209 deletions(-)


From a.heider at gmail.com  Sun Jun 14 05:28:11 2026
From: a.heider at gmail.com (Andre Heider)
Date: Sun, 14 Jun 2026 14:28:11 +0200
Subject: [PATCH] riscv: dts: spacemit: k1-musepi-pro: add cpu scaling
In-Reply-To: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
Message-ID: <20260614122812.2287506-1-a.heider@gmail.com>

Enable CPU DVFS by including the OPP table and wiring the CPU nodes to the
CPU regulator supply.

Signed-off-by: Andre Heider <a.heider at gmail.com>
---
 .../riscv/boot/dts/spacemit/k1-musepi-pro.dts | 35 ++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/boot/dts/spacemit/k1-musepi-pro.dts b/arch/riscv/boot/dts/spacemit/k1-musepi-pro.dts
index 0d809e4ad3b1..1b425011f123 100644
--- a/arch/riscv/boot/dts/spacemit/k1-musepi-pro.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-musepi-pro.dts
@@ -9,6 +9,7 @@
 
 #include "k1.dtsi"
 #include "k1-pinctrl.dtsi"
+#include "k1-opp.dtsi"
 
 / {
 	model = "SpacemiT MusePi Pro";
@@ -99,6 +100,38 @@ &combo_phy {
 	status = "okay";
 };
 
+&cpu_0 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_1 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_2 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_3 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_4 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_5 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_6 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_7 {
+	cpu-supply = <&buck1_0v9>;
+};
+
 &eth0 {
 	phy-handle = <&rgmii0>;
 	phy-mode = "rgmii-id";
@@ -178,7 +211,7 @@ pmic at 41 {
 		dldoin2-supply = <&buck5>;
 
 		regulators {
-			buck1 {
+			buck1_0v9: buck1 {
 				regulator-min-microvolt = <500000>;
 				regulator-max-microvolt = <3450000>;
 				regulator-ramp-delay = <5000>;
-- 
2.53.0



From dlan at kernel.org  Sun Jun 14 17:41:08 2026
From: dlan at kernel.org (Yixun Lan)
Date: Mon, 15 Jun 2026 00:41:08 +0000
Subject: [PATCH] riscv: dts: spacemit: orangepi-rv2: Add cpu scaling for
 K1, SoC
In-Reply-To: <f031e13e-d9f5-414a-b90e-a3d5a60b8d05@online.fr>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
 <f031e13e-d9f5-414a-b90e-a3d5a60b8d05@online.fr>
Message-ID: <20260615004108-GKA1002079@kernel.org>

Hi Vincent,

 Please send the patch directly instead of attached file, it's more
easy for people to review and apply, suggest to use b4, or
 "git send-email" (old way)


On 08:50 Sun 14 Jun     , Vincent Legoll wrote:
> [RESEND] as I cannot see yesterday's
> 
> 
> Hello,
> 
> 
> 
> I tested (on OrangePi RV2) the attached patch applied over
> 
> spacemit/for-next + Shuwei Wu's V3 series.
> 
> 
> This is a copy/paste of Shuwei Wu's work, so I don't know
> 
> if I can submit this with my SoB or if it should be done
> 
It's ok to add your SoB while adding support for new board

> differently, please advise.
> 
> 
> Anyways, you can add my:
> 
> Tested-by: Vincent Legoll <vincent.legoll at gmail.com> # OrangePi-RV2
> 
> 
> To the relevant patches from your series, if that's useful,
> 
> because it looks like it is working properly:
> 
> 
> On Void linux (musl libc):
> 
> 
> uname -a
> Linux opirv2 7.1.0-rc1-00043-gb860bca13be4 #14 SMP PREEMPT Sat Jun 13 
> 11:02:13 CEST 2026 riscv64 GNU/Linux
> 
> awk --version | head -1
> GNU Awk 5.3.2, API 4.0
> 
> echo userspace > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor
> 
> echo 1600000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
> time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
> real? ? 0m0.300s
> user? ? 0m0.299s
> sys? ? ?0m0.001s
> 
> echo 1228800 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
> time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
> real? ? 0m0.432s
> user? ? 0m0.429s
> sys? ? ?0m0.004s
> 
> echo 1000000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
> time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
> real? ? 0m0.476s
> user? ? 0m0.476s
> sys? ? ?0m0.001s
> 
> echo 819000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
> time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
> real? ? 0m0.582s
> user? ? 0m0.581s
> sys? ? ?0m0.001s
> 
> echo 614400 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
> time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
> real? ? 0m0.778s
> user? ? 0m0.773s
> sys? ? ?0m0.005s
> 
> -- 
> 
> Vincent Legoll
> 

> From 9924789655ae5f4f98e7a5cdc3df3f34e7bfb659 Mon Sep 17 00:00:00 2001
> From: Vincent Legoll <vincent.legoll at gmail.com>
> Date: Sat, 13 Jun 2026 10:49:34 +0200
> Subject: [PATCH] riscv: dts: spacemit: orangepi-rv2: Add cpu scaling for K1
>  SoC
> 
> Enable CPU DVFS on OrangePi RV2
> 
..
> This is a copy/paste from Shuwei Wu's BPI-F3 DTS modifications
> 
It's quite common that people do copy/paste for additional board
support, no need to mention it in commit message which I think it
isn't really useful


> Signed-off-by: Vincent Legoll <vincent.legoll at gmail.com>
> ---
>  .../boot/dts/spacemit/k1-orangepi-rv2.dts     | 35 ++++++++++++++++++-
>  1 file changed, 34 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
> index 7c49bce427f3..62d25f579af6 100644
> --- a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
> +++ b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
> @@ -8,6 +8,7 @@
>  
>  #include "k1.dtsi"
>  #include "k1-pinctrl.dtsi"
> +#include "k1-opp.dtsi"
keep alphabet sorted
>  
>  / {
>  	model = "OrangePi RV2";
> @@ -80,6 +81,38 @@ &combo_phy {
>  	status = "okay";
>  };
>  
> +&cpu_0 {
> +       cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_1 {
> +       cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_2 {
> +       cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_3 {
> +       cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_4 {
> +       cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_5 {
> +       cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_6 {
> +       cpu-supply = <&buck1_0v9>;
> +};
> +
> +&cpu_7 {
> +       cpu-supply = <&buck1_0v9>;
> +};
> +
>  &emmc {
>  	bus-width = <8>;
>  	mmc-hs400-1_8v;
> @@ -162,7 +195,7 @@ pmic at 41 {
>  		dldoin2-supply = <&buck5>;
>  
>  		regulators {
> -			buck1 {
> +			buck1_0v9: buck1 {
>  				regulator-min-microvolt = <500000>;
>  				regulator-max-microvolt = <3450000>;
>  				regulator-ramp-delay = <5000>;
> -- 
> 2.54.0
> 


-- 
Yixun Lan (dlan)


From dlan at kernel.org  Sun Jun 14 18:15:16 2026
From: dlan at kernel.org (Yixun Lan)
Date: Mon, 15 Jun 2026 01:15:16 +0000
Subject: [PATCH v3] riscv: dts: spacemit: Use symbolic PDMA request
 numbers on K1
In-Reply-To: <20260611-b4-k1-pdma-req-macros-v3-1-ae8416052571@gmail.com>
References: <20260611-b4-k1-pdma-req-macros-v3-1-ae8416052571@gmail.com>
Message-ID: <20260615011516-GKB1002079@kernel.org>

Hi Guodong,
 The patch itself looks good to me, only few minor comments

On 09:17 Thu 11 Jun     , Guodong Xu wrote:
> Add a local DTS header, k1-pdma.h, that gives symbolic names to the K1
> PDMA request numbers. These request numbers are hardware-fixed; their
> allocation can be found in K1 manual.
> 
..
> Replace the hard-coded numbers in the SPI3 "dmas" property with the
> K1_PDMA_SPI3_RX/TX macros.
> 
As it's too obvious that people can tell from the diff, then I feel it's
unnecessary to repeat in commit message..

> Signed-off-by: Guodong Xu <docular.xu at gmail.com>
> ---
> Add a local DTS header naming the K1 PDMA request lines and convert the
> current user (the K1 SPI3 node) to the new K1_PDMA_* macros.
..
> The request
> numbers come from the SpacemiT K1 User Manual [1], Chapter 9.4.3 DMA
> Connectivity & Assignments.
> 
I'd suggest to put above into commit message, as more detailed description.
Here is my attempt to slightly reconstruct the commit message:

The PDMA request numbers (DRQ) are fixed values specific to the SoC from a
hardware perspective. The detailed definition can be found in K1 User Manual,
Chapter 9.4.3 DMA Connectivity & Assignments. Add a DTS header file to define
the symbolic names for the DRQs of non-secure DMA peripherals.

> [1]: https://www.spacemit.com/community/document/info?lang=en&nodepath=hardware/key_stone/k1/k1_docs/k1_usermanual/9.Top_System.md
> 
> Changes in v3:
> - Move the request-number macros from include/dt-bindings/dma/ to a local
>   DTS header arch/riscv/boot/dts/spacemit/k1-pdma.h (Conor).
> - Squash the header and its user into a single patch.
> - Link to v2: https://patch.msgid.link/20260609-b4-k1-pdma-req-macros-v2-0-5d5d7b997b54 at gmail.com
> 
> Changes in v2:
> - Drop the #dma-cells description change in spacemit,k1-pdma.yaml; the request
>   numbers are hardware-fixed and unused by the driver (Conor)
> - Link to v1: https://patch.msgid.link/20260607-b4-k1-pdma-req-macros-v1-0-5b2a3955007c at gmail.com
> 
> BR,
> Guodong Xu
> ---
>  arch/riscv/boot/dts/spacemit/k1-pdma.h | 56 ++++++++++++++++++++++++++++++++++
>  arch/riscv/boot/dts/spacemit/k1.dtsi   |  4 ++-
>  2 files changed, 59 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/riscv/boot/dts/spacemit/k1-pdma.h b/arch/riscv/boot/dts/spacemit/k1-pdma.h
> new file mode 100644
> index 0000000000000..65112d5847add
> --- /dev/null
> +++ b/arch/riscv/boot/dts/spacemit/k1-pdma.h
> @@ -0,0 +1,56 @@
> +/* SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) */
> +/*
> + * This header provides DMA request number for non-secure peripherals of
> + * SpacemiT K1 PDMA.
slightly less redundant,
  DMA request number (DRQ) defintion for non-secure peripherals

> + *
> + * Copyright (c) 2026 Guodong Xu <docular.xu at gmail.com>
> + */
> +
> +#ifndef _DTS_SPACEMIT_K1_PDMA_H
> +#define _DTS_SPACEMIT_K1_PDMA_H
> +
> +#define K1_PDMA_UART0_TX	3
> +#define K1_PDMA_UART0_RX	4
> +#define K1_PDMA_UART2_TX	5
> +#define K1_PDMA_UART2_RX	6
> +#define K1_PDMA_UART3_TX	7
> +#define K1_PDMA_UART3_RX	8
> +#define K1_PDMA_UART4_TX	9
> +#define K1_PDMA_UART4_RX	10
> +#define K1_PDMA_I2C0_TX		11
> +#define K1_PDMA_I2C0_RX		12
> +#define K1_PDMA_I2C1_TX		13
> +#define K1_PDMA_I2C1_RX		14
> +#define K1_PDMA_I2C2_TX		15
> +#define K1_PDMA_I2C2_RX		16
> +#define K1_PDMA_I2C4_TX		17
> +#define K1_PDMA_I2C4_RX		18
> +#define K1_PDMA_SPI3_TX		19
> +#define K1_PDMA_SPI3_RX		20
> +#define K1_PDMA_I2S0_TX		21
> +#define K1_PDMA_I2S0_RX		22
> +#define K1_PDMA_I2S1_TX		23
> +#define K1_PDMA_I2S1_RX		24
> +#define K1_PDMA_UART5_TX	25
> +#define K1_PDMA_UART5_RX	26
> +#define K1_PDMA_UART6_TX	27
> +#define K1_PDMA_UART6_RX	28
> +#define K1_PDMA_UART7_TX	29
> +#define K1_PDMA_UART7_RX	30
> +#define K1_PDMA_UART8_TX	31
> +#define K1_PDMA_UART8_RX	32
> +#define K1_PDMA_UART9_TX	33
> +#define K1_PDMA_UART9_RX	34
> +#define K1_PDMA_I2C5_TX		35
> +#define K1_PDMA_I2C5_RX		36
> +#define K1_PDMA_I2C6_TX		37
> +#define K1_PDMA_I2C6_RX		38
> +#define K1_PDMA_I2C7_TX		39
> +#define K1_PDMA_I2C7_RX		40
> +#define K1_PDMA_I2C8_TX		41
> +#define K1_PDMA_I2C8_RX		42
> +#define K1_PDMA_CAN0_RX		43
> +#define K1_PDMA_QSPI_RX		44
> +#define K1_PDMA_QSPI_TX		45
> +
> +#endif /* _DTS_SPACEMIT_K1_PDMA_H */
> diff --git a/arch/riscv/boot/dts/spacemit/k1.dtsi b/arch/riscv/boot/dts/spacemit/k1.dtsi
> index 08a0f28d011fe..7d414e15d2cc2 100644
> --- a/arch/riscv/boot/dts/spacemit/k1.dtsi
> +++ b/arch/riscv/boot/dts/spacemit/k1.dtsi
> @@ -6,6 +6,8 @@
>  #include <dt-bindings/clock/spacemit,k1-syscon.h>
>  #include <dt-bindings/phy/phy.h>
>  
> +#include "k1-pdma.h"
> +
>  /dts-v1/;
>  / {
>  	#address-cells = <2>;
> @@ -1094,7 +1096,7 @@ spi3: spi at d401c000 {
>  				clock-names = "core", "bus";
>  				resets = <&syscon_apbc RESET_SSP3>;
>  				interrupts = <55>;
> -				dmas = <&pdma 20>, <&pdma 19>;
> +				dmas = <&pdma K1_PDMA_SPI3_RX>, <&pdma K1_PDMA_SPI3_TX>;
>  				dma-names = "rx", "tx";
>  				status = "disabled";
>  			};
> 
> ---
> base-commit: 793cc54475b49b5b558902b5c13e4bfe66530a50
> change-id: 20260607-b4-k1-pdma-req-macros-8d276d0126df
> 
> Best regards,
> --  
> Guodong Xu <docular.xu at gmail.com>
> 

-- 
Yixun Lan (dlan)


From dlan at kernel.org  Sun Jun 14 18:20:29 2026
From: dlan at kernel.org (Yixun Lan)
Date: Mon, 15 Jun 2026 01:20:29 +0000
Subject: [PATCH v4 10/16] riscv: dts: spacemit: k3: Add Zic64b ISA
 extension
In-Reply-To: <20260611-rva23u64-hwprobe-v2-v4-10-3f01a2449488@gmail.com>
References: <20260611-rva23u64-hwprobe-v2-v4-0-3f01a2449488@gmail.com>
 <20260611-rva23u64-hwprobe-v2-v4-10-3f01a2449488@gmail.com>
Message-ID: <20260615012029-GKA1003249@kernel.org>

Hi Guodong,

On 16:12 Thu 11 Jun     , Guodong Xu wrote:
> The K3 X100 cores have 64-byte cache blocks, already described by their
> cbom/cbop/cboz-block-size of 64, so they implement Zic64b, a mandatory
> RVA23 extension.  Declare it in each core's riscv,isa-extensions.
> 
> Signed-off-by: Guodong Xu <docular.xu at gmail.com>

Reviewed-by: Yixun Lan <dlan at kernel.org>

> ---
> v4: No change.
> v3: New patch.
> ---
>  arch/riscv/boot/dts/spacemit/k3.dtsi | 48 ++++++++++++++++++------------------
>  1 file changed, 24 insertions(+), 24 deletions(-)
> 
> diff --git a/arch/riscv/boot/dts/spacemit/k3.dtsi b/arch/riscv/boot/dts/spacemit/k3.dtsi
> index 4ac457399b583..b5aa983f0bfa1 100644
> --- a/arch/riscv/boot/dts/spacemit/k3.dtsi
> +++ b/arch/riscv/boot/dts/spacemit/k3.dtsi
> @@ -35,9 +35,9 @@ cpu_0: cpu at 0 {
>  					       "svinval", "svnapot", "svpbmt", "za64rs",
>  					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
>  					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
> -					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
> -					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
> -					       "zicond", "zicsr", "zifencei", "zihintntl",
> +					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
> +					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
> +					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
>  					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
>  					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
>  					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
> @@ -76,9 +76,9 @@ cpu_1: cpu at 1 {
>  					       "svinval", "svnapot", "svpbmt", "za64rs",
>  					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
>  					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
> -					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
> -					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
> -					       "zicond", "zicsr", "zifencei", "zihintntl",
> +					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
> +					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
> +					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
>  					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
>  					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
>  					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
> @@ -117,9 +117,9 @@ cpu_2: cpu at 2 {
>  					       "svinval", "svnapot", "svpbmt", "za64rs",
>  					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
>  					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
> -					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
> -					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
> -					       "zicond", "zicsr", "zifencei", "zihintntl",
> +					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
> +					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
> +					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
>  					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
>  					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
>  					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
> @@ -158,9 +158,9 @@ cpu_3: cpu at 3 {
>  					       "svinval", "svnapot", "svpbmt", "za64rs",
>  					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
>  					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
> -					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
> -					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
> -					       "zicond", "zicsr", "zifencei", "zihintntl",
> +					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
> +					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
> +					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
>  					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
>  					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
>  					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
> @@ -199,9 +199,9 @@ cpu_4: cpu at 4 {
>  					       "svinval", "svnapot", "svpbmt", "za64rs",
>  					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
>  					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
> -					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
> -					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
> -					       "zicond", "zicsr", "zifencei", "zihintntl",
> +					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
> +					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
> +					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
>  					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
>  					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
>  					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
> @@ -240,9 +240,9 @@ cpu_5: cpu at 5 {
>  					       "svinval", "svnapot", "svpbmt", "za64rs",
>  					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
>  					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
> -					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
> -					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
> -					       "zicond", "zicsr", "zifencei", "zihintntl",
> +					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
> +					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
> +					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
>  					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
>  					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
>  					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
> @@ -281,9 +281,9 @@ cpu_6: cpu at 6 {
>  					       "svinval", "svnapot", "svpbmt", "za64rs",
>  					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
>  					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
> -					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
> -					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
> -					       "zicond", "zicsr", "zifencei", "zihintntl",
> +					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
> +					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
> +					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
>  					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
>  					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
>  					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
> @@ -322,9 +322,9 @@ cpu_7: cpu at 7 {
>  					       "svinval", "svnapot", "svpbmt", "za64rs",
>  					       "zawrs", "zba", "zbb", "zbc", "zbs", "zca",
>  					       "zcb", "zcd", "zcmop", "zfa", "zfbfmin",
> -					       "zfh", "zfhmin", "zicbom", "zicbop", "zicboz",
> -					       "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr",
> -					       "zicond", "zicsr", "zifencei", "zihintntl",
> +					       "zfh", "zfhmin", "zic64b", "zicbom", "zicbop",
> +					       "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse",
> +					       "zicntr", "zicond", "zicsr", "zifencei", "zihintntl",
>  					       "zihintpause", "zihpm", "zimop", "zkt", "zvbb",
>  					       "zvbc", "zvfbfmin", "zvfbfwma", "zvfh",
>  					       "zvfhmin", "zvkb", "zvkg", "zvkn", "zvknc",
> 
> -- 
> 2.43.0
> 

-- 
Yixun Lan (dlan)


From troy.mitchell at linux.spacemit.com  Sun Jun 14 19:53:25 2026
From: troy.mitchell at linux.spacemit.com (Troy Mitchell)
Date: Mon, 15 Jun 2026 10:53:25 +0800
Subject: [PATCH] dmaengine: mmp_pdma: fix wrong extended DRCMR base for
 SpacemiT K3
Message-ID: <20260615-k3-pdma-fix-drcmr-base-v1-1-ee1af124199f@linux.spacemit.com>

K3 PDMA shares the same DRCMR layout as K1, where the extended DRCMR
base address is 0x1100. Commit 6587b8661a0b ("dmaengine: mmp_pdma: add
SpacemiT K3 support") incorrectly defined DRCMR_EXT_BASE_K3 as 0x1000,
causing all DRCMR accesses for channels >= 64 to be off by 0x100.

Drop the bogus DRCMR_EXT_BASE_K3 macro and reuse DRCMR_EXT_BASE_DEFAULT
for the K3 ops.

Fixes: 6587b8661a0b ("dmaengine: mmp_pdma: add SpacemiT K3 support")
Signed-off-by: Troy Mitchell <troy.mitchell at linux.spacemit.com>
---
This is a minimal fix for the wrong DRCMR_EXT_BASE_K3 value introduced
by commit 6587b8661a0b ("dmaengine: mmp_pdma: add SpacemiT K3 support").
K3 PDMA shares the same extended DRCMR base (0x1100) as K1, so the K3
ops now reuses DRCMR_EXT_BASE_DEFAULT.

I deliberately kept the per-ops drcmr_ext_base field and the
DRCMR_EXT_BASE_DEFAULT macro to preserve the extensibility that was
introduced together with the helper refactor, in case a future PDMA
variant ends up using a different extended base. If reviewers prefer
to drop this abstraction entirely and collapse it back to a single
constant now that all known users share the same value, I am happy to
send a v2 that removes the drcmr_ext_base ops field as a cleanup.
---
 drivers/dma/mmp_pdma.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index 386e85cd4882..78e3e07e681d 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -52,7 +52,6 @@
 #define DCSR_EORINTR	BIT(9)	/* The end of Receive */
 
 #define DRCMR_BASE		0x0100
-#define DRCMR_EXT_BASE_K3	0x1000
 #define DRCMR_EXT_BASE_DEFAULT	0x1100
 #define DRCMR_REQ_LIMIT		64
 #define DRCMR_MAPVLD	BIT(7)	/* Map Valid (read / write) */
@@ -1219,7 +1218,7 @@ static const struct mmp_pdma_ops spacemit_k3_pdma_ops = {
 	.get_desc_dst_addr = get_desc_dst_addr_64,
 	.run_bits = (DCSR_RUN | DCSR_LPAEEN | DCSR_EORIRQEN | DCSR_EORSTOPEN),
 	.dma_width = 64,
-	.drcmr_ext_base = DRCMR_EXT_BASE_K3,
+	.drcmr_ext_base = DRCMR_EXT_BASE_DEFAULT,
 };
 
 static const struct of_device_id mmp_pdma_dt_ids[] = {

---
base-commit: c425609d6ac4012c8bbf01ec2e10e801b1923a7b
change-id: 20260615-k3-pdma-fix-drcmr-base-326536770427

Best regards,
--  
Troy Mitchell <troy.mitchell at linux.spacemit.com>



From chenwandun1 at gmail.com  Sun Jun 14 20:33:34 2026
From: chenwandun1 at gmail.com (Wandun)
Date: Mon, 15 Jun 2026 11:33:34 +0800
Subject: [PATCH v3 05/11] of: reserved_mem: split
 alloc_reserved_mem_array() from fdt_scan_reserved_mem_late()
In-Reply-To: <20260612144122.GA974326-robh@kernel.org>
References: <20260527032917.3385849-1-chenwandun1@gmail.com>
 <20260527032917.3385849-6-chenwandun1@gmail.com>
 <20260612144122.GA974326-robh@kernel.org>
Message-ID: <894d7c33-8e14-4ba5-b774-14062ece39f2@gmail.com>



On 6/12/26 22:41, Rob Herring wrote:
> On Wed, May 27, 2026 at 11:29:11AM +0800, Wandun Chen wrote:
>> From: Wandun Chen <chenwandun at lixiang.com>
>>
>> Prepare for storing /memreserve/ entries in the reserved_mem array.
>> alloc_reserved_mem_array is skipped if the device tree lacks a
>> /reserved-memory node, pointer 'reserved_mem' continues to reference
>> the reserved_mem_array which lives in __initdata, storing
>> /memreserve/ entries into reserved_mem_array would result in metadata
>> loss, and an out-of-bounds memory access will occur if the device
>> tree contains more than MAX_RESERVED_REGIONS /memreserve/ entries.
>>
>> So split alloc_reserved_mem_array() from fdt_scan_reserved_mem_late(),
>> and call alloc_reserved_mem_array() whether or not there is a
>> /reserved-memory node.
>>
>> No functional change.
>> The actual /memreserve/ population is added in a follow-up patch.
>>
>> Signed-off-by: Wandun Chen <chenwandun at lixiang.com>
>> ---
>>  drivers/of/fdt.c             | 7 +++++--
>>  drivers/of/of_private.h      | 1 +
>>  drivers/of/of_reserved_mem.c | 6 +-----
>>  3 files changed, 7 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
>> index 82f7327c59ea..83a2a474831e 100644
>> --- a/drivers/of/fdt.c
>> +++ b/drivers/of/fdt.c
>> @@ -1284,8 +1284,11 @@ void __init unflatten_device_tree(void)
>>  {
>>  	void *fdt = initial_boot_params;
>>  
>> -	/* Save the statically-placed regions in the reserved_mem array */
>> -	fdt_scan_reserved_mem_late();
>> +	/* Attempt dynamic allocation of a new reserved_mem array */
>> +	if (fdt && alloc_reserved_mem_array()) {
>> +		/* Save the statically-placed regions in the reserved_mem array */
>> +		fdt_scan_reserved_mem_late();
> 
> Can we make this just:
> 
> alloc_reserved_mem_array();
> fdt_scan_reserved_mem_late();
> 
> We already check !fdt in fdt_scan_reserved_mem_late().

Thanks for you review, Rob.

The reason I kept the fdt check is that total_reserved_mem_cnt is wrong
when fdt is NULL, early_init_fdt_scan_reserved_mem() returns early in
that case, so fdt_scan_reserved_mem() never runs, and
total_reserved_mem_cnt stays at MAX_RESERVED_REGIONS. Calling
alloc_reserved_mem_array() unconditionally would allocate unnecessarily
memory.

A better fix might be to make total_reserved_mem_cnt always correct, add
a !fdt check at the top of fdt_scan_reserved_mem() that sets
total_reserved_mem_cnt to 0, and let early_init_fdt_scan_reserved_mem()
call it even when initial_boot_params is NULL. Then
alloc_reserved_mem_array() could naturally skip allcation when that
count is 0, and we can drop the outer fdt guard.


There is still separate UAF issue (fixed in patch3) if we don't check
the return value of alloc_reserved_mem_array().


With the fdt_scan_reserved_mem() fix for total_reserved_mem_cnt, the
call site in unflatten_device_tree() becomes:

if (alloc_reserved_mem_array()) {
        fdt_scan_reserved_mem_late();
}

How does that sound?


Best regards,
Wandun

> 
> Rob



From viresh.kumar at linaro.org  Sun Jun 14 22:07:17 2026
From: viresh.kumar at linaro.org (Viresh Kumar)
Date: Mon, 15 Jun 2026 10:37:17 +0530
Subject: [PATCH v3 0/2] cpufreq: spacemit: Add cpufreq support for K1 SoC
In-Reply-To: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
Message-ID: <lt7l6hvia6hahvizr6qwirgnhzjqdfn4edzt7fakqxbhkcmaxr@x6d5h4i55edw>

On 12-06-26, 17:51, Shuwei Wu wrote:
> Changes in v3:
> - Add a K1-specific cpufreq driver for the shared-rail, dual-clock topology

Why ?

> - Use one shared CPU OPP table and one cpufreq policy for all CPUs
> - Link to v2: https://lore.kernel.org/r/20260410-shadow-deps-v2-0-4e16b8c0f60e at mailbox.org

-- 
viresh


From viresh.kumar at linaro.org  Sun Jun 14 22:24:38 2026
From: viresh.kumar at linaro.org (Viresh Kumar)
Date: Mon, 15 Jun 2026 10:54:38 +0530
Subject: [PATCH v3 1/2] cpufreq: spacemit: Add K1 cpufreq driver
In-Reply-To: <20260612-shadow-deps-v3-1-2f3ba88611ff@mailbox.org>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
 <20260612-shadow-deps-v3-1-2f3ba88611ff@mailbox.org>
Message-ID: <bd4s2icqgusnuujvrpoag4cniy3g2e4bumecqxt5yffl77aqpq@kxg4dj4c2wk3>

On 12-06-26, 17:51, Shuwei Wu wrote:
> K1 has two CPU cluster clocks but one shared CPU voltage rail. Use one
> cpufreq policy for all CPUs, let the OPP core handle the shared regulator
> and the cluster0 clock, and update the cluster1 clock explicitly.

If the clusters can do DVFS individually (as they have separate clocks), this
should be represented as two separate policies. Isn't it ?

-- 
viresh


From shuwei.wu at mailbox.org  Sun Jun 14 23:12:06 2026
From: shuwei.wu at mailbox.org (Shuwei Wu)
Date: Mon, 15 Jun 2026 14:12:06 +0800
Subject: [PATCH v3 1/2] cpufreq: spacemit: Add K1 cpufreq driver
In-Reply-To: <bd4s2icqgusnuujvrpoag4cniy3g2e4bumecqxt5yffl77aqpq@kxg4dj4c2wk3>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
 <20260612-shadow-deps-v3-1-2f3ba88611ff@mailbox.org>
 <bd4s2icqgusnuujvrpoag4cniy3g2e4bumecqxt5yffl77aqpq@kxg4dj4c2wk3>
Message-ID: <DJ9EFPG561VZ.1WGRYYHJ2W9J9@mailbox.org>

Hi Viresh,

Thanks for your reply.

On Mon Jun 15, 2026 at 1:24 PM CST, Viresh Kumar wrote:
> On 12-06-26, 17:51, Shuwei Wu wrote:
>> K1 has two CPU cluster clocks but one shared CPU voltage rail. Use one
>> cpufreq policy for all CPUs, let the OPP core handle the shared regulator
>> and the cluster0 clock, and update the cluster1 clock explicitly.
>
> If the clusters can do DVFS individually (as they have separate clocks), this
> should be represented as two separate policies. Isn't it ?

The clusters have separate clocks, but they share the same voltage supply.[1]
So two independent policies would be unsafe: one policy could lower the shared
voltage while the other cluster is still running at a higher frequency.
This means they can't use different policies.

>From a hardware perspective, the eight cores of the K1 are homogeneous,
so using the same policy for them is relatively reasonable.

I used a K1-specific driver because cpufreq-dt only manages one CPU clock
through the CPU device used for the OPP transition.
On K1, the policy needs to control two independent cluster clocks and one shared
regulator, so the driver has to update the second cluster clock explicitly and
keep the ordering safe: raise voltage before raising either cluster, and lower
both cluster clocks before lowering the shared voltage.

[1] https://lore.kernel.org/spacemit/aeaXszeaE62rM6BJ at aurel32.net/

-- 
Best regards,
Shuwei Wu


From viresh.kumar at linaro.org  Sun Jun 14 23:34:50 2026
From: viresh.kumar at linaro.org (Viresh Kumar)
Date: Mon, 15 Jun 2026 12:04:50 +0530
Subject: [PATCH v3 1/2] cpufreq: spacemit: Add K1 cpufreq driver
In-Reply-To: <DJ9EFPG561VZ.1WGRYYHJ2W9J9@mailbox.org>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
 <20260612-shadow-deps-v3-1-2f3ba88611ff@mailbox.org>
 <bd4s2icqgusnuujvrpoag4cniy3g2e4bumecqxt5yffl77aqpq@kxg4dj4c2wk3>
 <DJ9EFPG561VZ.1WGRYYHJ2W9J9@mailbox.org>
Message-ID: <wjwkykv555gkeqxabsqcdfn4lomcopawsv7bgm4bydc5likhjs@p3ca3p7wbri5>

Hi Shuwei,

On 15-06-26, 14:12, Shuwei Wu wrote:
> The clusters have separate clocks, but they share the same voltage supply.[1]
> So two independent policies would be unsafe: one policy could lower the shared
> voltage while the other cluster is still running at a higher frequency.

No, both will vote for the regulator contraints using CPU device and the
regulator core will make sure it doesn't break any of them. This is what all
frameworks do, regulator, clk, etc.

> This means they can't use different policies.

This is incorrect.

> From a hardware perspective, the eight cores of the K1 are homogeneous,
> so using the same policy for them is relatively reasonable.

Right, but this is inefficient. One cluster can be idle, or in low freq mode
while other can be in higher. They MUST be two policies.

> I used a K1-specific driver because cpufreq-dt only manages one CPU clock
> through the CPU device used for the OPP transition.
> On K1, the policy needs to control two independent cluster clocks and one shared
> regulator, so the driver has to update the second cluster clock explicitly and
> keep the ordering safe: raise voltage before raising either cluster, and lower
> both cluster clocks before lowering the shared voltage.
> 
> [1] https://lore.kernel.org/spacemit/aeaXszeaE62rM6BJ at aurel32.net/

-- 
viresh


From zhangzhanpeng.jasper at bytedance.com  Sun Jun 14 23:48:55 2026
From: zhangzhanpeng.jasper at bytedance.com (Zhanpeng Zhang)
Date: Mon, 15 Jun 2026 14:48:55 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
Message-ID: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>

Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
registers to be accessed using 32-bit accesses, provided the accesses are
properly aligned and do not span multiple registers.

Add a config option for such implementations and access 64-bit IOMMU
registers as paired 32-bit MMIO operations when it is enabled. Serialize
the paired accesses so the high and low halves cannot interleave with
another CPU. Full 64-bit register programming writes the high half before
the low half.

This option describes the register access width. It is not an RV32 kernel
mode and does not describe a 32-bit IOMMU architecture.

Co-developed-by: Xu Lu <luxu.kernel at bytedance.com>
Signed-off-by: Xu Lu <luxu.kernel at bytedance.com>
Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com>
---
This is needed for platforms whose RISC-V IOMMU register window does not
support naturally aligned 64-bit MMIO accesses.

 drivers/iommu/riscv/Kconfig | 11 ++++++++
 drivers/iommu/riscv/iommu.c |  4 +++
 drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
 3 files changed, 64 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
index b86e5ab94183..54d624b9b2ef 100644
--- a/drivers/iommu/riscv/Kconfig
+++ b/drivers/iommu/riscv/Kconfig
@@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
 	def_bool y if RISCV_IOMMU && PCI_MSI
 	help
 	  Support for the PCIe implementation of RISC-V IOMMU architecture.
+
+config RISCV_IOMMU_32BIT_ACCESS
+	bool "Use 32-bit accesses for RISC-V IOMMU registers"
+	depends on RISCV_IOMMU
+	help
+	  Say Y when the RISC-V IOMMU MMIO window cannot be accessed
+	  using naturally aligned 64-bit loads and stores.
+
+	  When enabled, 64-bit IOMMU registers are accessed as paired
+	  32-bit MMIO operations. This option does not describe an RV32
+	  kernel or a 32-bit IOMMU architecture.
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index a31f50bbad35..7fa1721b5728 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -53,6 +53,10 @@ struct riscv_iommu_devres {
 	void *addr;
 };
 
+#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
+DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
+#endif
+
 static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
 {
 	struct riscv_iommu_devres *devres = res;
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 46df79dd5495..ba78ef1858c5 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -14,6 +14,9 @@
 #include <linux/iommu.h>
 #include <linux/types.h>
 #include <linux/iopoll.h>
+#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
+#include <linux/spinlock.h>
+#endif
 
 #include "iommu-bits.h"
 
@@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
 #define riscv_iommu_readl(iommu, addr) \
 	readl_relaxed((iommu)->reg + (addr))
 
-#define riscv_iommu_readq(iommu, addr) \
-	readq_relaxed((iommu)->reg + (addr))
-
 #define riscv_iommu_writel(iommu, addr, val) \
 	writel_relaxed((val), (iommu)->reg + (addr))
 
+#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
+	readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
+			   delay_us, timeout_us)
+
+#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
+#define riscv_iommu_readq(iommu, addr) \
+	readq_relaxed((iommu)->reg + (addr))
+
 #define riscv_iommu_writeq(iommu, addr, val) \
 	writeq_relaxed((val), (iommu)->reg + (addr))
 
 #define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
 	readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
 			   delay_us, timeout_us)
+#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
 
-#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
-	readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
-			   delay_us, timeout_us)
+extern raw_spinlock_t riscv_iommu_32bit_access_lock;
+
+static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
+{
+	u32 lo, hi;
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
+	do {
+		hi = readl_relaxed(addr + sizeof(u32));
+		lo = readl_relaxed(addr);
+	} while (hi != readl_relaxed(addr + sizeof(u32)));
+	raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
+
+	return ((u64)hi << 32) | (u64)lo;
+}
+
+static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
+{
+	unsigned long flags;
+
+	raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
+	writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
+	writel_relaxed((u32)value, addr);
+	raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
+}
+
+#define riscv_iommu_readq(iommu, addr) \
+	__riscv_iommu_readq_relaxed((iommu)->reg + (addr))
+
+#define riscv_iommu_writeq(iommu, addr, val) \
+	__riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
+
+#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
+	readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
+			   val, cond, delay_us, timeout_us)
+#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
 
 #endif
-- 
2.50.1 (Apple Git-155)


From troy.mitchell at linux.spacemit.com  Mon Jun 15 00:15:40 2026
From: troy.mitchell at linux.spacemit.com (Troy Mitchell)
Date: Mon, 15 Jun 2026 15:15:40 +0800
Subject: [PATCH] dmaengine: mmp_pdma: fix wrong extended DRCMR base for
 SpacemiT K3
In-Reply-To: <20260615-k3-pdma-fix-drcmr-base-v1-1-ee1af124199f@linux.spacemit.com>
References: <20260615-k3-pdma-fix-drcmr-base-v1-1-ee1af124199f@linux.spacemit.com>
Message-ID: <DJ9FSDGD51UL.19AY499L4RI3K@linux.spacemit.com>

On Mon Jun 15, 2026 at 10:53 AM CST, Troy Mitchell wrote:
> K3 PDMA shares the same DRCMR layout as K1, where the extended DRCMR
> base address is 0x1100. Commit 6587b8661a0b ("dmaengine: mmp_pdma: add
> SpacemiT K3 support") incorrectly defined DRCMR_EXT_BASE_K3 as 0x1000,
> causing all DRCMR accesses for channels >= 64 to be off by 0x100.
>
> Drop the bogus DRCMR_EXT_BASE_K3 macro and reuse DRCMR_EXT_BASE_DEFAULT
> for the K3 ops.
>
> Fixes: 6587b8661a0b ("dmaengine: mmp_pdma: add SpacemiT K3 support")
To clarify: the previous version was not untested; it simply hadn't been
tested with SPI DMA specifically. This issue only affects DMA for SPI
devices, rather than all DMA-capable peripherals

                                          - Troy


From docular.xu at gmail.com  Mon Jun 15 01:01:43 2026
From: docular.xu at gmail.com (Guodong Xu)
Date: Mon, 15 Jun 2026 04:01:43 -0400
Subject: [PATCH] dmaengine: mmp_pdma: fix wrong extended DRCMR base for
 SpacemiT K3
In-Reply-To: <20260615-k3-pdma-fix-drcmr-base-v1-1-ee1af124199f@linux.spacemit.com>
References: <20260615-k3-pdma-fix-drcmr-base-v1-1-ee1af124199f@linux.spacemit.com>
Message-ID: <4wo2ylvv2v2kmec4vzycgide3orx2zwjzdjunfm23t6pclknbl@pqtb7lw2parx>

Hi Troy,

Thanks for the patch.

On 2026-06-15 10:53, Troy Mitchell wrote:
>K3 PDMA shares the same DRCMR layout as K1, where the extended DRCMR

K1 never touches DMA request numbers higher than 45. It's not K1 who needs
the extended DRCMR. PXAxx needs them.

>base address is 0x1100. Commit 6587b8661a0b ("dmaengine: mmp_pdma: add
>SpacemiT K3 support") incorrectly defined DRCMR_EXT_BASE_K3 as 0x1000,

The SpacemiT K3 datasheet still 'incorrectly' carries the base 0x1000.
Refer to [1], Section 16.1.4.6 DMA Connectivity & Assignments
which still states 0x1000 as the base:

0x1004 Request for SSP0 TxReq 0xD4040000
0x1008 Request for SSP0 RxReq 0xD4040000

I would recommend you double check with the SpacemiT team to make sure.
It's better SpacemiT can fix both the online document and downloadable PDF
as well.

[1]: https://www.spacemit.com/community/document/info?lang=en&nodepath=hardware/key_stone/k3/k3_docs/k3_usermanual/16_peripherals/dma.md

>causing all DRCMR accesses for channels >= 64 to be off by 0x100.
>
>Drop the bogus DRCMR_EXT_BASE_K3 macro and reuse DRCMR_EXT_BASE_DEFAULT
>for the K3 ops.

>
>Fixes: 6587b8661a0b ("dmaengine: mmp_pdma: add SpacemiT K3 support")
>Signed-off-by: Troy Mitchell <troy.mitchell at linux.spacemit.com>
>---
>This is a minimal fix for the wrong DRCMR_EXT_BASE_K3 value introduced
>by commit 6587b8661a0b ("dmaengine: mmp_pdma: add SpacemiT K3 support").
>K3 PDMA shares the same extended DRCMR base (0x1100) as K1, so the K3
>ops now reuses DRCMR_EXT_BASE_DEFAULT.

Before we flip it, could you please confirm your source fo truth:
did you confirm 0x1100 on k3 silicon with a real DMA transaction,
or from the datasheet? It would help if you could share your
test setup.

BR,
Guodong Xu

>Best regards,
>--
>Troy Mitchell <troy.mitchell at linux.spacemit.com>
>
>
>_______________________________________________
>linux-riscv mailing list
>linux-riscv at lists.infradead.org
>http://lists.infradead.org/mailman/listinfo/linux-riscv


From schwab at suse.de  Mon Jun 15 01:21:12 2026
From: schwab at suse.de (Andreas Schwab)
Date: Mon, 15 Jun 2026 10:21:12 +0200
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
	(Zhanpeng Zhang's message of "Mon, 15 Jun 2026 14:48:55 +0800")
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
Message-ID: <mvmik7kz01z.fsf@suse.de>

On Jun 15 2026, Zhanpeng Zhang wrote:

> +config RISCV_IOMMU_32BIT_ACCESS
> +	bool "Use 32-bit accesses for RISC-V IOMMU registers"
> +	depends on RISCV_IOMMU
> +	help
> +	  Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> +	  using naturally aligned 64-bit loads and stores.
> +
> +	  When enabled, 64-bit IOMMU registers are accessed as paired
> +	  32-bit MMIO operations. This option does not describe an RV32
> +	  kernel or a 32-bit IOMMU architecture.

What is the expected setting in a generic kernel?

-- 
Andreas Schwab, SUSE Labs, schwab at suse.de
GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE  1748 E4D4 88E3 0EEA B9D7
"And now for something completely different."


From ruanjinjie at huawei.com  Mon Jun 15 01:51:48 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 15 Jun 2026 16:51:48 +0800
Subject: [PATCH RFC 3/3] arm64: Add HOTPLUG_PARALLEL support for secondary
 CPUs
In-Reply-To: <SN6PR02MB41575306521E6223561F476FD4182@SN6PR02MB4157.namprd02.prod.outlook.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
 <20260611133809.3854977-4-ruanjinjie@huawei.com>
 <SN6PR02MB41575306521E6223561F476FD4182@SN6PR02MB4157.namprd02.prod.outlook.com>
Message-ID: <e96a2579-c010-4198-a2a3-6ba35b14aef0@huawei.com>



On 6/12/2026 11:45 PM, Michael Kelley wrote:
> From: Jinjie Ruan <ruanjinjie at huawei.com> Sent: Thursday, June 11, 2026 6:38 AM
>>
>> Support for parallel secondary CPU bringup is already utilized by x86,
>> MIPS, and RISC-V. This patch brings this capability to the arm64
>> architecture.
>>
>> Rework the global `secondary_data` accessed during early boot into
>> a per-CPU array. This array maps logical CPU IDs to MPIDR_EL1 values,
>> enabling the early boot code in head.S to resolve each secondary CPU's
>> logical ID concurrently.
>>
>> To fully enable HOTPLUG_PARALLEL, this patch implements:
>> 1) An arm64-specific arch_cpuhp_kick_ap_alive() handler.
>> 2) Callbacks to cpuhp_ap_sync_alive() inside secondary_start_kernel().
>>
>> Successfully tested on QEMU ARM64 virt machine (KVM on, 128 vCPUs).
>>
>> |     test kernel	   | secondary CPUs boot time |
>> |  ---------------------   |	--------------------  |
>> |   Without this patch     |		155.672	      |
>> |   cpuhp.parallel=0	   |		62.897	      |
>> |   cpuhp.parallel=1	   |		166.703	      |
> 
> The last two rows seem mixed up. I would expect parallel=0 to
> result in a longer boot time.

Hi, Michael,

The results are correct and not mixed up.

Compared to the original non?HOTPLUG_PARALLEL approach, the advantage of
cpuhp.parallel=0 lies in its use of cpu_relax(`yield` on arm64) instead
of the wait_for_completion_timeout() mechanism (which may cause sleep
and context switching). This significantly reduces the overhead of VM
exits and context switches in a KVM guest, thereby cutting the secondary
CPU boot time by more than half.

Regarding cpuhp.parallel=1, I believe the reason it fails to optimize
boot time is that when a large number of CPUs issue the KICK_AP call
simultaneously, it results in severe lock contention within KVM, which
paradoxically slows down secondary CPU bringup. However, this needs
further investigation into the PSCI_CPU_ON code in KVM.

I'm testing these performance aspects on physical hardware, so the
results might be somewhat different because secondary CPU bringup
requires trapping into the ATF firmware.

Best regards,
Jinjie

> 
> Michael
> 
>>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>> ---
>>  arch/arm64/Kconfig           |  1 +
>>  arch/arm64/include/asm/smp.h |  8 ++++++++
>>  arch/arm64/kernel/head.S     | 23 +++++++++++++++++++++++
>>  arch/arm64/kernel/smp.c      | 27 +++++++++++++++++++++++++++
>>  4 files changed, 59 insertions(+)
>>
> 
> 



From zhangzhanpeng.jasper at bytedance.com  Mon Jun 15 02:51:38 2026
From: zhangzhanpeng.jasper at bytedance.com (Zhanpeng Zhang)
Date: Mon, 15 Jun 2026 02:51:38 -0700
Subject: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <mvmik7kz01z.fsf@suse.de>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com> <mvmik7kz01z.fsf@suse.de>
Message-ID: <CACnXVnfr9DzKaXkRAP4zkKP61KG7=+iJ6+TZhBJ_vECrTZJpkA@mail.gmail.com>

Hi Andreas,

For a generic kernel, the expected setting is to leave
RISCV_IOMMU_32BIT_ACCESS disabled.

If supporting such platforms from a single generic kernel is preferred, I can
look into replacing this build-time option with a runtime indication.

Regards,
Zhanpeng

> From: "Andreas Schwab"<schwab at suse.de>
> Date:? Mon, Jun 15, 2026, 16:22
> Subject:? [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
> To: "Zhanpeng Zhang"<zhangzhanpeng.jasper at bytedance.com>
> Cc: "Tomasz Jeznach"<tjeznach at rivosinc.com>, "Joerg Roedel"<joro at 8bytes.org>, "Will Deacon"<will at kernel.org>, "Robin Murphy"<robin.murphy at arm.com>, "Paul Walmsley"<pjw at kernel.org>, "Palmer Dabbelt"<palmer at dabbelt.com>, "Albert Ou"<aou at eecs.berkeley.edu>, "Alexandre Ghiti"<alex at ghiti.fr>, <iommu at lists.linux.dev>, <linux-riscv at lists.infradead.org>, <linux-kernel at vger.kernel.org>, "Xu Lu"<luxu.kernel at bytedance.com>, <cuiyunhui at bytedance.com>, <yuanzhu at bytedance.com>
> On Jun 15 2026, Zhanpeng Zhang wrote:
>
> > +config RISCV_IOMMU_32BIT_ACCESS
> > + ? ? ? ?bool "Use 32-bit accesses for RISC-V IOMMU registers"
> > + ? ? ? ?depends on RISCV_IOMMU
> > + ? ? ? ?help
> > + ? ? ? ? ?Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> > + ? ? ? ? ?using naturally aligned 64-bit loads and stores.
> > +
> > + ? ? ? ? ?When enabled, 64-bit IOMMU registers are accessed as paired
> > + ? ? ? ? ?32-bit MMIO operations. This option does not describe an RV32
> > + ? ? ? ? ?kernel or a 32-bit IOMMU architecture.
>
> What is the expected setting in a generic kernel?
>
> --
> Andreas Schwab, SUSE Labs, schwab at suse.de
> GPG Key fingerprint = 0196 BAD8 1CE9 1970 F4BE ?1748 E4D4 88E3 0EEA B9D7
> "And now for something completely different."
>


From ruanjinjie at huawei.com  Mon Jun 15 02:57:22 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Mon, 15 Jun 2026 17:57:22 +0800
Subject: [PATCH RFC 3/3] arm64: Add HOTPLUG_PARALLEL support for secondary
 CPUs
In-Reply-To: <SN6PR02MB41575306521E6223561F476FD4182@SN6PR02MB4157.namprd02.prod.outlook.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
 <20260611133809.3854977-4-ruanjinjie@huawei.com>
 <SN6PR02MB41575306521E6223561F476FD4182@SN6PR02MB4157.namprd02.prod.outlook.com>
Message-ID: <4588efb4-e757-4ca7-9197-025b67ca9ef6@huawei.com>



On 6/12/2026 11:45 PM, Michael Kelley wrote:
> From: Jinjie Ruan <ruanjinjie at huawei.com> Sent: Thursday, June 11, 2026 6:38 AM
>>
>> Support for parallel secondary CPU bringup is already utilized by x86,
>> MIPS, and RISC-V. This patch brings this capability to the arm64
>> architecture.
>>
>> Rework the global `secondary_data` accessed during early boot into
>> a per-CPU array. This array maps logical CPU IDs to MPIDR_EL1 values,
>> enabling the early boot code in head.S to resolve each secondary CPU's
>> logical ID concurrently.
>>
>> To fully enable HOTPLUG_PARALLEL, this patch implements:
>> 1) An arm64-specific arch_cpuhp_kick_ap_alive() handler.
>> 2) Callbacks to cpuhp_ap_sync_alive() inside secondary_start_kernel().
>>
>> Successfully tested on QEMU ARM64 virt machine (KVM on, 128 vCPUs).
>>
>> |     test kernel	   | secondary CPUs boot time |
>> |  ---------------------   |	--------------------  |
>> |   Without this patch     |		155.672	      |
>> |   cpuhp.parallel=0	   |		62.897	      |
>> |   cpuhp.parallel=1	   |		166.703	      |
> 
> The last two rows seem mixed up. I would expect parallel=0 to
> result in a longer boot time.

Without this patch:

KVM event statistics (6 entries)
Event name       Samples       Sample%     Time (ns)         Time%
Mean Time (ns)
  DABT_LOW        323112        75.00%    1669148000        17.00%
5165
       WFx         85817        19.00%     723215800         7.00%
8427
     SYS64         14914         3.00%     419934530         4.00%
28157
       IRQ          5643         1.00%    6732439250        70.00%
1193060
     HVC64           282         0.00%      35543970         0.00%
126042
  IABT_LOW             1         0.00%          6130         0.00%
6130

cpuhp.parallel=0:

Event name       Samples       Sample%     Time (ns)         Time%
Mean Time (ns)
 DABT_LOW        308175        80.00%     643628050         6.00%
2088
      WFx         55208        14.00%     261925270         2.00%
4744
    SYS64         14975         3.00%     155727880         1.00%
10399
      IRQ          4755         1.00%    8496162210        88.00%
1786784
    HVC64           280         0.00%      19429900         0.00%
69392
 IABT_LOW             1         0.00%          5850         0.00%
5850

cpuhp.parallel=1:

 Event name       Samples       Sample%     Time (ns)         Time%
Mean Time (ns)
 DABT_LOW        307923        77.00%     692965050         2.00%
     2250
      WFx         59549        15.00%     287888960         0.00%
     4834
    SYS64         15127         3.00%     334366230         1.00%
    22103
      IRQ         12861         3.00%   29784004970        95.00%
  2315838
    HVC64           280         0.00%      21869940         0.00%
    78106
 IABT_LOW             1         0.00%          9320         0.00%
     9320

- Default (no patch): Slowest HVC64 handling (126??s), highest WFx count
(85k), and most total VM?exits.

- cpuhp.parallel=1: HVC64 latency improved to 78??s (close to
cpuhp.parallel=0), but IRQ exits increased dramatically (12.9k, 2.7?
that of `cpuhp.parallel=0`), accounting for 95% of event time and
becoming the new bottleneck.

- cpuhp.parallel=0: Fastest HVC64 (69??s), lowest IRQ exits (4.8k), and
lowest total samples, delivering the best overall boot performance.

Therefor, `cpuhp.parallel=1` reduces HVC cost but suffers from a massive
increase in IRQ exits, while `cpuhp.parallel=0` avoids this interrupt
storm and therefore performs best in a KVM guest.

> 
> Michael
> 
>>
>> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
>> ---
>>  arch/arm64/Kconfig           |  1 +
>>  arch/arm64/include/asm/smp.h |  8 ++++++++
>>  arch/arm64/kernel/head.S     | 23 +++++++++++++++++++++++
>>  arch/arm64/kernel/smp.c      | 27 +++++++++++++++++++++++++++
>>  4 files changed, 59 insertions(+)
>>
> 
> 



From david.laight.linux at gmail.com  Mon Jun 15 02:59:59 2026
From: david.laight.linux at gmail.com (David Laight)
Date: Mon, 15 Jun 2026 10:59:59 +0100
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
Message-ID: <20260615105959.136698e8@pumpkin>

On Mon, 15 Jun 2026 14:48:55 +0800
Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com> wrote:

> Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
> to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
> registers to be accessed using 32-bit accesses, provided the accesses are
> properly aligned and do not span multiple registers.
> 
> Add a config option for such implementations and access 64-bit IOMMU
> registers as paired 32-bit MMIO operations when it is enabled. Serialize
> the paired accesses so the high and low halves cannot interleave with
> another CPU. Full 64-bit register programming writes the high half before
> the low half.
> 
> This option describes the register access width. It is not an RV32 kernel
> mode and does not describe a 32-bit IOMMU architecture.
> 
> Co-developed-by: Xu Lu <luxu.kernel at bytedance.com>
> Signed-off-by: Xu Lu <luxu.kernel at bytedance.com>
> Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com>
> ---
> This is needed for platforms whose RISC-V IOMMU register window does not
> support naturally aligned 64-bit MMIO accesses.
> 
>  drivers/iommu/riscv/Kconfig | 11 ++++++++
>  drivers/iommu/riscv/iommu.c |  4 +++
>  drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
>  3 files changed, 64 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> index b86e5ab94183..54d624b9b2ef 100644
> --- a/drivers/iommu/riscv/Kconfig
> +++ b/drivers/iommu/riscv/Kconfig
> @@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
>  	def_bool y if RISCV_IOMMU && PCI_MSI
>  	help
>  	  Support for the PCIe implementation of RISC-V IOMMU architecture.
> +
> +config RISCV_IOMMU_32BIT_ACCESS
> +	bool "Use 32-bit accesses for RISC-V IOMMU registers"
> +	depends on RISCV_IOMMU
> +	help
> +	  Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> +	  using naturally aligned 64-bit loads and stores.
> +
> +	  When enabled, 64-bit IOMMU registers are accessed as paired
> +	  32-bit MMIO operations. This option does not describe an RV32
> +	  kernel or a 32-bit IOMMU architecture.
> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> index a31f50bbad35..7fa1721b5728 100644
> --- a/drivers/iommu/riscv/iommu.c
> +++ b/drivers/iommu/riscv/iommu.c
> @@ -53,6 +53,10 @@ struct riscv_iommu_devres {
>  	void *addr;
>  };
>  
> +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
> +#endif
> +
>  static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
>  {
>  	struct riscv_iommu_devres *devres = res;
> diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> index 46df79dd5495..ba78ef1858c5 100644
> --- a/drivers/iommu/riscv/iommu.h
> +++ b/drivers/iommu/riscv/iommu.h
> @@ -14,6 +14,9 @@
>  #include <linux/iommu.h>
>  #include <linux/types.h>
>  #include <linux/iopoll.h>
> +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +#include <linux/spinlock.h>
> +#endif
>  
>  #include "iommu-bits.h"
>  
> @@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
>  #define riscv_iommu_readl(iommu, addr) \
>  	readl_relaxed((iommu)->reg + (addr))
>  
> -#define riscv_iommu_readq(iommu, addr) \
> -	readq_relaxed((iommu)->reg + (addr))
> -
>  #define riscv_iommu_writel(iommu, addr, val) \
>  	writel_relaxed((val), (iommu)->reg + (addr))
>  
> +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> +	readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> +			   delay_us, timeout_us)
> +
> +#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +#define riscv_iommu_readq(iommu, addr) \
> +	readq_relaxed((iommu)->reg + (addr))
> +
>  #define riscv_iommu_writeq(iommu, addr, val) \
>  	writeq_relaxed((val), (iommu)->reg + (addr))
>  
>  #define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
>  	readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
>  			   delay_us, timeout_us)
> +#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
>  
> -#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> -	readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> -			   delay_us, timeout_us)
> +extern raw_spinlock_t riscv_iommu_32bit_access_lock;
> +
> +static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
> +{
> +	u32 lo, hi;
> +	unsigned long flags;
> +
> +	raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> +	do {
> +		hi = readl_relaxed(addr + sizeof(u32));
> +		lo = readl_relaxed(addr);
> +	} while (hi != readl_relaxed(addr + sizeof(u32)));
> +	raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);

Why the lock and the loop?
If you need the loop (for places where the hardware might be changing
both words?) then there is no need to read 'hi' twice when you loop.

But does it make any sense to be reading the value either while the hardware
is updating it (does that happen?) or concurrently with a write.


> +
> +	return ((u64)hi << 32) | (u64)lo;
> +}
> +
> +static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
> +{
> +	unsigned long flags;
> +
> +	raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> +	writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
> +	writel_relaxed((u32)value, addr);
> +	raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);

What are you actually locking against?
I'm pretty sure it doesn't make any sense for two cpu to be writing to the
same entry at the same time.

Can't the writel_relaxed() be re-ordered, so you aren't guaranteeing they'll
be done high-low.
Same with the reads.

	David

> +}
> +
> +#define riscv_iommu_readq(iommu, addr) \
> +	__riscv_iommu_readq_relaxed((iommu)->reg + (addr))
> +
> +#define riscv_iommu_writeq(iommu, addr, val) \
> +	__riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
> +
> +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> +	readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
> +			   val, cond, delay_us, timeout_us)
> +#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
>  
>  #endif



From josh.milas at gmail.com  Mon Jun 15 05:03:21 2026
From: josh.milas at gmail.com (Joshua Milas)
Date: Mon, 15 Jun 2026 08:03:21 -0400
Subject: [PATCH v6 0/3] Add initial Milk-V Duo S board support
Message-ID: <20260615120324.1527881-1-josh.milas@gmail.com>

This adds an initial device tree for the Milk-V Duo S board
with support for reading from the SD card and network over
Ethernet. This is continued work from Michael Opdenacker's
v6 series [1] on the ARM64 and RISCV side. It has been tested
with ARM64 and RISCV64 to boot from an SD card, have networking
from ethernet, enumerate the wifi chip, have bluetooth, and can 
read a I2C slave device over i2c4.

---

v6
- Patches 1,3 from v5 were applied
- Rebased to latest sophgo/for-next 
- Added mmc1, mmc2, serial4 aliases
- Removed spi3 alias and node as it was conflicting with sdhci1/wifi
- Added wifi_pwrseq node for wifi chip
- Added pinctrl configs for enabled devices
- Reordered &sdhci0 properties
- Updated &sdhci1 node properties for wifi chip
- Added uart4 for bluetooth
- Changed memory from 256 MB to 512 MB on riscv side

v5: https://lore.kernel.org/sophgo/20260403111516.379795-1-josh.milas at gmail.com/
- Fixes spaces at beginning of line in &usb node of DTS

v4: https://lore.kernel.org/sophgo/20260328173450.219664-2-josh.milas at gmail.com/
- Rebased to latest sophogo/for-next
- Added usb node to arm64 and riscv DTS
- Removed sg200x link in commit messages
- Added missing change to v3 and removed link from v2

v3: https://lore.kernel.org/sophgo/20251029001052.36774-1-josh.milas at gmail.com/
- Added sg2000 interrupt controller and timer to documentation
- Added sg2000.dtsi for RISCV and moved DTS over to use it
- remove devices from DTS's to match what is available in the
  default pinmux config. spi0-2, i2c0-3, uart1-4
- Added i2c4 and spi3 aliases
- Removed milkv,duo-s from sophgo,cv1812h in documentation

v2: https://lore.kernel.org/sophgo/20251011014811.28521-1-josh.milas at gmail.com/
- Made new entry in docs to avoid DTC error
- "Milk-V DuoS" -> "Milk-V Duo S"
- Sorting of aliases
- Added uart*, emmc, mdio, gmac0, i2c*, spi*, dmac, saradc
  to device tree matching what is available on the pinout
- Removal of 'no-mmc' and 'no-sdio' for sdhci0 as it works without
- Added riscv device tree

v1: https://lore.kernel.org/sophgo/20250927173619.89768-1-josh.milas at gmail.com/

Link: https://lore.kernel.org/linux-riscv/20240421055710.143617-1-michael.opdenacker at bootlin.com/ [1]

Joshua Milas (3):
  arm64: dts: sophgo: add initial Milk-V Duo S board support
  riscv64: dts: sophgo: add SG2000 dtsi
  riscv64: dts: sophgo: add initial Milk-V Duo S board support

 arch/arm64/boot/dts/sophgo/Makefile           |   1 +
 .../boot/dts/sophgo/sg2000-milkv-duo-s.dts    | 245 ++++++++++++++++++
 arch/riscv/boot/dts/sophgo/Makefile           |   1 +
 .../boot/dts/sophgo/sg2000-milkv-duo-s.dts    | 245 ++++++++++++++++++
 arch/riscv/boot/dts/sophgo/sg2000.dtsi        |  53 ++++
 5 files changed, 545 insertions(+)
 create mode 100644 arch/arm64/boot/dts/sophgo/sg2000-milkv-duo-s.dts
 create mode 100644 arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts
 create mode 100644 arch/riscv/boot/dts/sophgo/sg2000.dtsi


base-commit: f7337210bede62fc7c6230ef58013dddf7e0a921
-- 
2.54.0



From josh.milas at gmail.com  Mon Jun 15 05:03:22 2026
From: josh.milas at gmail.com (Joshua Milas)
Date: Mon, 15 Jun 2026 08:03:22 -0400
Subject: [PATCH v6 1/3] arm64: dts: sophgo: add initial Milk-V Duo S board support
In-Reply-To: <20260615120324.1527881-1-josh.milas@gmail.com>
References: <20260615120324.1527881-1-josh.milas@gmail.com>
Message-ID: <20260615120324.1527881-2-josh.milas@gmail.com>

Adds initial arm64 support for the Milk-V Duo S board
[1] making it possible to boot Linux to the command line.

Link: https://milkv.io/duo-s [1]

Signed-off-by: Joshua Milas <josh.milas at gmail.com>
---
 arch/arm64/boot/dts/sophgo/Makefile           |   1 +
 .../boot/dts/sophgo/sg2000-milkv-duo-s.dts    | 245 ++++++++++++++++++
 2 files changed, 246 insertions(+)
 create mode 100644 arch/arm64/boot/dts/sophgo/sg2000-milkv-duo-s.dts

diff --git a/arch/arm64/boot/dts/sophgo/Makefile b/arch/arm64/boot/dts/sophgo/Makefile
index 94f52cd7d994..68aace728223 100644
--- a/arch/arm64/boot/dts/sophgo/Makefile
+++ b/arch/arm64/boot/dts/sophgo/Makefile
@@ -1,2 +1,3 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2000-milkv-duo-module-01-evb.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += sg2000-milkv-duo-s.dtb
diff --git a/arch/arm64/boot/dts/sophgo/sg2000-milkv-duo-s.dts b/arch/arm64/boot/dts/sophgo/sg2000-milkv-duo-s.dts
new file mode 100644
index 000000000000..f56bfddeacc4
--- /dev/null
+++ b/arch/arm64/boot/dts/sophgo/sg2000-milkv-duo-s.dts
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/pinctrl/pinctrl-sg2000.h>
+#include "sg2000.dtsi"
+
+/ {
+	model = "Milk-V Duo S";
+	compatible = "milkv,duo-s", "sophgo,sg2000";
+
+	aliases {
+		i2c4 = &i2c4;
+		mmc0 = &sdhci0;
+		mmc1 = &emmc;
+		mmc2 = &sdhci1;
+		serial0 = &uart0;
+		serial4 = &uart4;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&porta 15 GPIO_ACTIVE_LOW>;
+		power-off-delay-us = <50000>;
+		post-power-on-delay-ms = <200>;
+	};
+};
+
+&osc {
+	clock-frequency = <25000000>;
+};
+
+&pinctrl {
+	emmc_cfg: emmc-cfg {
+		emmc-rstn-pins {
+			pinmux = <PINMUX(PIN_EMMC_RSTN, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		emmc-clk-pins {
+			pinmux = <PINMUX(PIN_EMMC_CLK, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		emmc-cmd-pins {
+			pinmux = <PINMUX(PIN_EMMC_CMD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		emmc-data-pins {
+			pinmux = <PINMUX(PIN_EMMC_DAT0, 0)>,
+				 <PINMUX(PIN_EMMC_DAT1, 0)>,
+				 <PINMUX(PIN_EMMC_DAT2, 0)>,
+				 <PINMUX(PIN_EMMC_DAT3, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+	};
+
+	i2c4_cfg: i2c4-cfg {
+		i2c4-pins {
+			pinmux = <PINMUX(PIN_VIVO_D1, 7)>,
+				 <PINMUX(PIN_VIVO_D0, 7)>;
+			bias-pull-up;
+			drive-strength-microamp = <4000>;
+			power-source = <1800>;
+		};
+	};
+
+	sdhci0_cfg: sdhci0-cfg {
+		sdhci0-cd-pins {
+			pinmux = <PINMUX(PIN_SD0_CD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		sdhci0-clk-pins {
+			pinmux = <PINMUX(PIN_SD0_CLK, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <16100>;
+			power-source = <3300>;
+		};
+
+		sdhci0-cmd-pins {
+			pinmux = <PINMUX(PIN_SD0_CMD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		sdhci0-data-pins {
+			pinmux = <PINMUX(PIN_SD0_D0, 0)>,
+				 <PINMUX(PIN_SD0_D1, 0)>,
+				 <PINMUX(PIN_SD0_D2, 0)>,
+				 <PINMUX(PIN_SD0_D3, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+
+	sdhci1_cfg: sdhci1-cfg {
+		sdhci1-clk-pins {
+			pinmux = <PINMUX(PIN_MIPI_TXM4, 1)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		sdhci1-cmd-pins {
+			pinmux = <PINMUX(PIN_MIPI_TXP4, 1)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		sdhci1-data-pins {
+			pinmux = <PINMUX(PIN_MIPI_TXM3, 1)>,
+				 <PINMUX(PIN_MIPI_TXP3, 1)>,
+				 <PINMUX(PIN_MIPI_TXM2, 7)>,
+				 <PINMUX(PIN_MIPI_TXP2, 7)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+	};
+
+	uart0_cfg: uart0-cfg {
+		uart0-pins {
+			pinmux = <PINMUX(PIN_UART0_TX, 0)>,
+				 <PINMUX(PIN_UART0_RX, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+
+	uart4_cfg: uart4-cfg {
+		uart4-data-pins {
+			pinmux = <PINMUX(PIN_UART2_TX, 5)>,
+				 <PINMUX(PIN_UART2_RX, 5)>;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		uart4-control-pins {
+			pinmux = <PINMUX(PIN_UART2_CTS, 5)>,
+				 <PINMUX(PIN_UART2_RTS, 5)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+};
+
+&dmac {
+	status = "okay";
+};
+
+&emmc {
+	bus-width = <4>;
+	no-1-8-v;
+	cap-mmc-hw-reset;
+	no-sd;
+	no-sdio;
+	non-removable;
+	pinctrl-0 = <&emmc_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gmac0 {
+	status = "okay";
+};
+
+&i2c4 {
+	pinctrl-0 = <&i2c4_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&mdio {
+	status = "okay";
+};
+
+&saradc {
+	status = "okay";
+};
+
+&sdhci0 {
+	bus-width = <4>;
+	disable-wp;
+	no-1-8-v;
+	pinctrl-0 = <&sdhci0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sdhci1 {
+	bus-width = <4>;
+	cap-sdio-irq;
+	cap-sd-highspeed;
+	keep-power-in-suspend;
+	no-mmc;
+	no-sd;
+	non-removable;
+	max-frequency = <150000000>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	pinctrl-0 = <&sdhci1_cfg>;
+	pinctrl-names = "default";
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-0 = <&uart4_cfg>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+	status = "okay";
+};
+
+&usb {
+	dr_mode = "host";
+	status = "okay";
+};
+
-- 
2.54.0



From josh.milas at gmail.com  Mon Jun 15 05:03:23 2026
From: josh.milas at gmail.com (Joshua Milas)
Date: Mon, 15 Jun 2026 08:03:23 -0400
Subject: [PATCH v6 2/3] riscv64: dts: sophgo: add SG2000 dtsi
In-Reply-To: <20260615120324.1527881-1-josh.milas@gmail.com>
References: <20260615120324.1527881-1-josh.milas@gmail.com>
Message-ID: <20260615120324.1527881-3-josh.milas@gmail.com>

Adds sg2000.dtsi on the RISCV side.

Signed-off-by: Joshua Milas <josh.milas at gmail.com>
Tested-by: Gui-Dong Han <hanguidong02 at gmail.com>
Reviewed-by: Gui-Dong Han <hanguidong02 at gmail.com>
---
 arch/riscv/boot/dts/sophgo/sg2000.dtsi | 53 ++++++++++++++++++++++++++
 1 file changed, 53 insertions(+)
 create mode 100644 arch/riscv/boot/dts/sophgo/sg2000.dtsi

diff --git a/arch/riscv/boot/dts/sophgo/sg2000.dtsi b/arch/riscv/boot/dts/sophgo/sg2000.dtsi
new file mode 100644
index 000000000000..38462769574f
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/sg2000.dtsi
@@ -0,0 +1,53 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+#define SOC_PERIPHERAL_IRQ(nr)	((nr) + 16)
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/pinctrl/pinctrl-sg2000.h>
+#include "cv180x-cpus.dtsi"
+#include "cv180x.dtsi"
+#include "cv181x.dtsi"
+
+/ {
+	compatible = "sophgo,sg2000";
+
+	memory at 80000000 {
+		device_type = "memory";
+		reg = <0x80000000 0x20000000>;
+	};
+
+	soc {
+		interrupt-parent = <&plic>;
+		dma-noncoherent;
+
+		pinctrl: pinctrl at 3001000 {
+			compatible = "sophgo,sg2000-pinctrl";
+			reg = <0x03001000 0x1000>,
+			      <0x05027000 0x1000>;
+			reg-names = "sys", "rtc";
+		};
+
+		clk: clock-controller at 3002000 {
+			compatible = "sophgo,sg2000-clk";
+			reg = <0x03002000 0x1000>;
+			clocks = <&osc>;
+			#clock-cells = <1>;
+		};
+
+		plic: interrupt-controller at 70000000 {
+			compatible = "sophgo,sg2000-plic", "thead,c900-plic";
+			reg = <0x70000000 0x4000000>;
+			interrupts-extended = <&cpu0_intc 11>, <&cpu0_intc 9>;
+			interrupt-controller;
+			#address-cells = <0>;
+			#interrupt-cells = <2>;
+			riscv,ndev = <101>;
+		};
+
+		clint: timer at 74000000 {
+			compatible = "sophgo,sg2000-clint", "thead,c900-clint";
+			reg = <0x74000000 0x10000>;
+			interrupts-extended = <&cpu0_intc 3>, <&cpu0_intc 7>;
+		};
+	};
+};
-- 
2.54.0



From josh.milas at gmail.com  Mon Jun 15 05:03:24 2026
From: josh.milas at gmail.com (Joshua Milas)
Date: Mon, 15 Jun 2026 08:03:24 -0400
Subject: [PATCH v6 3/3] riscv64: dts: sophgo: add initial Milk-V Duo S board support
In-Reply-To: <20260615120324.1527881-1-josh.milas@gmail.com>
References: <20260615120324.1527881-1-josh.milas@gmail.com>
Message-ID: <20260615120324.1527881-4-josh.milas@gmail.com>

This adds initial riscv support for the Milk-V Duo S board
[1] making it possible to boot Linux to the command line.

Link: https://milkv.io/duo-s [1]

Signed-off-by: Joshua Milas <josh.milas at gmail.com>
---
 arch/riscv/boot/dts/sophgo/Makefile           |   1 +
 .../boot/dts/sophgo/sg2000-milkv-duo-s.dts    | 245 ++++++++++++++++++
 2 files changed, 246 insertions(+)
 create mode 100644 arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts

diff --git a/arch/riscv/boot/dts/sophgo/Makefile b/arch/riscv/boot/dts/sophgo/Makefile
index 6f65526d4193..58cc6b70d8de 100644
--- a/arch/riscv/boot/dts/sophgo/Makefile
+++ b/arch/riscv/boot/dts/sophgo/Makefile
@@ -1,6 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0
 dtb-$(CONFIG_ARCH_SOPHGO) += cv1800b-milkv-duo.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += cv1812h-huashan-pi.dtb
+dtb-$(CONFIG_ARCH_SOPHGO) += sg2000-milkv-duo-s.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2002-licheerv-nano-b.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-milkv-pioneer.dtb
 dtb-$(CONFIG_ARCH_SOPHGO) += sg2042-evb-v1.dtb
diff --git a/arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts b/arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts
new file mode 100644
index 000000000000..f56bfddeacc4
--- /dev/null
+++ b/arch/riscv/boot/dts/sophgo/sg2000-milkv-duo-s.dts
@@ -0,0 +1,245 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+
+/dts-v1/;
+
+#include <dt-bindings/pinctrl/pinctrl-sg2000.h>
+#include "sg2000.dtsi"
+
+/ {
+	model = "Milk-V Duo S";
+	compatible = "milkv,duo-s", "sophgo,sg2000";
+
+	aliases {
+		i2c4 = &i2c4;
+		mmc0 = &sdhci0;
+		mmc1 = &emmc;
+		mmc2 = &sdhci1;
+		serial0 = &uart0;
+		serial4 = &uart4;
+	};
+
+	chosen {
+		stdout-path = "serial0:115200n8";
+	};
+
+	wifi_pwrseq: wifi-pwrseq {
+		compatible = "mmc-pwrseq-simple";
+		reset-gpios = <&porta 15 GPIO_ACTIVE_LOW>;
+		power-off-delay-us = <50000>;
+		post-power-on-delay-ms = <200>;
+	};
+};
+
+&osc {
+	clock-frequency = <25000000>;
+};
+
+&pinctrl {
+	emmc_cfg: emmc-cfg {
+		emmc-rstn-pins {
+			pinmux = <PINMUX(PIN_EMMC_RSTN, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		emmc-clk-pins {
+			pinmux = <PINMUX(PIN_EMMC_CLK, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		emmc-cmd-pins {
+			pinmux = <PINMUX(PIN_EMMC_CMD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		emmc-data-pins {
+			pinmux = <PINMUX(PIN_EMMC_DAT0, 0)>,
+				 <PINMUX(PIN_EMMC_DAT1, 0)>,
+				 <PINMUX(PIN_EMMC_DAT2, 0)>,
+				 <PINMUX(PIN_EMMC_DAT3, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+	};
+
+	i2c4_cfg: i2c4-cfg {
+		i2c4-pins {
+			pinmux = <PINMUX(PIN_VIVO_D1, 7)>,
+				 <PINMUX(PIN_VIVO_D0, 7)>;
+			bias-pull-up;
+			drive-strength-microamp = <4000>;
+			power-source = <1800>;
+		};
+	};
+
+	sdhci0_cfg: sdhci0-cfg {
+		sdhci0-cd-pins {
+			pinmux = <PINMUX(PIN_SD0_CD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		sdhci0-clk-pins {
+			pinmux = <PINMUX(PIN_SD0_CLK, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <16100>;
+			power-source = <3300>;
+		};
+
+		sdhci0-cmd-pins {
+			pinmux = <PINMUX(PIN_SD0_CMD, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		sdhci0-data-pins {
+			pinmux = <PINMUX(PIN_SD0_D0, 0)>,
+				 <PINMUX(PIN_SD0_D1, 0)>,
+				 <PINMUX(PIN_SD0_D2, 0)>,
+				 <PINMUX(PIN_SD0_D3, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+
+	sdhci1_cfg: sdhci1-cfg {
+		sdhci1-clk-pins {
+			pinmux = <PINMUX(PIN_MIPI_TXM4, 1)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		sdhci1-cmd-pins {
+			pinmux = <PINMUX(PIN_MIPI_TXP4, 1)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+
+		sdhci1-data-pins {
+			pinmux = <PINMUX(PIN_MIPI_TXM3, 1)>,
+				 <PINMUX(PIN_MIPI_TXP3, 1)>,
+				 <PINMUX(PIN_MIPI_TXM2, 7)>,
+				 <PINMUX(PIN_MIPI_TXP2, 7)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <1800>;
+		};
+	};
+
+	uart0_cfg: uart0-cfg {
+		uart0-pins {
+			pinmux = <PINMUX(PIN_UART0_TX, 0)>,
+				 <PINMUX(PIN_UART0_RX, 0)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+
+	uart4_cfg: uart4-cfg {
+		uart4-data-pins {
+			pinmux = <PINMUX(PIN_UART2_TX, 5)>,
+				 <PINMUX(PIN_UART2_RX, 5)>;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+
+		uart4-control-pins {
+			pinmux = <PINMUX(PIN_UART2_CTS, 5)>,
+				 <PINMUX(PIN_UART2_RTS, 5)>;
+			bias-pull-up;
+			drive-strength-microamp = <10800>;
+			power-source = <3300>;
+		};
+	};
+};
+
+&dmac {
+	status = "okay";
+};
+
+&emmc {
+	bus-width = <4>;
+	no-1-8-v;
+	cap-mmc-hw-reset;
+	no-sd;
+	no-sdio;
+	non-removable;
+	pinctrl-0 = <&emmc_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&gmac0 {
+	status = "okay";
+};
+
+&i2c4 {
+	pinctrl-0 = <&i2c4_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&mdio {
+	status = "okay";
+};
+
+&saradc {
+	status = "okay";
+};
+
+&sdhci0 {
+	bus-width = <4>;
+	disable-wp;
+	no-1-8-v;
+	pinctrl-0 = <&sdhci0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&sdhci1 {
+	bus-width = <4>;
+	cap-sdio-irq;
+	cap-sd-highspeed;
+	keep-power-in-suspend;
+	no-mmc;
+	no-sd;
+	non-removable;
+	max-frequency = <150000000>;
+	mmc-pwrseq = <&wifi_pwrseq>;
+	pinctrl-0 = <&sdhci1_cfg>;
+	pinctrl-names = "default";
+	sd-uhs-sdr50;
+	sd-uhs-sdr104;
+	status = "okay";
+};
+
+&uart0 {
+	pinctrl-0 = <&uart0_cfg>;
+	pinctrl-names = "default";
+	status = "okay";
+};
+
+&uart4 {
+	pinctrl-0 = <&uart4_cfg>;
+	pinctrl-names = "default";
+	uart-has-rtscts;
+	status = "okay";
+};
+
+&usb {
+	dr_mode = "host";
+	status = "okay";
+};
+
-- 
2.54.0



From shuwei.wu at mailbox.org  Mon Jun 15 05:11:01 2026
From: shuwei.wu at mailbox.org (Shuwei Wu)
Date: Mon, 15 Jun 2026 20:11:01 +0800
Subject: [PATCH v3 1/2] cpufreq: spacemit: Add K1 cpufreq driver
In-Reply-To: <wjwkykv555gkeqxabsqcdfn4lomcopawsv7bgm4bydc5likhjs@p3ca3p7wbri5>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
 <20260612-shadow-deps-v3-1-2f3ba88611ff@mailbox.org>
 <bd4s2icqgusnuujvrpoag4cniy3g2e4bumecqxt5yffl77aqpq@kxg4dj4c2wk3>
 <DJ9EFPG561VZ.1WGRYYHJ2W9J9@mailbox.org>
 <wjwkykv555gkeqxabsqcdfn4lomcopawsv7bgm4bydc5likhjs@p3ca3p7wbri5>
Message-ID: <DJ9M2IDYE6XZ.20RN5AFBYNB9Y@mailbox.org>

Hi Viresh,

Thanks for pointing it out.

On Mon Jun 15, 2026 at 2:34 PM CST, Viresh Kumar wrote:
> Hi Shuwei,
>
> On 15-06-26, 14:12, Shuwei Wu wrote:
>> The clusters have separate clocks, but they share the same voltage supply.[1]
>> So two independent policies would be unsafe: one policy could lower the shared
>> voltage while the other cluster is still running at a higher frequency.
>
> No, both will vote for the regulator contraints using CPU device and the
> regulator core will make sure it doesn't break any of them. This is what all
> frameworks do, regulator, clk, etc.
>
>> This means they can't use different policies.
>
> This is incorrect.
>
>> From a hardware perspective, the eight cores of the K1 are homogeneous,
>> so using the same policy for them is relatively reasonable.
>
> Right, but this is inefficient. One cluster can be idle, or in low freq mode
> while other can be in higher. They MUST be two policies.

Yes, you're right. Two policies are not inherently unsafe.
The regulator framework handles multi-consumer voting correctly.

The actual problem was using single value opp-microvolt. With one cluster at
a low frequency holding a precise [950000, 950000] on the shared rail, and the
other requesting [1050000, 1050000] for 1.6 GHz, the regulator finds no
intersection:

~ # echo 1600000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
[  544.744195] buck1: Restricting voltage, 1050000-950000uV
[  544.757073] cpu cpu0: _set_opp_voltage: failed to set
              voltage (1050000 1050000 1050000 mV): -22
[  544.771304] cpufreq: __target_index: Failed to change
              cpu frequency: -22

The fix is to use the <target min max> triplet for the lower OPPs so the
regulator always has a valid intersection:

-    cpu_opp_table: opp-table-cpu {
+    cluster0_opp_table: opp-table-cluster0 {
         compatible = "operating-points-v2";
         opp-shared;
         opp-614400000 {
-            opp-microvolt = <950000>;
+            opp-microvolt = <950000 950000 1050000>;
         };
         opp-819000000 {
-            opp-microvolt = <950000>;
+            opp-microvolt = <950000 950000 1050000>;
         };
         ...
         opp-1600000000 {
             opp-microvolt = <1050000>;
         };
     };
+    cluster1_opp_table: opp-table-cluster1 {
+        // same OPP entries and voltage ranges as above
+    };
-    &cpu_0 { operating-points-v2 = <&cpu_opp_table>; };
+    &cpu_0 { operating-points-v2 = <&cluster0_opp_table>; };
     ...
-    &cpu_7 { operating-points-v2 = <&cpu_opp_table>; };
+    &cpu_3 { operating-points-v2 = <&cluster0_opp_table>; };
+    &cpu_4 { operating-points-v2 = <&cluster1_opp_table>; };
     ...
+    &cpu_7 { operating-points-v2 = <&cluster1_opp_table>; };

This way the low frequency cluster accepts up to 1.05 V on the rail.
That is safe: high voltage at low frequency costs power but does not cause
instability.

With two cpufreq-dt policies (one per cluster) and these ranges, neither cluster
blocks the other. Tested on BPI-F3 and OrangePi Rv2 boards, works as expected.

Does this look good to you, or would you prefer a different approach?
>
>> I used a K1-specific driver because cpufreq-dt only manages one CPU clock
>> through the CPU device used for the OPP transition.
>> On K1, the policy needs to control two independent cluster clocks and one shared
>> regulator, so the driver has to update the second cluster clock explicitly and
>> keep the ordering safe: raise voltage before raising either cluster, and lower
>> both cluster clocks before lowering the shared voltage.
>> 
>> [1] https://lore.kernel.org/spacemit/aeaXszeaE62rM6BJ at aurel32.net/

-- 
Best regards,
Shuwei Wu


From pinkesh.vaghela at einfochips.com  Mon Jun 15 05:20:09 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Mon, 15 Jun 2026 17:50:09 +0530
Subject: [PATCH 0/7] riscv: eswin: eic7700: Add support for clocks, resets, pinctrl, HSP power domain, I2C and watchdog
Message-ID: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>

This series extends the ESWIN's EIC7700 SoC support beyond the
already upstreamed basic DTS and DTSI files. It introduces DT nodes
for reset, clock, pinctrl, HSP power domain, I2C and Watchdog.

As support for boot media is yet to be upstreamed, we have
boot-tested this series with initramfs on HiFive Premier P550 board
using Linux 7.1, U-Boot 2024.01 and OpenSBI 1.8.1.

[1]: https://lore.kernel.org/lkml/20251113014656.2605447-1-samuel.holland at sifive.com/

Pinkesh Vaghela (2):
  dt-bindings: mfd: syscon: add ESWIN EIC7700 compatible
  riscv: dts: eswin: add hsp power domain

Pritesh Patel (4):
  riscv: dts: eswin: add reset generator for EIC7700 SoC
  riscv: dts: eswin: add clock generator for EIC7700 SoC
  riscv: dts: eswin: add I2C controller support
  riscv: dts: eswin: add watchdog support

Yulin Lu (1):
  riscv: dts: eswin: eic7700: add pinctrl support

 .../devicetree/bindings/mfd/syscon.yaml       |   2 +
 .../dts/eswin/eic7700-hifive-premier-p550.dts | 182 ++++
 .../riscv/boot/dts/eswin/eic7700-pinctrl.dtsi | 888 ++++++++++++++++++
 arch/riscv/boot/dts/eswin/eic7700.dtsi        | 234 +++++
 4 files changed, 1306 insertions(+)
 create mode 100644 arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi

-- 
2.34.1



From pinkesh.vaghela at einfochips.com  Mon Jun 15 05:20:10 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Mon, 15 Jun 2026 17:50:10 +0530
Subject: [PATCH 1/7] riscv: dts: eswin: add reset generator for EIC7700 SoC
In-Reply-To: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615122016.1110206-2-pinkesh.vaghela@einfochips.com>

From: Pritesh Patel <pritesh.patel at einfochips.com>

Add reset generator node for EIC7700 SoC

Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
---
 arch/riscv/boot/dts/eswin/eic7700.dtsi | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
index c3ed93008bca..430a210f01e6 100644
--- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
+++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
@@ -4,6 +4,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/reset/eswin,eic7700-reset.h>
 
 / {
 	#address-cells = <2>;
@@ -341,5 +342,11 @@ gpioD: gpio-port at 3 {
 				#gpio-cells = <2>;
 			};
 		};
+
+		reset: reset-controller at 51828300 {
+			compatible = "eswin,eic7700-reset";
+			reg = <0x0 0x51828300 0x0 0x200>;
+			#reset-cells = <1>;
+		};
 	};
 };
-- 
2.34.1



From pinkesh.vaghela at einfochips.com  Mon Jun 15 05:20:11 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Mon, 15 Jun 2026 17:50:11 +0530
Subject: [PATCH 2/7] riscv: dts: eswin: add clock generator for EIC7700 SoC
In-Reply-To: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615122016.1110206-3-pinkesh.vaghela@einfochips.com>

From: Pritesh Patel <pritesh.patel at einfochips.com>

Add clock generator node for EIC7700 SoC.
HiFive Premier P550 boards have 24MHz crystal oscillator to provide
the input clock.

Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
---
 .../boot/dts/eswin/eic7700-hifive-premier-p550.dts  |  5 +++++
 arch/riscv/boot/dts/eswin/eic7700.dtsi              | 13 +++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
index 131ed1fc6b2e..1fb92f0e7c55 100644
--- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
+++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
@@ -20,6 +20,11 @@ chosen {
 	};
 };
 
+&xtal {
+	clock-frequency = <24000000>;
+	clock-output-names = "xtal24m";
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
index 430a210f01e6..a7ebb1115958 100644
--- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
+++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
@@ -4,6 +4,7 @@
  */
 
 /dts-v1/;
+#include <dt-bindings/clock/eswin,eic7700-clock.h>
 #include <dt-bindings/reset/eswin,eic7700-reset.h>
 
 / {
@@ -203,6 +204,11 @@ pmu {
 				<0x00000000 0x0000000f 0xfffffffc 0x000000ff 0x00000078>;
 	};
 
+	xtal: oscillator {
+		compatible = "fixed-clock";
+		#clock-cells = <0>;
+	};
+
 	soc {
 		compatible = "simple-bus";
 		ranges;
@@ -343,6 +349,13 @@ gpioD: gpio-port at 3 {
 			};
 		};
 
+		clk: clock-controller at 51828000 {
+			compatible = "eswin,eic7700-clock";
+			reg = <0x0 0x51828000 0x0 0x300>;
+			clocks = <&xtal>;
+			#clock-cells = <1>;
+		};
+
 		reset: reset-controller at 51828300 {
 			compatible = "eswin,eic7700-reset";
 			reg = <0x0 0x51828300 0x0 0x200>;
-- 
2.34.1



From pinkesh.vaghela at einfochips.com  Mon Jun 15 05:20:12 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Mon, 15 Jun 2026 17:50:12 +0530
Subject: [PATCH 3/7] riscv: dts: eswin: eic7700: add pinctrl support
In-Reply-To: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615122016.1110206-4-pinkesh.vaghela@einfochips.com>

From: Yulin Lu <luyulin at eswincomputing.com>

Add pinctrl node and related pin configuration for EIC7700 SoC

Co-developed-by: Pritesh Patel <pritesh.patel at einfochips.com>
Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
Signed-off-by: Yulin Lu <luyulin at eswincomputing.com>
Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
---
 .../dts/eswin/eic7700-hifive-premier-p550.dts | 109 +++
 .../riscv/boot/dts/eswin/eic7700-pinctrl.dtsi | 888 ++++++++++++++++++
 arch/riscv/boot/dts/eswin/eic7700.dtsi        |   5 +
 3 files changed, 1002 insertions(+)
 create mode 100644 arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi

diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
index 1fb92f0e7c55..e7bb96e14958 100644
--- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
+++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
@@ -6,6 +6,7 @@
 /dts-v1/;
 
 #include "eic7700.dtsi"
+#include "eic7700-pinctrl.dtsi"
 
 / {
 	compatible = "sifive,hifive-premier-p550", "eswin,eic7700";
@@ -18,6 +19,15 @@ aliases {
 	chosen {
 		stdout-path = "serial0:115200n8";
 	};
+
+	vcc_1v8: vcc1v8 {
+		 compatible = "regulator-fixed";
+		 regulator-name = "vcc1v8";
+		 regulator-always-on;
+		 regulator-boot-on;
+		 regulator-min-microvolt = <1800000>;
+		 regulator-max-microvolt = <1800000>;
+	 };
 };
 
 &xtal {
@@ -25,6 +35,105 @@ &xtal {
 	clock-output-names = "xtal24m";
 };
 
+&gpio0_pins {
+	bias-disable;
+	input-enable;
+};
+
+&gpio5_pins {
+	bias-disable;
+	input-enable;
+};
+
+&gpio11_pins {
+	bias-disable;
+	input-enable;
+};
+
+&gpio14_pins {
+	bias-pull-up;
+	input-disable;
+};
+
+&gpio15_pins {
+	bias-disable;
+	input-enable;
+};
+
+&gpio28_pins {
+	bias-disable;
+	input-enable;
+};
+
+&gpio43_pins {
+	bias-disable;
+	input-disable;
+};
+
+&gpio71_pins {
+	bias-pull-up;
+	input-disable;
+};
+
+&gpio74_pins {
+	bias-pull-up;
+	input-disable;
+};
+
+&gpio76_pins {
+	bias-disable;
+	input-disable;
+};
+
+&gpio77_pins {
+	bias-pull-up;
+	input-disable;
+};
+
+&gpio79_pins {
+	bias-disable;
+	input-disable;
+};
+
+&gpio80_pins {
+	bias-pull-up;
+	input-disable;
+};
+
+&gpio82_pins {
+	bias-pull-up;
+	input-disable;
+};
+
+&gpio84_pins {
+	bias-disable;
+	input-disable;
+};
+
+&gpio85_pins {
+	bias-pull-up;
+	input-disable;
+};
+
+&gpio94_pins {
+	bias-disable;
+	input-disable;
+};
+
+&gpio106_pins {
+	bias-disable;
+	input-disable;
+};
+
+&gpio111_pins {
+	bias-disable;
+	input-disable;
+};
+
+&pinctrl {
+	vrgmii-supply = <&vcc_1v8>;
+};
+
 &uart0 {
 	status = "okay";
 };
diff --git a/arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi b/arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi
new file mode 100644
index 000000000000..7293df146aa7
--- /dev/null
+++ b/arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi
@@ -0,0 +1,888 @@
+// SPDX-License-Identifier: (GPL-2.0 OR MIT)
+/*
+ * Copyright (c) 2025 Beijing ESWIN Computing Technology Co., Ltd.
+ *
+ * ESWIN's EIC7700 SoC pin-mux and pin-config options are listed as
+ * device tree nodes in this file.
+ *
+ * Authors: Yulin Lu <luyulin at eswincomputing.com>
+ */
+
+&pinctrl{
+	default-pins-grp {
+		sata_act_led_pins: sata-act-led-pins{
+			pins = "gpio27";
+			function = "sata";
+		};
+
+		emmc_led_ctrl_pins: emmc-led-ctrl-pins {
+			pins = "gpio29";
+			function = "emmc";
+		};
+
+		sd0_led_ctrl_pins: sd0-led-ctrl-pins {
+			pins = "gpio34";
+			function = "sdio";
+		};
+
+		sd1_led_ctrl_pins: sd1-led-ctrl-pins {
+			pins = "spi1_d2";
+			function = "sdio";
+		};
+
+		i2c6_pins: i2c6-pins {
+			pins = "uart1_cts", "uart1_rts";
+			function = "i2c";
+		};
+
+		i2c7_pins: i2c7-pins {
+			pins = "uart2_tx", "uart2_rx";
+			function = "i2c";
+		};
+
+		i2c9_pins: i2c9-pins {
+			pins = "spi1_d0", "spi1_d1";
+			function = "i2c";
+		};
+
+		pwm1_pins: pwm1-pins {
+			pins = "spi1_d3";
+			function = "pwm";
+		};
+
+		pwm2_pins: pwm2-pins {
+			pins = "spi1_cs1_n";
+			function = "pwm";
+		};
+
+		mipi_csi_xtrig0_pins: mipi-csi-xtrig0-pins {
+			pins = "gpio92";
+			function = "mipi_csi";
+		};
+
+		mipi_csi_xtrig1_pins: mipi-csi-xtrig1-pins {
+			pins = "gpio93";
+			function = "mipi_csi";
+		};
+
+		dual_spi2_pins: dual-spi2-pins {
+			pins = "spi2_cs0_n", "jtag0_tck", "jtag0_tms", "jtag0_tdi";
+			function = "spi";
+		};
+
+		quad_spi2_pins: quad-spi2-pins {
+			pins = "spi2_cs0_n", "spi2_cs1_n", "jtag0_tck", "jtag0_tms",
+			       "jtag0_tdi", "jtag0_tdo", "gpio5";
+			function = "spi";
+		};
+
+		gpio1_pins: gpio1-pins {
+			pins = "jtag0_tck";
+			function = "gpio";
+		};
+
+		gpio2_pins: gpio2-pins {
+			pins = "jtag0_tms";
+			function = "gpio";
+		};
+
+		gpio3_pins: gpio3-pins {
+			pins = "jtag0_tdi";
+			function = "gpio";
+		};
+
+		gpio4_pins: gpio4-pins {
+			pins = "jtag0_tdo";
+			function = "gpio";
+		};
+
+		gpio6_pins: gpio6-pins {
+			pins = "spi2_cs0_n";
+			function = "gpio";
+		};
+
+		gpio7_pins: gpio7-pins {
+			pins = "jtag1_tck";
+			function = "gpio";
+		};
+
+		gpio8_pins: gpio8-pins {
+			pins = "jtag1_tms";
+			function = "gpio";
+		};
+
+		gpio9_pins: gpio9-pins {
+			pins = "jtag1_tdi";
+			function = "gpio";
+		};
+
+		gpio10_pins: gpio10-pins {
+			pins = "jtag1_tdo";
+			function = "gpio";
+		};
+
+		gpio12_pins: gpio12-pins {
+			pins = "spi2_cs1_n";
+			function = "gpio";
+		};
+
+		gpio13_pins: gpio13-pins {
+			pins = "mode_set0";
+			function = "gpio";
+		};
+
+		gpio14_pins: gpio14-pins {
+			pins = "mode_set1";
+			function = "gpio";
+		};
+
+		gpio15_pins: gpio15-pins {
+			pins = "mode_set2";
+			function = "gpio";
+		};
+
+		gpio16_pins: gpio16-pins {
+			pins = "mode_set3";
+			function = "gpio";
+		};
+
+		gpio17_pins: gpio17-pins {
+			pins = "jtag2_trst";
+			function = "gpio";
+		};
+
+		gpio18_pins: gpio18-pins {
+			pins = "i2s0_bclk";
+			function = "gpio";
+		};
+
+		gpio19_pins: gpio19-pins {
+			pins = "i2s0_wclk";
+			function = "gpio";
+		};
+
+		gpio20_pins: gpio20-pins {
+			pins = "i2s0_sdi";
+			function = "gpio";
+		};
+
+		gpio21_pins: gpio21-pins {
+			pins = "i2s0_sdo";
+			function = "gpio";
+		};
+
+		gpio22_pins: gpio22-pins {
+			pins = "i2s_mclk";
+			function = "gpio";
+		};
+
+		gpio23_pins: gpio23-pins {
+			pins = "i2s2_bclk";
+			function = "gpio";
+		};
+
+		gpio24_pins: gpio24-pins {
+			pins = "i2s2_wclk";
+			function = "gpio";
+		};
+
+		gpio25_pins: gpio25-pins {
+			pins = "i2s2_sdi";
+			function = "gpio";
+		};
+
+		gpio26_pins: gpio26-pins {
+			pins = "i2s2_sdo";
+			function = "gpio";
+		};
+
+		gpio29_pins: gpio29-pins {
+			pins = "gpio29";
+			function = "gpio";
+		};
+
+		gpio30_pins: gpio30-pins {
+			pins = "i2s1_bclk";
+			function = "gpio";
+		};
+
+		gpio31_pins: gpio31-pins {
+			pins = "i2s1_wclk";
+			function = "gpio";
+		};
+
+		gpio32_pins: gpio32-pins {
+			pins = "i2s1_sdi";
+			function = "gpio";
+		};
+
+		gpio33_pins: gpio33-pins {
+			pins = "i2s1_sdo";
+			function = "gpio";
+		};
+
+		gpio34_pins: gpio34-pins {
+			pins = "gpio34";
+			function = "gpio";
+		};
+
+		gpio35_pins: gpio35-pins {
+			pins = "spi1_cs0_n";
+			function = "gpio";
+		};
+
+		gpio36_pins: gpio36-pins {
+			pins = "spi1_clk";
+			function = "gpio";
+		};
+
+		gpio37_pins: gpio37-pins {
+			pins = "spi1_d0";
+			function = "gpio";
+		};
+
+		gpio38_pins: gpio38-pins {
+			pins = "spi1_d1";
+			function = "gpio";
+		};
+
+		gpio39_pins: gpio39-pins {
+			pins = "spi1_d2";
+			function = "gpio";
+		};
+
+		gpio40_pins: gpio40-pins {
+			pins = "spi1_d3";
+			function = "gpio";
+		};
+
+		gpio41_pins: gpio41-pins {
+			pins = "spi1_cs1_n";
+			function = "gpio";
+		};
+
+		gpio42_pins: gpio42-pins {
+			pins = "usb0_pwren";
+			function = "gpio";
+		};
+
+		gpio43_pins: gpio43-pins {
+			pins = "usb1_pwren";
+			function = "gpio";
+		};
+
+		gpio44_pins: gpio44-pins {
+			pins = "i2c0_scl";
+			function = "gpio";
+		};
+
+		gpio45_pins: gpio45-pins {
+			pins = "i2c0_sda";
+			function = "gpio";
+		};
+
+		gpio46_pins: gpio46-pins {
+			pins = "i2c1_scl";
+			function = "gpio";
+		};
+
+		gpio47_pins: gpio47-pins {
+			pins = "i2c1_sda";
+			function = "gpio";
+		};
+
+		gpio48_pins: gpio48-pins {
+			pins = "i2c2_scl";
+			function = "gpio";
+		};
+
+		gpio49_pins: gpio49-pins {
+			pins = "i2c2_sda";
+			function = "gpio";
+		};
+
+		gpio50_pins: gpio50-pins {
+			pins = "i2c3_scl";
+			function = "gpio";
+		};
+
+		gpio51_pins: gpio51-pins {
+			pins = "i2c3_sda";
+			function = "gpio";
+		};
+
+		gpio52_pins: gpio52-pins {
+			pins = "i2c4_scl";
+			function = "gpio";
+		};
+
+		gpio53_pins: gpio53-pins {
+			pins = "i2c4_sda";
+			function = "gpio";
+		};
+
+		gpio54_pins: gpio54-pins {
+			pins = "i2c5_scl";
+			function = "gpio";
+		};
+
+		gpio55_pins: gpio55-pins {
+			pins = "i2c5_sda";
+			function = "gpio";
+		};
+
+		gpio56_pins: gpio56-pins {
+			pins = "uart0_tx";
+			function = "gpio";
+		};
+
+		gpio57_pins: gpio57-pins {
+			pins = "uart0_rx";
+			function = "gpio";
+		};
+
+		gpio58_pins: gpio58-pins {
+			pins = "uart1_tx";
+			function = "gpio";
+		};
+
+		gpio59_pins: gpio59-pins {
+			pins = "uart1_rx";
+			function = "gpio";
+		};
+
+		gpio60_pins: gpio60-pins {
+			pins = "uart1_cts";
+			function = "gpio";
+		};
+
+		gpio61_pins: gpio61-pins {
+			pins = "uart1_rts";
+			function = "gpio";
+		};
+
+		gpio62_pins: gpio62-pins {
+			pins = "uart2_tx";
+			function = "gpio";
+		};
+
+		gpio63_pins: gpio63-pins {
+			pins = "uart2_rx";
+			function = "gpio";
+		};
+
+		gpio64_pins: gpio64-pins {
+			pins = "jtag2_tck";
+			function = "gpio";
+		};
+
+		gpio65_pins: gpio65-pins {
+			pins = "jtag2_tms";
+			function = "gpio";
+		};
+
+		gpio66_pins: gpio66-pins {
+			pins = "jtag2_tdi";
+			function = "gpio";
+		};
+
+		gpio67_pins: gpio67-pins {
+			pins = "jtag2_tdo";
+			function = "gpio";
+		};
+
+		gpio68_pins: gpio68-pins {
+			pins = "fan_pwm";
+			function = "gpio";
+		};
+
+		gpio69_pins: gpio69-pins {
+			pins = "fan_tach";
+			function = "gpio";
+		};
+
+		gpio70_pins: gpio70-pins {
+			pins = "mipi_csi0_xvs";
+			function = "gpio";
+		};
+
+		gpio71_pins: gpio71-pins {
+			pins = "mipi_csi0_xhs";
+			function = "gpio";
+		};
+
+		gpio72_pins: gpio72-pins {
+			pins = "mipi_csi0_mclk";
+			function = "gpio";
+		};
+
+		gpio73_pins: gpio73-pins {
+			pins = "mipi_csi1_xvs";
+			function = "gpio";
+		};
+
+		gpio74_pins: gpio74-pins {
+			pins = "mipi_csi1_xhs";
+			function = "gpio";
+		};
+
+		gpio75_pins: gpio75-pins {
+			pins = "mipi_csi1_mclk";
+			function = "gpio";
+		};
+
+		gpio76_pins: gpio76-pins {
+			pins = "mipi_csi2_xvs";
+			function = "gpio";
+		};
+
+		gpio77_pins: gpio77-pins {
+			pins = "mipi_csi2_xhs";
+			function = "gpio";
+		};
+
+		gpio78_pins: gpio78-pins {
+			pins = "mipi_csi2_mclk";
+			function = "gpio";
+		};
+
+		gpio79_pins: gpio79-pins {
+			pins = "mipi_csi3_xvs";
+			function = "gpio";
+		};
+
+		gpio80_pins: gpio80-pins {
+			pins = "mipi_csi3_xhs";
+			function = "gpio";
+		};
+
+		gpio81_pins: gpio81-pins {
+			pins = "mipi_csi3_mclk";
+			function = "gpio";
+		};
+
+		gpio82_pins: gpio82-pins {
+			pins = "mipi_csi4_xvs";
+			function = "gpio";
+		};
+
+		gpio83_pins: gpio83-pins {
+			pins = "mipi_csi4_xhs";
+			function = "gpio";
+		};
+
+		gpio84_pins: gpio84-pins {
+			pins = "mipi_csi4_mclk";
+			function = "gpio";
+		};
+
+		gpio85_pins: gpio85-pins {
+			pins = "mipi_csi5_xvs";
+			function = "gpio";
+		};
+
+		gpio86_pins: gpio86-pins {
+			pins = "mipi_csi5_xhs";
+			function = "gpio";
+		};
+
+		gpio87_pins: gpio87-pins {
+			pins = "mipi_csi5_mclk";
+			function = "gpio";
+		};
+
+		gpio88_pins: gpio88-pins {
+			pins = "spi3_cs_n";
+			function = "gpio";
+		};
+
+		gpio89_pins: gpio89-pins {
+			pins = "spi3_clk";
+			function = "gpio";
+		};
+
+		gpio90_pins: gpio90-pins {
+			pins = "spi3_di";
+			function = "gpio";
+		};
+
+		gpio91_pins: gpio91-pins {
+			pins = "spi3_do";
+			function = "gpio";
+		};
+
+		gpio92_pins: gpio92-pins {
+			pins = "gpio92";
+			function = "gpio";
+		};
+
+		gpio93_pins: gpio93-pins {
+			pins = "gpio93";
+			function = "gpio";
+		};
+
+		gpio94_pins: gpio94-pins {
+			pins = "s_mode";
+			function = "gpio";
+		};
+
+		gpio95_pins: gpio95-pins {
+			pins = "gpio95";
+			function = "gpio";
+		};
+
+		gpio96_pins: gpio96-pins {
+			pins = "spi0_cs_n";
+			function = "gpio";
+		};
+
+		gpio97_pins: gpio97-pins {
+			pins = "spi0_clk";
+			function = "gpio";
+		};
+
+		gpio98_pins: gpio98-pins {
+			pins = "spi0_d0";
+			function = "gpio";
+		};
+
+		gpio99_pins: gpio99-pins {
+			pins = "spi0_d1";
+			function = "gpio";
+		};
+
+		gpio100_pins: gpio100-pins {
+			pins = "spi0_d2";
+			function = "gpio";
+		};
+
+		gpio101_pins: gpio101-pins {
+			pins = "spi0_d3";
+			function = "gpio";
+		};
+
+		gpio102_pins: gpio102-pins {
+			pins = "i2c10_scl";
+			function = "gpio";
+		};
+
+		gpio103_pins: gpio103-pins {
+			pins = "i2c10_sda";
+			function = "gpio";
+		};
+
+		gpio104_pins: gpio104-pins {
+			pins = "i2c11_scl";
+			function = "gpio";
+		};
+
+		gpio105_pins: gpio105-pins {
+			pins = "i2c11_sda";
+			function = "gpio";
+		};
+
+		gpio107_pins: gpio107-pins {
+			pins = "boot_sel0";
+			function = "gpio";
+		};
+
+		gpio108_pins: gpio108-pins {
+			pins = "boot_sel1";
+			function = "gpio";
+		};
+
+		gpio109_pins: gpio109-pins {
+			pins = "boot_sel2";
+			function = "gpio";
+		};
+
+		gpio110_pins: gpio110-pins {
+			pins = "boot_sel3";
+			function = "gpio";
+		};
+
+		uart3_pins: uart3-pins {
+			pins = "gpio92", "gpio93";
+			function = "uart";
+		};
+
+		uart4_pins: uart4-pins {
+			pins = "spi1_d0", "spi1_d1";
+			function = "uart";
+		};
+
+		gpio0_pins: gpio0-pins {
+			pins = "gpio0";
+			function = "gpio";
+		};
+
+		gpio5_pins: gpio5-pins {
+			pins = "gpio5";
+			function = "gpio";
+		};
+
+		gpio11_pins: gpio11-pins {
+			pins = "gpio11";
+			function = "gpio";
+		};
+
+		gpio27_pins: gpio27-pins {
+			pins = "gpio27";
+			function = "gpio";
+		};
+
+		gpio28_pins: gpio28-pins {
+			pins = "gpio28";
+			function = "gpio";
+		};
+
+		gpio106_pins: gpio106-pins {
+			pins = "gpio106";
+			function = "gpio";
+		};
+
+		gpio111_pins: gpio111-pins {
+			pins = "gpio111";
+			function = "gpio";
+		};
+
+		chip_mode_pins: chip-mode-pins {
+			pins = "chip_mode";
+			function = "chip_mode";
+		};
+
+		sdio0_pins: sdio0-pins {
+			pins = "mode_set0", "mode_set1";
+			function = "sdio";
+		};
+
+		sdio1_pins: sdio1-pins {
+			pins = "mode_set2", "mode_set3";
+			function = "sdio";
+		};
+
+		jtag0_pins: jtag0-pins {
+			pins = "jtag0_tck", "jtag0_tms", "jtag0_tdi", "jtag0_tdo";
+			function = "jtag";
+		};
+
+		jtag1_pins: jtag1-pins {
+			pins = "jtag1_tck", "jtag1_tms", "jtag1_tdi", "jtag1_tdo";
+			function = "jtag";
+		};
+
+		jtag2_pins: jtag2-pins {
+			pins = "jtag2_trst", "jtag2_tck", "jtag2_tms", "jtag2_tdi",
+			       "jtag2_tdo";
+			function = "jtag";
+		};
+
+		pcie_pins: pcie-pins {
+			pins = "pcie_clkreq_n", "pcie_wake_n", "pcie_perst_n";
+			function = "pcie";
+		};
+
+		hdmi_pins: hdmi-pins {
+			pins = "hdmi_scl", "hdmi_sda", "hdmi_cec";
+			function = "hdmi";
+		};
+
+		rgmii0_pins: rgmii0-pins {
+			pins = "rgmii0_clk_125", "rgmii0_txen", "rgmii0_txclk", "rgmii0_txd0",
+			       "rgmii0_txd1", "rgmii0_txd2", "rgmii0_txd3", "rgmii0_rxclk",
+			       "rgmii0_rxdv", "rgmii0_rxd0", "rgmii0_rxd1", "rgmii0_rxd2",
+			       "rgmii0_rxd3", "rgmii0_mdc", "rgmii0_mdio", "rgmii0_intb";
+			function = "hdmi";
+		};
+
+		rgmii1_pins: rgmii1-pins {
+			pins = "rgmii1_clk_125", "rgmii1_txen", "rgmii1_txclk", "rgmii1_txd0",
+			       "rgmii1_txd1", "rgmii1_txd2", "rgmii1_txd3", "rgmii1_rxclk",
+			       "rgmii1_rxdv", "rgmii1_rxd0", "rgmii1_rxd1", "rgmii1_rxd2",
+			       "rgmii1_rxd3", "rgmii1_mdc", "rgmii1_mdio", "rgmii1_intb";
+			function = "hdmi";
+		};
+
+		i2s0_pins: i2s0-pins {
+			pins = "i2s0_bclk", "i2s0_wclk", "i2s0_sdi", "i2s0_sdo", "i2s_mclk";
+			function = "hdmi";
+		};
+
+		i2s1_pins: i2s1-pins {
+			pins = "i2s1_bclk", "i2s1_wclk", "i2s1_sdi", "i2s1_sdo", "i2s_mclk";
+			function = "hdmi";
+		};
+
+		i2s2_pins: i2s2-pins {
+			pins = "i2s2_bclk", "i2s2_wclk", "i2s2_sdi", "i2s2_sdo", "i2s_mclk";
+			function = "hdmi";
+		};
+
+		usb0_pwren_pins: usb0-pwren-pins {
+			pins = "usb0_pwren";
+			function = "usb";
+		};
+
+		usb1_pwren_pins: usb1-pwren-pins {
+			pins = "usb1_pwren";
+			function = "usb";
+		};
+
+		i2c0_pins: i2c0-pins {
+			pins = "i2c0_scl", "i2c0_sda";
+			function = "i2c";
+		};
+
+		i2c1_pins: i2c1-pins {
+			pins = "i2c1_scl", "i2c1_sda";
+			function = "i2c";
+		};
+
+		i2c2_pins: i2c2-pins {
+			pins = "i2c2_scl", "i2c2_sda";
+			function = "i2c";
+		};
+
+		i2c3_pins: i2c3-pins {
+			pins = "i2c3_scl", "i2c3_sda";
+			function = "i2c";
+		};
+
+		i2c4_pins: i2c4-pins {
+			pins = "i2c4_scl", "i2c4_sda";
+			function = "i2c";
+		};
+
+		i2c5_pins: i2c5-pins {
+			pins = "i2c5_scl", "i2c5_sda";
+			function = "i2c";
+		};
+
+		i2c8_pins: i2c8-pins {
+			pins = "gpio92", "gpio93";
+			function = "i2c";
+		};
+
+		i2c10_pins: i2c10-pins {
+			pins = "i2c10_scl", "i2c10_sda";
+			function = "i2c";
+		};
+
+		i2c11_pins: i2c11-pins {
+			pins = "i2c11_scl", "i2c11_sda";
+			function = "i2c";
+		};
+
+		uart0_pins: uart0-pins {
+			pins = "uart0_tx", "uart0_rx";
+			function = "uart";
+		};
+
+		uart1_pins: uart1-pins {
+			pins = "uart1_tx", "uart1_rx", "uart1_cts", "uart1_rts";
+			function = "uart";
+		};
+
+		uart2_pins: uart2-pins {
+			pins = "uart2_tx", "uart2_rx";
+			function = "uart";
+		};
+
+		fan_pwm_pins: fan-pwm-pins {
+			pins = "fan_pwm";
+			function = "pwm";
+		};
+
+		fan_tach_pins: fan-tach-pins {
+			pins = "fan_tach";
+			function = "fan_tach";
+		};
+
+		mipi_csi0_pins: mipi-csi0-pins {
+			pins = "mipi_csi0_xvs", "mipi_csi0_xhs", "mipi_csi0_mclk";
+			function = "mipi_csi";
+		};
+
+		mipi_csi1_pins: mipi-csi1-pins {
+			pins = "mipi_csi1_xvs", "mipi_csi1_xhs", "mipi_csi1_mclk";
+			function = "mipi_csi";
+		};
+
+		mipi_csi2_pins: mipi-csi2-pins {
+			pins = "mipi_csi2_xvs", "mipi_csi2_xhs", "mipi_csi2_mclk";
+			function = "mipi_csi";
+		};
+
+		mipi_csi3_pins: mipi-csi3-pins {
+			pins = "mipi_csi3_xvs", "mipi_csi3_xhs", "mipi_csi3_mclk";
+			function = "mipi_csi";
+		};
+
+		mipi_csi4_pins: mipi-csi4-pins {
+			pins = "mipi_csi4_xvs", "mipi_csi4_xhs", "mipi_csi4_mclk";
+			function = "mipi_csi";
+		};
+
+		mipi_csi5_pins: mipi-csi5-pins {
+			pins = "mipi_csi5_xvs", "mipi_csi5_xhs", "mipi_csi5_mclk";
+			function = "mipi_csi";
+		};
+
+		s_mode_pins: s-mode-pins {
+			pins = "s_mode";
+			function = "s_mode";
+		};
+
+		boot_sel0_pins: boot-sel0-pins {
+			pins = "boot_sel0";
+			function = "boot_sel";
+		};
+
+		boot_sel1_pins: boot-sel1-pins {
+			pins = "boot_sel1";
+			function = "boot_sel";
+		};
+
+		boot_sel2_pins: boot-sel2-pins {
+			pins = "boot_sel2";
+			function = "boot_sel";
+		};
+
+		boot_sel3_pins: boot-sel3-pins {
+			pins = "boot_sel3";
+			function = "boot_sel";
+		};
+
+		ddr_ref_clk_sel_pins: ddr-ref-clk-sel-pins {
+			pins = "gpio95";
+			function = "ddr_ref_clk_sel";
+		};
+
+		lpddr_ref_clk_pins: lpddr-ref-clk-pins {
+			pins = "lpddr_ref_clk";
+			function = "lpddr_ref_clk";
+		};
+
+		spi0_pins: spi0-pins {
+			pins = "spi0_cs_n", "spi0_clk", "spi0_d0", "spi0_d1", "spi0_d2",
+			       "spi0_d3";
+			function = "spi";
+		};
+
+		dual_spi1_pins: dual-spi1-pins {
+			pins = "spi1_cs0_n", "spi1_clk", "spi1_d0", "spi1_d1";
+			function = "spi";
+		};
+
+		quad_spi1_pins: quad-spi1-pins {
+			pins = "spi1_cs0_n", "spi1_cs1_n", "spi1_clk", "spi1_d0", "spi1_d1",
+			       "spi1_d2", "spi1_d3";
+			function = "spi";
+		};
+
+		spi3_pins: spi3-pins {
+			pins = "spi3_cs_n", "spi3_clk", "spi3_di", "spi3_do";
+			function = "spi";
+		};
+	};
+};
diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
index a7ebb1115958..8798c50f7584 100644
--- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
+++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
@@ -349,6 +349,11 @@ gpioD: gpio-port at 3 {
 			};
 		};
 
+		pinctrl: pinctrl at 51600080 {
+			compatible = "eswin,eic7700-pinctrl";
+			reg = <0x0 0x51600080 0x0 0x1fff80>;
+		};
+
 		clk: clock-controller at 51828000 {
 			compatible = "eswin,eic7700-clock";
 			reg = <0x0 0x51828000 0x0 0x300>;
-- 
2.34.1



From pinkesh.vaghela at einfochips.com  Mon Jun 15 05:20:13 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Mon, 15 Jun 2026 17:50:13 +0530
Subject: [PATCH 4/7] dt-bindings: mfd: syscon: add ESWIN EIC7700 compatible
In-Reply-To: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615122016.1110206-5-pinkesh.vaghela@einfochips.com>

Document ESWIN EIC7700 SoC compatible for syscon registers.

Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
---
 Documentation/devicetree/bindings/mfd/syscon.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
index e22867088063..7d3365601249 100644
--- a/Documentation/devicetree/bindings/mfd/syscon.yaml
+++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
@@ -62,6 +62,7 @@ select:
           - cirrus,ep7209-syscon3
           - cnxt,cx92755-uc
           - econet,en751221-chip-scu
+          - eswin,eic7700-syscfg
           - freecom,fsg-cs2-system-controller
           - fsl,imx93-aonmix-ns-syscfg
           - fsl,imx93-wakeupmix-syscfg
@@ -175,6 +176,7 @@ properties:
               - cirrus,ep7209-syscon3
               - cnxt,cx92755-uc
               - econet,en751221-chip-scu
+              - eswin,eic7700-syscfg
               - freecom,fsg-cs2-system-controller
               - fsl,imx93-aonmix-ns-syscfg
               - fsl,imx93-wakeupmix-syscfg
-- 
2.34.1



From pinkesh.vaghela at einfochips.com  Mon Jun 15 05:20:14 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Mon, 15 Jun 2026 17:50:14 +0530
Subject: [PATCH 5/7] riscv: dts: eswin: add hsp power domain
In-Reply-To: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615122016.1110206-6-pinkesh.vaghela@einfochips.com>

HSP CSR is inside the HSP power domain. HSP CFG clock must be enabled
to access the HSP CSR registers.
Add HSP power domain node to manage hsp cfg clock

Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
---
 arch/riscv/boot/dts/eswin/eic7700.dtsi | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
index 8798c50f7584..f8caf39616b2 100644
--- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
+++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
@@ -252,6 +252,19 @@ plic: interrupt-controller at c000000 {
 			#interrupt-cells = <1>;
 		};
 
+		hsp_power_domain: bus at 50400000 {
+			compatible = "simple-pm-bus";
+			ranges = <0x0 0x50400000 0x0 0x50400000 0x0 0xa0000>;
+			clocks = <&clk EIC7700_CLK_GATE_HSP_CFG_CLK>;
+			#address-cells = <2>;
+			#size-cells = <2>;
+
+			hsp_sp_csr: hsp-sp-top-csr at 50440000 {
+				compatible = "eswin,eic7700-syscfg", "syscon";
+				reg = <0x0 0x50440000 0x0 0x2000>;
+			};
+		};
+
 		uart0: serial at 50900000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x0 0x50900000 0x0 0x10000>;
-- 
2.34.1



From pinkesh.vaghela at einfochips.com  Mon Jun 15 05:20:15 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Mon, 15 Jun 2026 17:50:15 +0530
Subject: [PATCH 6/7] riscv: dts: eswin: add I2C controller support
In-Reply-To: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615122016.1110206-7-pinkesh.vaghela@einfochips.com>

From: Pritesh Patel <pritesh.patel at einfochips.com>

Add I2C nodes for EIC7700 SoC.
Also add nodes for corresponding slave devices in dts file and
enable them for HiFive Premier P550 board

Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
---
 .../dts/eswin/eic7700-hifive-premier-p550.dts |  52 ++++++
 arch/riscv/boot/dts/eswin/eic7700.dtsi        | 156 ++++++++++++++++++
 2 files changed, 208 insertions(+)

diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
index e7bb96e14958..0f0c98474c62 100644
--- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
+++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
@@ -130,6 +130,58 @@ &gpio111_pins {
 	input-disable;
 };
 
+&aon_i2c0 {
+	status = "okay";
+
+	eeprom at 50 {
+		compatible = "atmel,24c02";
+		reg = <0x50>;
+	};
+};
+
+&aon_i2c1 {
+	status = "okay";
+
+	pac1934 at 10 {
+		compatible = "microchip,pac1934";
+		reg = <0x10>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+
+		channel at 1 {
+			reg = <0x1>;
+			shunt-resistor-micro-ohms = <1000>;
+			label = "VDD_SOM";
+		};
+
+		channel at 2 {
+			reg = <0x2>;
+			shunt-resistor-micro-ohms = <1000>;
+			label = "VDD_SOC";
+		};
+
+		channel at 3 {
+			reg = <0x3>;
+			shunt-resistor-micro-ohms = <1000>;
+			label = "VDD_CPU";
+		};
+
+		channel at 4 {
+			reg = <0x4>;
+			shunt-resistor-micro-ohms = <1000>;
+			label = "VDD_LPDDR";
+		};
+	};
+
+	ina226 at 44 {
+		compatible = "ti,ina226";
+		reg = <0x44>;
+		#io-channel-cells = <1>;
+		label = "sys_power";
+		shunt-resistor = <1000>;
+	};
+};
+
 &pinctrl {
 	vrgmii-supply = <&vcc_1v8>;
 };
diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
index f8caf39616b2..28706431b2c0 100644
--- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
+++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
@@ -315,6 +315,162 @@ uart4: serial at 50940000 {
 			status = "disabled";
 		};
 
+		i2c0: i2c at 50950000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x50950000 0x0 0x8000>;
+			interrupts = <105>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C0_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c1: i2c at 50960000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x50960000 0x0 0x8000>;
+			interrupts = <106>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C1_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c2: i2c at 50970000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x50970000 0x0 0x8000>;
+			interrupts = <107>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C2_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C2>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c3: i2c at 50980000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x50980000 0x0 0x8000>;
+			interrupts = <108>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C3_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C3>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c4: i2c at 50990000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x50990000 0x0 0x8000>;
+			interrupts = <109>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C4_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C4>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c5: i2c at 509a0000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x509a0000 0x0 0x8000>;
+			interrupts = <110>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C5_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C5>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c6: i2c at 509b0000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x509b0000 0x0 0x8000>;
+			interrupts = <111>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C6_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C6>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c7: i2c at 509c0000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x509c0000 0x0 0x8000>;
+			interrupts = <112>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C7_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C7>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c8: i2c at 509d0000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x509d0000 0x0 0x8000>;
+			interrupts = <113>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C8_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C8>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		i2c9: i2c at 509e0000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x509e0000 0x0 0x8000>;
+			interrupts = <114>;
+			clocks = <&clk EIC7700_CLK_GATE_LSP_I2C9_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_I2C9>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		aon_i2c0: i2c at 51830000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x51830000 0x0 0x8000>;
+			interrupts = <290>;
+			clocks = <&clk EIC7700_CLK_GATE_AON_I2C0_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_ANO0>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
+		aon_i2c1: i2c at 51838000 {
+			compatible = "snps,designware-i2c";
+			reg = <0x0 0x51838000 0x0 0x8000>;
+			interrupts = <291>;
+			clocks = <&clk EIC7700_CLK_GATE_AON_I2C1_PCLK>;
+			clock-names = "ref";
+			clock-frequency = <100000>;
+			resets = <&reset EIC7700_RESET_ANO1>;
+			#address-cells = <1>;
+			#size-cells = <0>;
+			status = "disabled";
+		};
+
 		gpio at 51600000 {
 			compatible = "snps,dw-apb-gpio";
 			reg = <0x0 0x51600000 0x0 0x80>;
-- 
2.34.1



From pinkesh.vaghela at einfochips.com  Mon Jun 15 05:20:16 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Mon, 15 Jun 2026 17:50:16 +0530
Subject: [PATCH 7/7] riscv: dts: eswin: add watchdog support
In-Reply-To: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615122016.1110206-8-pinkesh.vaghela@einfochips.com>

From: Pritesh Patel <pritesh.patel at einfochips.com>

Add watchdog node for ESWIN EIC7700 SoC and enable them for HiFive
Premier P550 board

Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
---
 .../dts/eswin/eic7700-hifive-premier-p550.dts | 16 ++++++++
 arch/riscv/boot/dts/eswin/eic7700.dtsi        | 40 +++++++++++++++++++
 2 files changed, 56 insertions(+)

diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
index 0f0c98474c62..a188a5e1d526 100644
--- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
+++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
@@ -193,3 +193,19 @@ &uart0 {
 &uart2 {
 	status = "okay";
 };
+
+&wdt0 {
+	status = "okay";
+};
+
+&wdt1 {
+	status = "okay";
+};
+
+&wdt2 {
+	status = "okay";
+};
+
+&wdt3 {
+	status = "okay";
+};
diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
index 28706431b2c0..a59a9932be0b 100644
--- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
+++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
@@ -265,6 +265,46 @@ hsp_sp_csr: hsp-sp-top-csr at 50440000 {
 			};
 		};
 
+		wdt0: watchdog at 50800000 {
+			compatible = "snps,dw-wdt";
+			reg = <0x0 0x50800000 0x0 0x4000>;
+			interrupts = <87>;
+			clocks =<&clk EIC7700_CLK_GATE_LSP_WDT0_PCLK>;
+			clock-names = "tclk";
+			resets = <&reset EIC7700_RESET_WDT0>;
+			status = "disabled";
+		};
+
+		wdt1: watchdog at 50804000 {
+			compatible = "snps,dw-wdt";
+			reg = <0x0 0x50804000 0x0 0x4000>;
+			interrupts = <88>;
+			clocks =<&clk EIC7700_CLK_GATE_LSP_WDT1_PCLK>;
+			clock-names = "tclk";
+			resets = <&reset EIC7700_RESET_WDT1>;
+			status = "disabled";
+		};
+
+		wdt2: watchdog at 50808000 {
+			compatible = "snps,dw-wdt";
+			reg = <0x0 0x50808000 0x0 0x4000>;
+			interrupts = <89>;
+			clocks =<&clk EIC7700_CLK_GATE_LSP_WDT2_PCLK>;
+			clock-names = "tclk";
+			resets = <&reset EIC7700_RESET_WDT2>;
+			status = "disabled";
+		};
+
+		wdt3: watchdog at 5080c000 {
+			compatible = "snps,dw-wdt";
+			reg = <0x0 0x5080c000 0x0 0x4000>;
+			interrupts = <90>;
+			clocks =<&clk EIC7700_CLK_GATE_LSP_WDT3_PCLK>;
+			clock-names = "tclk";
+			resets = <&reset EIC7700_RESET_WDT3>;
+			status = "disabled";
+		};
+
 		uart0: serial at 50900000 {
 			compatible = "snps,dw-apb-uart";
 			reg = <0x0 0x50900000 0x0 0x10000>;
-- 
2.34.1



From guoren at kernel.org  Mon Jun 15 05:38:17 2026
From: guoren at kernel.org (Guo Ren)
Date: Mon, 15 Jun 2026 12:38:17 +0000
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
Message-ID: <20260615123821.373248-1-guoren@kernel.org>

Hi Zhanpeng Zhang,

I noticed you posted a similar fix recently. However, I had already
submitted a similar solution back in September 2025 [1]. It would be
great if you could review it. A few concerns with the current patch:

1. Using spin_lock_irqsave in such a small semantic structure is
unnecessary. IRQ protection should be provided by the higher-level
IOMMU driver interfaces. Many existing call sites already handle IRQ
disabling, so adding it here feels redundant and adds avoidable
overhead.

2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
problematic. According to the RISC-V IOMMU specification (Software
Guidelines, ?Reading and writing IOMMU registers?):

> Registers that are 64-bit wide may be accessed using either a 32-bit
> or a 64-bit access.

This clearly requires that any hardware supporting 64-bit MMIO access
must also support 32-bit MMIO access. Therefore, the IOMMU driver should
be built on a 32-bit access base for maximum hardware compatibility.

3. Only performance-monitoring counters require 64-bit IO access or the
high-low-high do-while retry strategy. For ordinary status and control
MMIO registers, a single read is sufficient.

4. Introducing a compile-time Kconfig that forces 32-bit splitting (or
64-bit access) across the entire driver is unnecessary for the vast
majority of registers and would prevent a single kernel Image (or .ko)
from working across all compliant platforms.

I believe the correct approach is to keep the driver on a 32-bit access
foundation (as required by the spec) and apply special 64-bit or
high-low-high handling only to performance-monitoring counters when
justified by data. This preserves broad hardware support without
unnecessary complexity.

What do you think? I?m happy to discuss or collaborate on a cleaner
solution based on the earlier patch [1].

[1]: https://lore.kernel.org/linux-riscv/20250903144217.837448-1-guoren at kernel.org/

Best Regards
  GUO Ren

> Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
> to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
> registers to be accessed using 32-bit accesses, provided the accesses are
> properly aligned and do not span multiple registers.
> 
> Add a config option for such implementations and access 64-bit IOMMU
> registers as paired 32-bit MMIO operations when it is enabled. Serialize
> the paired accesses so the high and low halves cannot interleave with
> another CPU. Full 64-bit register programming writes the high half before
> the low half.
> 
> This option describes the register access width. It is not an RV32 kernel
> mode and does not describe a 32-bit IOMMU architecture.
> 
> Co-developed-by: Xu Lu <luxu.kernel at bytedance.com>
> Signed-off-by: Xu Lu <luxu.kernel at bytedance.com>
> Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com>
> ---
> This is needed for platforms whose RISC-V IOMMU register window does not
> support naturally aligned 64-bit MMIO accesses.
> 
>  drivers/iommu/riscv/Kconfig | 11 ++++++++
>  drivers/iommu/riscv/iommu.c |  4 +++
>  drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
>  3 files changed, 64 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> index b86e5ab94183..54d624b9b2ef 100644
> --- a/drivers/iommu/riscv/Kconfig
> +++ b/drivers/iommu/riscv/Kconfig
> @@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
>  	def_bool y if RISCV_IOMMU && PCI_MSI
>  	help
>  	  Support for the PCIe implementation of RISC-V IOMMU architecture.
> +
> +config RISCV_IOMMU_32BIT_ACCESS
> +	bool "Use 32-bit accesses for RISC-V IOMMU registers"
> +	depends on RISCV_IOMMU
> +	help
> +	  Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> +	  using naturally aligned 64-bit loads and stores.
> +
> +	  When enabled, 64-bit IOMMU registers are accessed as paired
> +	  32-bit MMIO operations. This option does not describe an RV32
> +	  kernel or a 32-bit IOMMU architecture.
> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> index a31f50bbad35..7fa1721b5728 100644
> --- a/drivers/iommu/riscv/iommu.c
> +++ b/drivers/iommu/riscv/iommu.c
> @@ -53,6 +53,10 @@ struct riscv_iommu_devres {
>  	void *addr;
>  };
>  
> +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
> +#endif
> +
>  static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
>  {
>  	struct riscv_iommu_devres *devres = res;
> diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> index 46df79dd5495..ba78ef1858c5 100644
> --- a/drivers/iommu/riscv/iommu.h
> +++ b/drivers/iommu/riscv/iommu.h
> @@ -14,6 +14,9 @@
>  #include <linux/iommu.h>
>  #include <linux/types.h>
>  #include <linux/iopoll.h>
> +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +#include <linux/spinlock.h>
> +#endif
>  
>  #include "iommu-bits.h"
>  
> @@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
>  #define riscv_iommu_readl(iommu, addr) \
>  	readl_relaxed((iommu)->reg + (addr))
>  
> -#define riscv_iommu_readq(iommu, addr) \
> -	readq_relaxed((iommu)->reg + (addr))
> -
>  #define riscv_iommu_writel(iommu, addr, val) \
>  	writel_relaxed((val), (iommu)->reg + (addr))
>  
> +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> +	readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> +			   delay_us, timeout_us)
> +
> +#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> +#define riscv_iommu_readq(iommu, addr) \
> +	readq_relaxed((iommu)->reg + (addr))
> +
>  #define riscv_iommu_writeq(iommu, addr, val) \
>  	writeq_relaxed((val), (iommu)->reg + (addr))
>  
>  #define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
>  	readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
>  			   delay_us, timeout_us)
> +#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
>  
> -#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> -	readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> -			   delay_us, timeout_us)
> +extern raw_spinlock_t riscv_iommu_32bit_access_lock;
> +
> +static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
> +{
> +	u32 lo, hi;
> +	unsigned long flags;
> +
> +	raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> +	do {
> +		hi = readl_relaxed(addr + sizeof(u32));
> +		lo = readl_relaxed(addr);
> +	} while (hi != readl_relaxed(addr + sizeof(u32)));
> +	raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
> +
> +	return ((u64)hi << 32) | (u64)lo;
> +}
> +
> +static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
> +{
> +	unsigned long flags;
> +
> +	raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> +	writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
> +	writel_relaxed((u32)value, addr);
> +	raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
> +}
> +
> +#define riscv_iommu_readq(iommu, addr) \
> +	__riscv_iommu_readq_relaxed((iommu)->reg + (addr))
> +
> +#define riscv_iommu_writeq(iommu, addr, val) \
> +	__riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
> +
> +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> +	readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
> +			   val, cond, delay_us, timeout_us)
> +#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
>  
>  #endif
> -- 
> 2.50.1 (Apple Git-155)


From zhangzhanpeng.jasper at bytedance.com  Mon Jun 15 06:21:52 2026
From: zhangzhanpeng.jasper at bytedance.com (Zhanpeng Zhang)
Date: Mon, 15 Jun 2026 06:21:52 -0700
Subject: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260615105959.136698e8@pumpkin>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com> <20260615105959.136698e8@pumpkin>
Message-ID: <CACnXVndGA+A1Uu1qZ0=AaEuJGrNQZx6iiuRWgLYAZpirE=UfNQ@mail.gmail.com>

Hi David,

Thanks, I agree with your point about the lock and the relaxed accessors.

Guo Ren also pointed me to the earlier discussion on this topic, and I think the
right next step is to align with that thread rather than continue this separate
Kconfig-based patch.

So I will drop this patch.

Thanks,
Zhanpeng

> From: "David Laight"<david.laight.linux at gmail.com>
> Date:? Mon, Jun 15, 2026, 18:00
> Subject:? [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
> To: "Zhanpeng Zhang"<zhangzhanpeng.jasper at bytedance.com>
> Cc: "Tomasz Jeznach"<tjeznach at rivosinc.com>, "Joerg Roedel"<joro at 8bytes.org>, "Will Deacon"<will at kernel.org>, "Robin Murphy"<robin.murphy at arm.com>, "Paul Walmsley"<pjw at kernel.org>, "Palmer Dabbelt"<palmer at dabbelt.com>, "Albert Ou"<aou at eecs.berkeley.edu>, "Alexandre Ghiti"<alex at ghiti.fr>, <iommu at lists.linux.dev>, <linux-riscv at lists.infradead.org>, <linux-kernel at vger.kernel.org>, "Xu Lu"<luxu.kernel at bytedance.com>, <cuiyunhui at bytedance.com>, <yuanzhu at bytedance.com>
> On Mon, 15 Jun 2026 14:48:55 +0800
> Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com> wrote:
>
> > Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
> > to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
> > registers to be accessed using 32-bit accesses, provided the accesses are
> > properly aligned and do not span multiple registers.
> >
> > Add a config option for such implementations and access 64-bit IOMMU
> > registers as paired 32-bit MMIO operations when it is enabled. Serialize
> > the paired accesses so the high and low halves cannot interleave with
> > another CPU. Full 64-bit register programming writes the high half before
> > the low half.
> >
> > This option describes the register access width. It is not an RV32 kernel
> > mode and does not describe a 32-bit IOMMU architecture.
> >
> > Co-developed-by: Xu Lu <luxu.kernel at bytedance.com>
> > Signed-off-by: Xu Lu <luxu.kernel at bytedance.com>
> > Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com>
> > ---
> > This is needed for platforms whose RISC-V IOMMU register window does not
> > support naturally aligned 64-bit MMIO accesses.
> >
> > ?drivers/iommu/riscv/Kconfig | 11 ++++++++
> > ?drivers/iommu/riscv/iommu.c | ?4 +++
> > ?drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
> > ?3 files changed, 64 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> > index b86e5ab94183..54d624b9b2ef 100644
> > --- a/drivers/iommu/riscv/Kconfig
> > +++ b/drivers/iommu/riscv/Kconfig
> > @@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
> > ? ? ? ? ?def_bool y if RISCV_IOMMU && PCI_MSI
> > ? ? ? ? ?help
> > ? ? ? ? ? ?Support for the PCIe implementation of RISC-V IOMMU architecture.
> > +
> > +config RISCV_IOMMU_32BIT_ACCESS
> > + ? ? ? ?bool "Use 32-bit accesses for RISC-V IOMMU registers"
> > + ? ? ? ?depends on RISCV_IOMMU
> > + ? ? ? ?help
> > + ? ? ? ? ?Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> > + ? ? ? ? ?using naturally aligned 64-bit loads and stores.
> > +
> > + ? ? ? ? ?When enabled, 64-bit IOMMU registers are accessed as paired
> > + ? ? ? ? ?32-bit MMIO operations. This option does not describe an RV32
> > + ? ? ? ? ?kernel or a 32-bit IOMMU architecture.
> > diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> > index a31f50bbad35..7fa1721b5728 100644
> > --- a/drivers/iommu/riscv/iommu.c
> > +++ b/drivers/iommu/riscv/iommu.c
> > @@ -53,6 +53,10 @@ struct riscv_iommu_devres {
> > ? ? ? ? ?void *addr;
> > ?};
> >
> > +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
> > +#endif
> > +
> > ?static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
> > ?{
> > ? ? ? ? ?struct riscv_iommu_devres *devres = res;
> > diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> > index 46df79dd5495..ba78ef1858c5 100644
> > --- a/drivers/iommu/riscv/iommu.h
> > +++ b/drivers/iommu/riscv/iommu.h
> > @@ -14,6 +14,9 @@
> > ?#include <linux/iommu.h>
> > ?#include <linux/types.h>
> > ?#include <linux/iopoll.h>
> > +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +#include <linux/spinlock.h>
> > +#endif
> >
> > ?#include "iommu-bits.h"
> >
> > @@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
> > ?#define riscv_iommu_readl(iommu, addr) \
> > ? ? ? ? ?readl_relaxed((iommu)->reg + (addr))
> >
> > -#define riscv_iommu_readq(iommu, addr) \
> > - ? ? ? ?readq_relaxed((iommu)->reg + (addr))
> > -
> > ?#define riscv_iommu_writel(iommu, addr, val) \
> > ? ? ? ? ?writel_relaxed((val), (iommu)->reg + (addr))
> >
> > +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > + ? ? ? ?readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? delay_us, timeout_us)
> > +
> > +#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +#define riscv_iommu_readq(iommu, addr) \
> > + ? ? ? ?readq_relaxed((iommu)->reg + (addr))
> > +
> > ?#define riscv_iommu_writeq(iommu, addr, val) \
> > ? ? ? ? ?writeq_relaxed((val), (iommu)->reg + (addr))
> >
> > ?#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > ? ? ? ? ?readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? delay_us, timeout_us)
> > +#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
> >
> > -#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > - ? ? ? ?readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> > - ? ? ? ? ? ? ? ? ? ? ? ? ? delay_us, timeout_us)
> > +extern raw_spinlock_t riscv_iommu_32bit_access_lock;
> > +
> > +static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
> > +{
> > + ? ? ? ?u32 lo, hi;
> > + ? ? ? ?unsigned long flags;
> > +
> > + ? ? ? ?raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> > + ? ? ? ?do {
> > + ? ? ? ? ? ? ? ?hi = readl_relaxed(addr + sizeof(u32));
> > + ? ? ? ? ? ? ? ?lo = readl_relaxed(addr);
> > + ? ? ? ?} while (hi != readl_relaxed(addr + sizeof(u32)));
> > + ? ? ? ?raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
>
> Why the lock and the loop?
> If you need the loop (for places where the hardware might be changing
> both words?) then there is no need to read 'hi' twice when you loop.
>
> But does it make any sense to be reading the value either while the hardware
> is updating it (does that happen?) or concurrently with a write.
>
>
> > +
> > + ? ? ? ?return ((u64)hi << 32) | (u64)lo;
> > +}
> > +
> > +static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
> > +{
> > + ? ? ? ?unsigned long flags;
> > +
> > + ? ? ? ?raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> > + ? ? ? ?writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
> > + ? ? ? ?writel_relaxed((u32)value, addr);
> > + ? ? ? ?raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
>
> What are you actually locking against?
> I'm pretty sure it doesn't make any sense for two cpu to be writing to the
> same entry at the same time.
>
> Can't the writel_relaxed() be re-ordered, so you aren't guaranteeing they'll
> be done high-low.
> Same with the reads.
>
> ? ? ? ? David
>
> > +}
> > +
> > +#define riscv_iommu_readq(iommu, addr) \
> > + ? ? ? ?__riscv_iommu_readq_relaxed((iommu)->reg + (addr))
> > +
> > +#define riscv_iommu_writeq(iommu, addr, val) \
> > + ? ? ? ?__riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
> > +
> > +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > + ? ? ? ?readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? val, cond, delay_us, timeout_us)
> > +#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
> >
> > ?#endif
>


From zhangzhanpeng.jasper at bytedance.com  Mon Jun 15 06:23:07 2026
From: zhangzhanpeng.jasper at bytedance.com (Zhanpeng Zhang)
Date: Mon, 15 Jun 2026 06:23:07 -0700
Subject: [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260615123821.373248-1-guoren@kernel.org>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com> <20260615123821.373248-1-guoren@kernel.org>
Message-ID: <CACnXVnd-DsP2XGrnDFjuZmm4NOpZ0Hd+5BLpoCsDTTtmuFZHMg@mail.gmail.com>

Hi Guo Ren,

Thanks for the pointer, and sorry that I missed the earlier discussion.

I agree with your concerns. The lock in my v1 is not the right approach, and
David also pointed out the same issue. More importantly, after reading your
comments, I agree that this should not be handled as a separate Kconfig-selected
path.

If the RISC-V IOMMU specification allows 64-bit registers to be accessed with
32-bit MMIO operations, then a generic kernel should be able to support that
without requiring a platform-specific build-time option. So I will drop my v1
and will not continue this separate patch.

I will take a closer look at your earlier proposal and the previous discussion.
If the preferred direction is to make 32-bit register accesses part of the
driver's common register access model, I am happy to help test, review, or
rework patches in that direction.

Best Regards,
Zhanpeng

> From: "Guo Ren"<guoren at kernel.org>
> Date:? Mon, Jun 15, 2026, 20:38
> Subject:? [External] Re: [PATCH v1] iommu/riscv: Support 32-bit register accesses
> To: <zhangzhanpeng.jasper at bytedance.com>
> Cc: <alex at ghiti.fr>, <aou at eecs.berkeley.edu>, <cuiyunhui at bytedance.com>, <iommu at lists.linux.dev>, <joro at 8bytes.org>, <linux-kernel at vger.kernel.org>, <linux-riscv at lists.infradead.org>, <luxu.kernel at bytedance.com>, <palmer at dabbelt.com>, <pjw at kernel.org>, <robin.murphy at arm.com>, <tjeznach at rivosinc.com>, <will at kernel.org>, <yuanzhu at bytedance.com>
> Hi Zhanpeng Zhang,
>
> I noticed you posted a similar fix recently. However, I had already
> submitted a similar solution back in September 2025 [1]. It would be
> great if you could review it. A few concerns with the current patch:
>
> 1. Using spin_lock_irqsave in such a small semantic structure is
> unnecessary. IRQ protection should be provided by the higher-level
> IOMMU driver interfaces. Many existing call sites already handle IRQ
> disabling, so adding it here feels redundant and adds avoidable
> overhead.
>
> 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
> problematic. According to the RISC-V IOMMU specification (Software
> Guidelines, ?Reading and writing IOMMU registers?):
>
> > Registers that are 64-bit wide may be accessed using either a 32-bit
> > or a 64-bit access.
>
> This clearly requires that any hardware supporting 64-bit MMIO access
> must also support 32-bit MMIO access. Therefore, the IOMMU driver should
> be built on a 32-bit access base for maximum hardware compatibility.
>
> 3. Only performance-monitoring counters require 64-bit IO access or the
> high-low-high do-while retry strategy. For ordinary status and control
> MMIO registers, a single read is sufficient.
>
> 4. Introducing a compile-time Kconfig that forces 32-bit splitting (or
> 64-bit access) across the entire driver is unnecessary for the vast
> majority of registers and would prevent a single kernel Image (or .ko)
> from working across all compliant platforms.
>
> I believe the correct approach is to keep the driver on a 32-bit access
> foundation (as required by the spec) and apply special 64-bit or
> high-low-high handling only to performance-monitoring counters when
> justified by data. This preserves broad hardware support without
> unnecessary complexity.
>
> What do you think? I?m happy to discuss or collaborate on a cleaner
> solution based on the earlier patch [1].
>
> [1]: https://lore.kernel.org/linux-riscv/20250903144217.837448-1-guoren at kernel.org/
>
> Best Regards
> ? GUO Ren
>
> > Some RISC-V IOMMU implementations cannot perform 64-bit MMIO accesses
> > to the IOMMU register file. The RISC-V IOMMU architecture allows 64-bit
> > registers to be accessed using 32-bit accesses, provided the accesses are
> > properly aligned and do not span multiple registers.
> >
> > Add a config option for such implementations and access 64-bit IOMMU
> > registers as paired 32-bit MMIO operations when it is enabled. Serialize
> > the paired accesses so the high and low halves cannot interleave with
> > another CPU. Full 64-bit register programming writes the high half before
> > the low half.
> >
> > This option describes the register access width. It is not an RV32 kernel
> > mode and does not describe a 32-bit IOMMU architecture.
> >
> > Co-developed-by: Xu Lu <luxu.kernel at bytedance.com>
> > Signed-off-by: Xu Lu <luxu.kernel at bytedance.com>
> > Signed-off-by: Zhanpeng Zhang <zhangzhanpeng.jasper at bytedance.com>
> > ---
> > This is needed for platforms whose RISC-V IOMMU register window does not
> > support naturally aligned 64-bit MMIO accesses.
> >
> > ?drivers/iommu/riscv/Kconfig | 11 ++++++++
> > ?drivers/iommu/riscv/iommu.c | ?4 +++
> > ?drivers/iommu/riscv/iommu.h | 55 +++++++++++++++++++++++++++++++++----
> > ?3 files changed, 64 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> > index b86e5ab94183..54d624b9b2ef 100644
> > --- a/drivers/iommu/riscv/Kconfig
> > +++ b/drivers/iommu/riscv/Kconfig
> > @@ -22,3 +22,14 @@ config RISCV_IOMMU_PCI
> > ? ? ? ? ?def_bool y if RISCV_IOMMU && PCI_MSI
> > ? ? ? ? ?help
> > ? ? ? ? ? ?Support for the PCIe implementation of RISC-V IOMMU architecture.
> > +
> > +config RISCV_IOMMU_32BIT_ACCESS
> > + ? ? ? ?bool "Use 32-bit accesses for RISC-V IOMMU registers"
> > + ? ? ? ?depends on RISCV_IOMMU
> > + ? ? ? ?help
> > + ? ? ? ? ?Say Y when the RISC-V IOMMU MMIO window cannot be accessed
> > + ? ? ? ? ?using naturally aligned 64-bit loads and stores.
> > +
> > + ? ? ? ? ?When enabled, 64-bit IOMMU registers are accessed as paired
> > + ? ? ? ? ?32-bit MMIO operations. This option does not describe an RV32
> > + ? ? ? ? ?kernel or a 32-bit IOMMU architecture.
> > diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> > index a31f50bbad35..7fa1721b5728 100644
> > --- a/drivers/iommu/riscv/iommu.c
> > +++ b/drivers/iommu/riscv/iommu.c
> > @@ -53,6 +53,10 @@ struct riscv_iommu_devres {
> > ? ? ? ? ?void *addr;
> > ?};
> >
> > +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +DEFINE_RAW_SPINLOCK(riscv_iommu_32bit_access_lock);
> > +#endif
> > +
> > ?static void riscv_iommu_devres_pages_release(struct device *dev, void *res)
> > ?{
> > ? ? ? ? ?struct riscv_iommu_devres *devres = res;
> > diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> > index 46df79dd5495..ba78ef1858c5 100644
> > --- a/drivers/iommu/riscv/iommu.h
> > +++ b/drivers/iommu/riscv/iommu.h
> > @@ -14,6 +14,9 @@
> > ?#include <linux/iommu.h>
> > ?#include <linux/types.h>
> > ?#include <linux/iopoll.h>
> > +#ifdef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +#include <linux/spinlock.h>
> > +#endif
> >
> > ?#include "iommu-bits.h"
> >
> > @@ -69,21 +72,61 @@ void riscv_iommu_disable(struct riscv_iommu_device *iommu);
> > ?#define riscv_iommu_readl(iommu, addr) \
> > ? ? ? ? ?readl_relaxed((iommu)->reg + (addr))
> >
> > -#define riscv_iommu_readq(iommu, addr) \
> > - ? ? ? ?readq_relaxed((iommu)->reg + (addr))
> > -
> > ?#define riscv_iommu_writel(iommu, addr, val) \
> > ? ? ? ? ?writel_relaxed((val), (iommu)->reg + (addr))
> >
> > +#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > + ? ? ? ?readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? delay_us, timeout_us)
> > +
> > +#ifndef CONFIG_RISCV_IOMMU_32BIT_ACCESS
> > +#define riscv_iommu_readq(iommu, addr) \
> > + ? ? ? ?readq_relaxed((iommu)->reg + (addr))
> > +
> > ?#define riscv_iommu_writeq(iommu, addr, val) \
> > ? ? ? ? ?writeq_relaxed((val), (iommu)->reg + (addr))
> >
> > ?#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > ? ? ? ? ?readx_poll_timeout(readq_relaxed, (iommu)->reg + (addr), val, cond, \
> > ? ? ? ? ? ? ? ? ? ? ? ? ? ? delay_us, timeout_us)
> > +#else /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
> >
> > -#define riscv_iommu_readl_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > - ? ? ? ?readx_poll_timeout(readl_relaxed, (iommu)->reg + (addr), val, cond, \
> > - ? ? ? ? ? ? ? ? ? ? ? ? ? delay_us, timeout_us)
> > +extern raw_spinlock_t riscv_iommu_32bit_access_lock;
> > +
> > +static inline u64 __riscv_iommu_readq_relaxed(void __iomem *addr)
> > +{
> > + ? ? ? ?u32 lo, hi;
> > + ? ? ? ?unsigned long flags;
> > +
> > + ? ? ? ?raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> > + ? ? ? ?do {
> > + ? ? ? ? ? ? ? ?hi = readl_relaxed(addr + sizeof(u32));
> > + ? ? ? ? ? ? ? ?lo = readl_relaxed(addr);
> > + ? ? ? ?} while (hi != readl_relaxed(addr + sizeof(u32)));
> > + ? ? ? ?raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
> > +
> > + ? ? ? ?return ((u64)hi << 32) | (u64)lo;
> > +}
> > +
> > +static inline void __riscv_iommu_writeq_relaxed(u64 value, void __iomem *addr)
> > +{
> > + ? ? ? ?unsigned long flags;
> > +
> > + ? ? ? ?raw_spin_lock_irqsave(&riscv_iommu_32bit_access_lock, flags);
> > + ? ? ? ?writel_relaxed((u32)(value >> 32), addr + sizeof(u32));
> > + ? ? ? ?writel_relaxed((u32)value, addr);
> > + ? ? ? ?raw_spin_unlock_irqrestore(&riscv_iommu_32bit_access_lock, flags);
> > +}
> > +
> > +#define riscv_iommu_readq(iommu, addr) \
> > + ? ? ? ?__riscv_iommu_readq_relaxed((iommu)->reg + (addr))
> > +
> > +#define riscv_iommu_writeq(iommu, addr, val) \
> > + ? ? ? ?__riscv_iommu_writeq_relaxed((val), (iommu)->reg + (addr))
> > +
> > +#define riscv_iommu_readq_timeout(iommu, addr, val, cond, delay_us, timeout_us) \
> > + ? ? ? ?readx_poll_timeout(__riscv_iommu_readq_relaxed, (iommu)->reg + (addr), \
> > + ? ? ? ? ? ? ? ? ? ? ? ? ? val, cond, delay_us, timeout_us)
> > +#endif /* CONFIG_RISCV_IOMMU_32BIT_ACCESS */
> >
> > ?#endif
> > --
> > 2.50.1 (Apple Git-155)
>


From mailhol at kernel.org  Mon Jun 15 09:08:56 2026
From: mailhol at kernel.org (Vincent Mailhol)
Date: Mon, 15 Jun 2026 18:08:56 +0200
Subject: [PATCH 00/19] init: discoverable root partitions, a.k.a. an
 omittable "root=" cmdline option
Message-ID: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>

DPS [1] defines GPT partition type UUIDs for OS partitions and
attributes that control whether such partitions should be
automatically discovered. The specification states that:

  The OS can discover and mount the necessary file systems with a
  non-existent or incomplete /etc/fstab file and without the root=
  kernel command line option.

DPS is already implemented in systemd-gpt-auto-generator [2], which,
when embedded in an initrd, indeed allows automatic detection of the
root filesystem through its partition type UUID.

This series adds this discovery feature directly into the kernel so
that people who are not using systemd or not using an initrd can still
benefit from it. The implementation follows the same model as
systemd-gpt-auto-generator:

  - GPT partition type UUIDs are used for automatic discovery policy
    only. No root=PARTTYPEUUID=xxx cmdline option or similar syntax is
    added.

  - The root= cmdline option takes precedence. This prevents unexpected
    behaviour.

  - Only the disk with the active EFI System Partition is scanned, as
    required by DPS. The disk is identified through the Boot Loader
    Interface LoaderDevicePartUUID EFI variable.

The DPS no-auto attribute is also implemented, giving another option for
the user to disable this auto discovery. However, the DPS read-only
attribute is intentionally not enforced. The kernel already mounts the
root filesystem read-only by default unless the command line requests
rw, and user space remains responsible for deciding whether a discovered
root should later be remounted read-write based on DPS metadata and
local policy. The other partition type UUIDs (home, swap, var...) are
also out of scope for the same reason: user space remains responsible
for mounting anything other than the root partition.

Patch 1 adds the ARCH_HAS_DPS_ROOT_PARTITION_TYPE_UUID capability and
the hidden CONFIG_DPS_ROOT_AUTO_DISCOVERY Kconfig symbol used to signal
whether the feature is available. Patches 2 to 12 declare the
ARCH_HAS_DPS_ROOT_PARTITION_TYPE_UUID capability for the supported
architectures and define their architecture-specific root partition type
UUID values in asm/dps_root.h.

Patches 13 to 16 make the GPT partition type UUID and the no-auto
attribute available during early block lookup.

Patch 17 is a small code refactor that prepares for patch 18, which
updates the root mount path so that, when root= is omitted, the kernel
reads LoaderDevicePartUUID and uses the early block lookup
infrastructure to discover the DPS root partition on that disk.

Finally, patch 19 documents this automatic root discovery feature.

Tested with GRUB, which implements the LoaderDevicePartUUID EFI variable
in its bli module [3]. With this, I was able to boot a kernel with a
completely empty cmdline and no initrd.

[1] The Discoverable Partitions Specification (DPS)
Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/

[2] systemd-gpt-auto-generator
Link: https://www.freedesktop.org/software/systemd/man/latest/systemd-gpt-auto-generator.html

[3] GRUB -- ?16.2 bli
Link: https://www.gnu.org/software/grub/manual/grub/html_node/bli_005fmodule.html

Signed-off-by: Vincent Mailhol <mailhol at kernel.org>
---
Vincent Mailhol (19):
      init: add DPS root partition type UUID capability
      alpha: define DPS root partition type UUID
      arc: define DPS root partition type UUID
      arm: define DPS root partition type UUID
      arm64: define DPS root partition type UUID
      loongarch: define DPS root partition type UUID
      mips: define DPS root partition type UUIDs
      parisc: define DPS root partition type UUID
      powerpc: define DPS root partition type UUIDs
      riscv: define DPS root partition type UUIDs
      s390: define DPS root partition type UUIDs
      x86: define DPS root partition type UUIDs
      block: store GPT partition type UUID
      block: add early_lookup_bdev_by_type_uuid()
      block: store GPT attributes as a raw value
      block: don't discover partition with DPS no-auto GPT attribute
      init: factor out root device lookup into lookup_root_device()
      init: discover root by DPS partition type UUID
      docs: document discoverable root partitions

 Documentation/admin-guide/discoverable-root.rst | 33 +++++++++
 Documentation/admin-guide/index.rst             |  1 +
 Documentation/admin-guide/kernel-parameters.txt |  5 ++
 arch/alpha/Kconfig                              |  1 +
 arch/alpha/include/asm/dps_root.h               |  8 +++
 arch/arc/Kconfig                                |  1 +
 arch/arc/include/asm/dps_root.h                 |  8 +++
 arch/arm/Kconfig                                |  1 +
 arch/arm/include/asm/dps_root.h                 |  8 +++
 arch/arm64/Kconfig                              |  1 +
 arch/arm64/include/asm/dps_root.h               |  8 +++
 arch/loongarch/Kconfig                          |  1 +
 arch/loongarch/include/asm/dps_root.h           |  8 +++
 arch/mips/Kconfig                               |  1 +
 arch/mips/include/asm/dps_root.h                | 20 ++++++
 arch/parisc/Kconfig                             |  1 +
 arch/parisc/include/asm/dps_root.h              |  8 +++
 arch/powerpc/Kconfig                            |  1 +
 arch/powerpc/include/asm/dps_root.h             | 16 +++++
 arch/riscv/Kconfig                              |  1 +
 arch/riscv/include/asm/dps_root.h               | 12 ++++
 arch/s390/Kconfig                               |  1 +
 arch/s390/include/asm/dps_root.h                | 12 ++++
 arch/x86/Kconfig                                |  1 +
 arch/x86/include/asm/dps_root.h                 | 12 ++++
 block/blk.h                                     |  1 +
 block/early-lookup.c                            | 68 +++++++++++++++++-
 block/partitions/core.c                         |  2 +
 block/partitions/efi.c                          |  3 +
 block/partitions/efi.h                          | 11 ++-
 include/linux/blk_types.h                       |  1 +
 include/linux/blkdev.h                          |  5 ++
 include/linux/root_dev.h                        |  6 ++
 init/Kconfig                                    |  6 ++
 init/do_mounts.c                                | 94 ++++++++++++++++++++++++-
 35 files changed, 355 insertions(+), 12 deletions(-)
---
base-commit: 36808d5e983985bbda87e01059cccc071fe3ec8d
change-id: 20260611-discoverable-root_partitions-bdacbada570d

Best regards,
-- 
Vincent Mailhol <mailhol at kernel.org>



From mailhol at kernel.org  Mon Jun 15 09:09:06 2026
From: mailhol at kernel.org (Vincent Mailhol)
Date: Mon, 15 Jun 2026 18:09:06 +0200
Subject: [PATCH 10/19] riscv: define DPS root partition type UUIDs
In-Reply-To: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>
References: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>
Message-ID: <20260615-discoverable-root_partitions-v1-10-39c78fac42e2@kernel.org>

DPS [1] assigns GPT partition type UUIDs to operating system partitions.
Root partitions use architecture-specific type UUIDs so the OS can
discover the intended root filesystem without relying on a root= cmdline
option.

Define DPS_ROOT_PARTITION_TYPE_UUID in asm/dps_root.h for the RISC-V
32/64-bit variants described by the specification and select
ARCH_HAS_DPS_ROOT_PARTITION_TYPE_UUID.

[1] The Discoverable Partitions Specification (DPS)
Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/

Cc: Paul Walmsley <pjw at kernel.org>
Cc: Palmer Dabbelt <palmer at dabbelt.com>
Cc: Albert Ou <aou at eecs.berkeley.edu>
Cc: linux-riscv at lists.infradead.org
Signed-off-by: Vincent Mailhol <mailhol at kernel.org>
---
 arch/riscv/Kconfig                |  1 +
 arch/riscv/include/asm/dps_root.h | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index 1a2fadccd4c4..526be67e858a 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -28,6 +28,7 @@ config RISCV
 	select ARCH_HAS_DEBUG_VIRTUAL if MMU
 	select ARCH_HAS_DEBUG_VM_PGTABLE
 	select ARCH_HAS_DEBUG_WX
+	select ARCH_HAS_DPS_ROOT_PARTITION_TYPE_UUID
 	select ARCH_HAS_ELF_CORE_EFLAGS if BINFMT_ELF && ELF_CORE
 	select ARCH_HAS_FAST_MULTIPLIER
 	select ARCH_HAS_FORTIFY_SOURCE
diff --git a/arch/riscv/include/asm/dps_root.h b/arch/riscv/include/asm/dps_root.h
new file mode 100644
index 000000000000..86f8e1dbd6ad
--- /dev/null
+++ b/arch/riscv/include/asm/dps_root.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+
+#ifndef _ASM_RISCV_DPS_ROOT_H
+#define _ASM_RISCV_DPS_ROOT_H
+
+#ifdef CONFIG_64BIT
+#define DPS_ROOT_PARTITION_TYPE_UUID "72ec70a6-cf74-40e6-bd49-4bda08e8f224"
+#else
+#define DPS_ROOT_PARTITION_TYPE_UUID "60d5a7fe-8e7d-435c-b714-3dd8162144e1"
+#endif
+
+#endif /* _ASM_RISCV_DPS_ROOT_H */

-- 
2.53.0



From hal.feng at starfivetech.com  Mon Jun 15 08:57:57 2026
From: hal.feng at starfivetech.com (Hal Feng)
Date: Mon, 15 Jun 2026 23:57:57 +0800
Subject: [PATCH v19 1/3] dt-bindings: pwm: opencores: Update compatibles, examples and maintainers
In-Reply-To: <20260615155759.129210-1-hal.feng@starfivetech.com>
References: <20260615155759.129210-1-hal.feng@starfivetech.com>
Message-ID: <20260615155759.129210-2-hal.feng@starfivetech.com>

Remove the jh8100 compatible since the JH8100 SoC has been canceled and
will not be released. Add the jhb100 compatible to replace it.
Use a oneOf construct to support the single-string opencores,pwm-v1
compatible.

Change the register size in examples to 0x10, since an OpenCores PTC IP
has only 4 32-bit registers: CNTR, HRC, LRC and CTRL.

I will maintain this pwm module in place of William.

Signed-off-by: Hal Feng <hal.feng at starfivetech.com>
---
 .../devicetree/bindings/pwm/opencores,pwm.yaml   | 16 +++++++++-------
 1 file changed, 9 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml b/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
index 52a59d245cdb..5f05606a2d3d 100644
--- a/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
+++ b/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: OpenCores PWM controller
 
 maintainers:
-  - William Qiu <william.qiu at starfivetech.com>
+  - Hal Feng <hal.feng at starfivetech.com>
 
 description:
   The OpenCores PTC ip core contains a PWM controller. When operating in PWM
@@ -19,12 +19,14 @@ allOf:
 
 properties:
   compatible:
-    items:
-      - enum:
-          - starfive,jh7100-pwm
-          - starfive,jh7110-pwm
-          - starfive,jh8100-pwm
+    oneOf:
       - const: opencores,pwm-v1
+      - items:
+        - enum:
+            - starfive,jh7100-pwm
+            - starfive,jh7110-pwm
+            - starfive,jhb100-pwm
+        - const: opencores,pwm-v1
 
   reg:
     maxItems: 1
@@ -49,7 +51,7 @@ examples:
   - |
     pwm at 12490000 {
         compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
-        reg = <0x12490000 0x10000>;
+        reg = <0x12490000 0x10>;
         clocks = <&clkgen 181>;
         resets = <&rstgen 109>;
         #pwm-cells = <3>;
-- 
2.43.2



From hal.feng at starfivetech.com  Mon Jun 15 08:57:58 2026
From: hal.feng at starfivetech.com (Hal Feng)
Date: Mon, 15 Jun 2026 23:57:58 +0800
Subject: [PATCH v19 2/3] riscv: dts: starfive: Correct pwm nodes
In-Reply-To: <20260615155759.129210-1-hal.feng@starfivetech.com>
References: <20260615155759.129210-1-hal.feng@starfivetech.com>
Message-ID: <20260615155759.129210-3-hal.feng@starfivetech.com>

Each of the StarFive JH7100/JH7110 SoCs has 8 OpenCores PTC IP
cores. One OpenCores PTC IP core can output one PWM channel.
Change the register size to 0x10, since an OpenCores PTC IP
has only 4 32-bit registers: CNTR, HRC, LRC and CTRL.

Signed-off-by: Hal Feng <hal.feng at starfivetech.com>
---
 .../boot/dts/starfive/jh7100-common.dtsi      | 28 ++++++--
 arch/riscv/boot/dts/starfive/jh7100.dtsi      | 67 ++++++++++++++++++-
 .../boot/dts/starfive/jh7110-common.dtsi      | 27 ++++++--
 .../boot/dts/starfive/jh7110-milkv-mars.dts   |  6 +-
 .../dts/starfive/jh7110-milkv-marscm.dtsi     |  6 +-
 .../dts/starfive/jh7110-pine64-star64.dts     |  6 +-
 .../jh7110-starfive-visionfive-2-lite.dtsi    |  6 +-
 .../jh7110-starfive-visionfive-2.dtsi         |  6 +-
 arch/riscv/boot/dts/starfive/jh7110.dtsi      | 67 ++++++++++++++++++-
 9 files changed, 198 insertions(+), 21 deletions(-)

diff --git a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
index ae1a6aeb0aea..85106545090e 100644
--- a/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7100-common.dtsi
@@ -199,13 +199,23 @@ GPO_I2C2_PAD_SDA_OEN,
 		};
 	};
 
-	pwm_pins: pwm-0 {
-		pwm-pins {
+	pwm0_pins: pwm0-0 {
+		pwm0-pins {
 			pinmux = <GPIOMUX(7,
 				  GPO_PWM_PAD_OUT_BIT0,
 				  GPO_PWM_PAD_OE_N_BIT0,
-				  GPI_NONE)>,
-				 <GPIOMUX(5,
+				  GPI_NONE)>;
+			bias-disable;
+			drive-strength = <35>;
+			input-disable;
+			input-schmitt-disable;
+			slew-rate = <0>;
+		};
+	};
+
+	pwm1_pins: pwm1-0 {
+		pwm1-pins {
+			pinmux =  <GPIOMUX(5,
 				  GPO_PWM_PAD_OUT_BIT1,
 				  GPO_PWM_PAD_OE_N_BIT1,
 				  GPI_NONE)>;
@@ -359,9 +369,15 @@ &osc_aud {
 	clock-frequency = <27000000>;
 };
 
-&pwm {
+&pwm0 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm0_pins>;
+	status = "okay";
+};
+
+&pwm1 {
 	pinctrl-names = "default";
-	pinctrl-0 = <&pwm_pins>;
+	pinctrl-0 = <&pwm1_pins>;
 	status = "okay";
 };
 
diff --git a/arch/riscv/boot/dts/starfive/jh7100.dtsi b/arch/riscv/boot/dts/starfive/jh7100.dtsi
index 7de0732b8eab..90438df1f74d 100644
--- a/arch/riscv/boot/dts/starfive/jh7100.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7100.dtsi
@@ -360,9 +360,72 @@ watchdog at 12480000 {
 				 <&rstgen JH7100_RSTN_WDT>;
 		};
 
-		pwm: pwm at 12490000 {
+		pwm0: pwm at 12490000 {
 			compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
-			reg = <0x0 0x12490000 0x0 0x10000>;
+			reg = <0x0 0x12490000 0x0 0x10>;
+			clocks = <&clkgen JH7100_CLK_PWM_APB>;
+			resets = <&rstgen JH7100_RSTN_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm1: pwm at 12490010 {
+			compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x12490010 0x0 0x10>;
+			clocks = <&clkgen JH7100_CLK_PWM_APB>;
+			resets = <&rstgen JH7100_RSTN_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm2: pwm at 12490020 {
+			compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x12490020 0x0 0x10>;
+			clocks = <&clkgen JH7100_CLK_PWM_APB>;
+			resets = <&rstgen JH7100_RSTN_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm3: pwm at 12490030 {
+			compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x12490030 0x0 0x10>;
+			clocks = <&clkgen JH7100_CLK_PWM_APB>;
+			resets = <&rstgen JH7100_RSTN_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm4: pwm at 12498000 {
+			compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x12498000 0x0 0x10>;
+			clocks = <&clkgen JH7100_CLK_PWM_APB>;
+			resets = <&rstgen JH7100_RSTN_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm5: pwm at 12498010 {
+			compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x12498010 0x0 0x10>;
+			clocks = <&clkgen JH7100_CLK_PWM_APB>;
+			resets = <&rstgen JH7100_RSTN_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm6: pwm at 12498020 {
+			compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x12498020 0x0 0x10>;
+			clocks = <&clkgen JH7100_CLK_PWM_APB>;
+			resets = <&rstgen JH7100_RSTN_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm7: pwm at 12498030 {
+			compatible = "starfive,jh7100-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x12498030 0x0 0x10>;
 			clocks = <&clkgen JH7100_CLK_PWM_APB>;
 			resets = <&rstgen JH7100_RSTN_PWM_APB>;
 			#pwm-cells = <3>;
diff --git a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi
index a7a1c09a2c90..64de468f2c31 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-common.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110-common.dtsi
@@ -326,9 +326,14 @@ uboot at 100000 {
 	};
 };
 
-&pwm {
+&pwm0 {
 	pinctrl-names = "default";
-	pinctrl-0 = <&pwm_pins>;
+	pinctrl-0 = <&pwm0_pins>;
+};
+
+&pwm1 {
+	pinctrl-names = "default";
+	pinctrl-0 = <&pwm1_pins>;
 };
 
 &spi0 {
@@ -528,12 +533,22 @@ GPOEN_ENABLE,
 		};
 	};
 
-	pwm_pins: pwm-0 {
-		pwm-pins {
+	pwm0_pins: pwm0-0 {
+		pwm0-pins {
 			pinmux = <GPIOMUX(46, GPOUT_SYS_PWM_CHANNEL0,
 					      GPOEN_SYS_PWM0_CHANNEL0,
-					      GPI_NONE)>,
-				 <GPIOMUX(59, GPOUT_SYS_PWM_CHANNEL1,
+					      GPI_NONE)>;
+			bias-disable;
+			drive-strength = <12>;
+			input-disable;
+			input-schmitt-disable;
+			slew-rate = <0>;
+		};
+	};
+
+	pwm1_pins: pwm1-0 {
+		pwm1-pins {
+			pinmux = <GPIOMUX(59, GPOUT_SYS_PWM_CHANNEL1,
 					      GPOEN_SYS_PWM0_CHANNEL1,
 					      GPI_NONE)>;
 			bias-disable;
diff --git a/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts b/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts
index 21873612d993..54013c70f4b4 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts
+++ b/arch/riscv/boot/dts/starfive/jh7110-milkv-mars.dts
@@ -68,7 +68,11 @@ &phy0 {
 	motorcomm,tx-clk-adj-enabled;
 };
 
-&pwm {
+&pwm0 {
+	status = "okay";
+};
+
+&pwm1 {
 	status = "okay";
 };
 
diff --git a/arch/riscv/boot/dts/starfive/jh7110-milkv-marscm.dtsi b/arch/riscv/boot/dts/starfive/jh7110-milkv-marscm.dtsi
index 025471061d43..31afac27b86d 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-milkv-marscm.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110-milkv-marscm.dtsi
@@ -87,7 +87,11 @@ &phy0 {
 	motorcomm,tx-clk-adj-enabled;
 };
 
-&pwm {
+&pwm0 {
+	status = "okay";
+};
+
+&pwm1 {
 	status = "okay";
 };
 
diff --git a/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts b/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts
index aec7ae3d1f5b..a9e82f25efde 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts
+++ b/arch/riscv/boot/dts/starfive/jh7110-pine64-star64.dts
@@ -95,7 +95,11 @@ &phy1 {
 	motorcomm,tx-clk-100-inverted;
 };
 
-&pwm {
+&pwm0 {
+	status = "okay";
+};
+
+&pwm1 {
 	status = "okay";
 };
 
diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-lite.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-lite.dtsi
index f8797a666dbf..85b56a72dff7 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-lite.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2-lite.dtsi
@@ -74,7 +74,11 @@ &phy0 {
 	tx-internal-delay-ps = <1500>;
 };
 
-&pwm {
+&pwm0 {
+	status = "okay";
+};
+
+&pwm1 {
 	status = "okay";
 };
 
diff --git a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
index edc8f4588133..35208f95cd3d 100644
--- a/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110-starfive-visionfive-2.dtsi
@@ -73,7 +73,11 @@ &pcie1 {
 	status = "okay";
 };
 
-&pwm {
+&pwm0 {
+	status = "okay";
+};
+
+&pwm1 {
 	status = "okay";
 };
 
diff --git a/arch/riscv/boot/dts/starfive/jh7110.dtsi b/arch/riscv/boot/dts/starfive/jh7110.dtsi
index 9c3e4598747e..82ea63f715b0 100644
--- a/arch/riscv/boot/dts/starfive/jh7110.dtsi
+++ b/arch/riscv/boot/dts/starfive/jh7110.dtsi
@@ -846,9 +846,72 @@ i2stx1: i2s at 120c0000 {
 			status = "disabled";
 		};
 
-		pwm: pwm at 120d0000 {
+		pwm0: pwm at 120d0000 {
 			compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
-			reg = <0x0 0x120d0000 0x0 0x10000>;
+			reg = <0x0 0x120d0000 0x0 0x10>;
+			clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
+			resets = <&syscrg JH7110_SYSRST_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm1: pwm at 120d0010 {
+			compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x120d0010 0x0 0x10>;
+			clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
+			resets = <&syscrg JH7110_SYSRST_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm2: pwm at 120d0020 {
+			compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x120d0020 0x0 0x10>;
+			clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
+			resets = <&syscrg JH7110_SYSRST_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm3: pwm at 120d0030 {
+			compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x120d0030 0x0 0x10>;
+			clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
+			resets = <&syscrg JH7110_SYSRST_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm4: pwm at 120d8000 {
+			compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x120d8000 0x0 0x10>;
+			clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
+			resets = <&syscrg JH7110_SYSRST_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm5: pwm at 120d8010 {
+			compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x120d8010 0x0 0x10>;
+			clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
+			resets = <&syscrg JH7110_SYSRST_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm6: pwm at 120d8020 {
+			compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x120d8020 0x0 0x10>;
+			clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
+			resets = <&syscrg JH7110_SYSRST_PWM_APB>;
+			#pwm-cells = <3>;
+			status = "disabled";
+		};
+
+		pwm7: pwm at 120d8030 {
+			compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
+			reg = <0x0 0x120d8030 0x0 0x10>;
 			clocks = <&syscrg JH7110_SYSCLK_PWM_APB>;
 			resets = <&syscrg JH7110_SYSRST_PWM_APB>;
 			#pwm-cells = <3>;
-- 
2.43.2



From hal.feng at starfivetech.com  Mon Jun 15 08:57:56 2026
From: hal.feng at starfivetech.com (Hal Feng)
Date: Mon, 15 Jun 2026 23:57:56 +0800
Subject: [PATCH v19 0/3] Add OpenCores PTC PWM support
Message-ID: <20260615155759.129210-1-hal.feng@starfivetech.com>

Add OpenCores PTC PWM driver which is used in StarFive
JH7100/JH7110/JHB100 SoC.

I will maintain this pwm module in place of William.

Changes since v18:
- Address Sashiko AI review comments for the OpenCores PWM driver.
- Fix runtime PM usage count handling on probe, error paths, PWM release
  and driver teardown.
- Reject period or duty cycle values below the hardware minimum.
- Restore PWM registers across system sleep resume.
- Return the real error from devm_pwmchip_alloc().
- Preserve bootloader-configured PWM state during probe and keep runtime
  PM active if the PWM is already enabled.
- Use synchronous runtime PM put before possible teardown.

Changes since v17:
- Simplify the code. Make it more readable.
- Restructure the driver to register the pwm chip for one pwm channel,
  because each OpenCores PTC IP core only supports one PWM channel.
  Drop starfive compatibles.
  Add patches to fix the dt-bindings and device tree.
- Support runtime pm and system sleep pm.
- Disable the pwm module and reset the pwm counter before updating the
  period and duty cycle.
- Improve the descriptions.
- Update the dt-bindings maintainer to Hal Feng.

History:
v18: https://lore.kernel.org/all/20260515054723.25024-1-hal.feng at starfivetech.com/
v17: https://lore.kernel.org/all/20250106103540.10079-1-william.qiu at starfivetech.com/

Hal Feng (3):
  dt-bindings: pwm: opencores: Update compatibles, examples and
    maintainers
  riscv: dts: starfive: Correct pwm nodes
  pwm: Add OpenCores PTC PWM driver

 .../bindings/pwm/opencores,pwm.yaml           |  16 +-
 MAINTAINERS                                   |   6 +
 .../boot/dts/starfive/jh7100-common.dtsi      |  28 +-
 arch/riscv/boot/dts/starfive/jh7100.dtsi      |  67 +++-
 .../boot/dts/starfive/jh7110-common.dtsi      |  27 +-
 .../boot/dts/starfive/jh7110-milkv-mars.dts   |   6 +-
 .../dts/starfive/jh7110-milkv-marscm.dtsi     |   6 +-
 .../dts/starfive/jh7110-pine64-star64.dts     |   6 +-
 .../jh7110-starfive-visionfive-2-lite.dtsi    |   6 +-
 .../jh7110-starfive-visionfive-2.dtsi         |   6 +-
 arch/riscv/boot/dts/starfive/jh7110.dtsi      |  67 +++-
 drivers/pwm/Kconfig                           |  12 +
 drivers/pwm/Makefile                          |   1 +
 drivers/pwm/pwm-ocores.c                      | 312 ++++++++++++++++++
 14 files changed, 538 insertions(+), 28 deletions(-)
 create mode 100644 drivers/pwm/pwm-ocores.c


base-commit: 95e56f0f293ef797123eb032f78f5b5d56a035a6
-- 
2.43.2



From hal.feng at starfivetech.com  Mon Jun 15 08:57:59 2026
From: hal.feng at starfivetech.com (Hal Feng)
Date: Mon, 15 Jun 2026 23:57:59 +0800
Subject: [PATCH v19 3/3] pwm: Add OpenCores PTC PWM driver
In-Reply-To: <20260615155759.129210-1-hal.feng@starfivetech.com>
References: <20260615155759.129210-1-hal.feng@starfivetech.com>
Message-ID: <20260615155759.129210-4-hal.feng@starfivetech.com>

Add PWM driver for OpenCores PTC IP core.

Signed-off-by: Hal Feng <hal.feng at starfivetech.com>
---
 MAINTAINERS              |   6 +
 drivers/pwm/Kconfig      |  12 ++
 drivers/pwm/Makefile     |   1 +
 drivers/pwm/pwm-ocores.c | 312 +++++++++++++++++++++++++++++++++++++++
 4 files changed, 331 insertions(+)
 create mode 100644 drivers/pwm/pwm-ocores.c

diff --git a/MAINTAINERS b/MAINTAINERS
index 0d94420eae3d..b6a004f2e6c6 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -20035,6 +20035,12 @@ F:	Documentation/i2c/busses/i2c-ocores.rst
 F:	drivers/i2c/busses/i2c-ocores.c
 F:	include/linux/platform_data/i2c-ocores.h
 
+OPENCORES PWM DRIVER
+M:	Hal Feng <hal.feng at starfivetech.com>
+S:	Supported
+F:	Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
+F:	drivers/pwm/pwm-ocores.c
+
 OPENRISC ARCHITECTURE
 M:	Jonas Bonn <jonas at southpole.se>
 M:	Stefan Kristiansson <stefan.kristiansson at saunalahti.fi>
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index 6f3147518376..dd7f3bf5c3eb 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -534,6 +534,18 @@ config PWM_NTXEC
 	  controller found in certain e-book readers designed by the original
 	  design manufacturer Netronix.
 
+config PWM_OCORES
+	tristate "OpenCores PTC PWM support"
+	depends on HAS_IOMEM && OF
+	depends on COMMON_CLK
+	depends on ARCH_STARFIVE || COMPILE_TEST
+	help
+	  PWM driver for OpenCores PTC IP core.
+	  For details see https://opencores.org/projects/ptc.
+
+	  To compile this driver as a module, choose M here: the module
+	  will be called pwm-ocores.
+
 config PWM_OMAP_DMTIMER
 	tristate "OMAP Dual-Mode Timer PWM support"
 	depends on OF
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 0dc0d2b69025..2d47bad7bd74 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -47,6 +47,7 @@ obj-$(CONFIG_PWM_MICROCHIP_CORE)	+= pwm-microchip-core.o
 obj-$(CONFIG_PWM_MTK_DISP)	+= pwm-mtk-disp.o
 obj-$(CONFIG_PWM_MXS)		+= pwm-mxs.o
 obj-$(CONFIG_PWM_NTXEC)		+= pwm-ntxec.o
+obj-$(CONFIG_PWM_OCORES)	+= pwm-ocores.o
 obj-$(CONFIG_PWM_OMAP_DMTIMER)	+= pwm-omap-dmtimer.o
 obj-$(CONFIG_PWM_PCA9685)	+= pwm-pca9685.o
 obj-$(CONFIG_PWM_PXA)		+= pwm-pxa.o
diff --git a/drivers/pwm/pwm-ocores.c b/drivers/pwm/pwm-ocores.c
new file mode 100644
index 000000000000..b126933d9922
--- /dev/null
+++ b/drivers/pwm/pwm-ocores.c
@@ -0,0 +1,312 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * OpenCores PTC PWM Driver
+ *
+ * https://opencores.org/projects/ptc
+ *
+ * Copyright (C) 2018-2026 StarFive Technology Co., Ltd.
+ *
+ * Limitations:
+ * - The hardware only supports inverted polarity.
+ * - The hardware minimum period / duty_cycle of PWM is (1 / pwm_apb clock frequency).
+ * - The hardware maximum period / duty_cycle of PWM is (U32_MAX / pwm_apb clock frequency).
+ * - The output is immediately set to low when the module is disabled.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pwm.h>
+#include <linux/reset.h>
+
+#define OCPWM_HRC	0x4
+#define OCPWM_LRC	0x8
+#define OCPWM_CTRL	0xC
+
+#define OCPWM_CTRL_EN	BIT(0)
+#define OCPWM_CTRL_OE	BIT(3)
+#define OCPWM_CTRL_RST	BIT(7)
+
+#define OCPWM_NUM_SAVED_REGS	3
+
+struct ocores_pwm_device {
+	void __iomem *base;
+	struct clk *clk;
+	unsigned long clk_rate;
+	struct reset_control *rst;
+	u32 saved_regs[OCPWM_NUM_SAVED_REGS];
+};
+
+static int ocores_pwm_get_state(struct pwm_chip *chip,
+				struct pwm_device *pwm,
+				struct pwm_state *state)
+{
+	struct ocores_pwm_device *ddata = pwmchip_get_drvdata(chip);
+	u32 period_data, duty_data, ctrl_data;
+	int ret;
+
+	ret = pm_runtime_resume_and_get(pwmchip_parent(chip));
+	if (ret < 0)
+		return ret;
+
+	period_data = readl(ddata->base + OCPWM_LRC);
+	duty_data = readl(ddata->base + OCPWM_HRC);
+	ctrl_data = readl(ddata->base + OCPWM_CTRL);
+
+	state->period = DIV_ROUND_UP_ULL((u64)period_data * NSEC_PER_SEC, ddata->clk_rate);
+	state->duty_cycle = DIV_ROUND_UP_ULL((u64)duty_data * NSEC_PER_SEC, ddata->clk_rate);
+	if (state->duty_cycle > state->period)
+		state->duty_cycle = state->period;
+
+	state->polarity = PWM_POLARITY_INVERSED;
+	state->enabled = (ctrl_data & OCPWM_CTRL_EN) ? true : false;
+
+	pm_runtime_put(pwmchip_parent(chip));
+
+	return 0;
+}
+
+static int ocores_pwm_apply(struct pwm_chip *chip,
+			    struct pwm_device *pwm,
+			    const struct pwm_state *state)
+{
+	struct ocores_pwm_device *ddata = pwmchip_get_drvdata(chip);
+	bool was_enabled = pwm_is_enabled(pwm);
+	u64 period_data, duty_data;
+	int ret;
+
+	if (state->polarity != PWM_POLARITY_INVERSED)
+		return -EINVAL;
+
+	if (state->enabled) {
+		if (!was_enabled) {
+			ret = pm_runtime_resume_and_get(pwmchip_parent(chip));
+			if (ret < 0)
+				return ret;
+		}
+	} else {
+		if (was_enabled) {
+			writel(0, ddata->base + OCPWM_CTRL);
+			pm_runtime_put(pwmchip_parent(chip));
+		}
+		return 0;
+	}
+
+	writel(0, ddata->base + OCPWM_CTRL);
+	writel(OCPWM_CTRL_RST, ddata->base + OCPWM_CTRL);
+
+	period_data = mul_u64_u32_div(state->period, ddata->clk_rate, NSEC_PER_SEC);
+	if (period_data > U32_MAX)
+		period_data = U32_MAX;
+
+	duty_data = mul_u64_u32_div(state->duty_cycle, ddata->clk_rate, NSEC_PER_SEC);
+	if (duty_data > U32_MAX)
+		duty_data = U32_MAX;
+
+	if (!period_data || !duty_data) {
+		if (!was_enabled)
+			pm_runtime_put(pwmchip_parent(chip));
+		return -EINVAL;
+	}
+
+	writel(period_data, ddata->base + OCPWM_LRC);
+	writel(duty_data, ddata->base + OCPWM_HRC);
+	writel(OCPWM_CTRL_OE | OCPWM_CTRL_EN, ddata->base + OCPWM_CTRL);
+
+	return 0;
+}
+
+static void ocores_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+	struct ocores_pwm_device *ddata = pwmchip_get_drvdata(chip);
+
+	if (pwm_is_enabled(pwm)) {
+		writel(0, ddata->base + OCPWM_CTRL);
+		pm_runtime_put_sync(pwmchip_parent(chip));
+	}
+}
+
+static const struct pwm_ops ocores_pwm_ops = {
+	.get_state = ocores_pwm_get_state,
+	.apply = ocores_pwm_apply,
+	.free = ocores_pwm_free,
+};
+
+static int ocores_pwm_runtime_suspend(struct device *dev)
+{
+	struct ocores_pwm_device *ddata = dev_get_drvdata(dev);
+
+	clk_disable_unprepare(ddata->clk);
+
+	return 0;
+}
+
+static int ocores_pwm_runtime_resume(struct device *dev)
+{
+	struct ocores_pwm_device *ddata = dev_get_drvdata(dev);
+	int ret;
+
+	ret = clk_prepare_enable(ddata->clk);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to enable clock\n");
+
+	return 0;
+}
+
+static int __maybe_unused ocores_pwm_suspend(struct device *dev)
+{
+	struct ocores_pwm_device *ddata = dev_get_drvdata(dev);
+	int ret, i;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret < 0)
+		return ret;
+
+	for (i = 0; i < OCPWM_NUM_SAVED_REGS; i++)
+		ddata->saved_regs[i] = readl(ddata->base + 4 + 4 * i);
+
+	pm_runtime_put_sync(dev);
+
+	return pm_runtime_force_suspend(dev);
+}
+
+static int __maybe_unused ocores_pwm_resume(struct device *dev)
+{
+	struct ocores_pwm_device *ddata = dev_get_drvdata(dev);
+	int ret, i;
+
+	ret = pm_runtime_force_resume(dev);
+	if (ret)
+		return ret;
+
+	ret = pm_runtime_resume_and_get(dev);
+	if (ret < 0)
+		return ret;
+
+	writel(0, ddata->base + OCPWM_CTRL);
+	writel(OCPWM_CTRL_RST, ddata->base + OCPWM_CTRL);
+	for (i = 0; i < OCPWM_NUM_SAVED_REGS; i++)
+		writel(ddata->saved_regs[i], ddata->base + 4 + 4 * i);
+
+	pm_runtime_put_sync(dev);
+
+	return 0;
+}
+
+static const struct dev_pm_ops ocores_pwm_pm_ops = {
+	RUNTIME_PM_OPS(ocores_pwm_runtime_suspend,
+		       ocores_pwm_runtime_resume, NULL)
+	SYSTEM_SLEEP_PM_OPS(ocores_pwm_suspend, ocores_pwm_resume)
+};
+
+static void ocores_pwm_pm_disable(void *data)
+{
+	struct device *dev = data;
+	struct ocores_pwm_device *ddata = dev_get_drvdata(dev);
+
+	pm_runtime_disable(dev);
+
+	if (!pm_runtime_status_suspended(dev)) {
+		/* Balance probe's pm_runtime_get_noresume() for bootloader-enabled PWM. */
+		if (readl(ddata->base + OCPWM_CTRL) & OCPWM_CTRL_EN)
+			pm_runtime_put_noidle(dev);
+
+		ocores_pwm_runtime_suspend(dev);
+	}
+
+	reset_control_assert(ddata->rst);
+}
+
+static int ocores_pwm_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct ocores_pwm_device *ddata;
+	struct pwm_chip *chip;
+	int ret;
+
+	chip = devm_pwmchip_alloc(dev, 1, sizeof(*ddata));
+	if (IS_ERR(chip))
+		return PTR_ERR(chip);
+
+	chip->ops = &ocores_pwm_ops;
+	ddata = pwmchip_get_drvdata(chip);
+
+	ddata->base = devm_platform_ioremap_resource(pdev, 0);
+	if (IS_ERR(ddata->base))
+		return dev_err_probe(dev, PTR_ERR(ddata->base),
+				     "Failed to map IO resources\n");
+
+	ddata->clk = devm_clk_get(dev, NULL);
+	if (IS_ERR(ddata->clk))
+		return dev_err_probe(dev, PTR_ERR(ddata->clk),
+				     "Failed to get clock\n");
+
+	ddata->clk_rate = clk_get_rate(ddata->clk);
+	if (!ddata->clk_rate || ddata->clk_rate > NSEC_PER_SEC)
+		return dev_err_probe(dev, -EINVAL,
+				     "Invalid clock rate: %lu\n", ddata->clk_rate);
+
+	ddata->rst = devm_reset_control_get_optional_shared(dev, NULL);
+	if (IS_ERR(ddata->rst))
+		return dev_err_probe(dev, PTR_ERR(ddata->rst),
+				     "Failed to get reset\n");
+
+	platform_set_drvdata(pdev, ddata);
+
+	ret = ocores_pwm_runtime_resume(dev);
+	if (ret)
+		return ret;
+
+	ret = reset_control_deassert(ddata->rst);
+	if (ret)
+		goto err_clk_disable;
+
+	ret = pm_runtime_set_active(dev);
+	if (ret)
+		goto err_reset_assert;
+
+	pm_runtime_get_noresume(dev);
+	pm_runtime_enable(dev);
+
+	if (!(readl(ddata->base + OCPWM_CTRL) & OCPWM_CTRL_EN))
+		pm_runtime_put_sync(dev);
+
+	ret = devm_add_action_or_reset(dev, ocores_pwm_pm_disable, dev);
+	if (ret)
+		return dev_err_probe(dev, ret, "Failed to add pm disable action\n");
+
+	ret = devm_pwmchip_add(dev, chip);
+	if (ret < 0)
+		return dev_err_probe(dev, ret, "Could not register PWM chip\n");
+
+	return 0;
+
+err_reset_assert:
+	reset_control_assert(ddata->rst);
+err_clk_disable:
+	ocores_pwm_runtime_suspend(dev);
+	return dev_err_probe(dev, ret, "Failed to init pwm power\n");
+}
+
+static const struct of_device_id ocores_pwm_of_match[] = {
+	{ .compatible = "opencores,pwm-v1" },
+	{ /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ocores_pwm_of_match);
+
+static struct platform_driver ocores_pwm_driver = {
+	.probe = ocores_pwm_probe,
+	.driver = {
+		.name = "ocores-pwm",
+		.of_match_table = ocores_pwm_of_match,
+		.pm = pm_ptr(&ocores_pwm_pm_ops),
+	},
+};
+module_platform_driver(ocores_pwm_driver);
+
+MODULE_AUTHOR("Jieqin Chen");
+MODULE_AUTHOR("Hal Feng <hal.feng at starfivetech.com>");
+MODULE_DESCRIPTION("OpenCores PTC PWM driver");
+MODULE_LICENSE("GPL");
-- 
2.43.2



From visitorckw at gmail.com  Mon Jun 15 09:18:08 2026
From: visitorckw at gmail.com (Kuan-Wei Chiu)
Date: Tue, 16 Jun 2026 00:18:08 +0800
Subject: [PATCH bpf-next v2 0/3] riscv, bpf: Fix signed operations and
 add 32 bit atomics
In-Reply-To: <20260511221648.3251464-1-visitorckw@gmail.com>
References: <20260511221648.3251464-1-visitorckw@gmail.com>
Message-ID: <ajAlwK990NFUAMwq@google.com>

Hi,

On Mon, May 11, 2026 at 10:16:45PM +0000, Kuan-Wei Chiu wrote:
> Fix miscompiled signed operations and expands 32 bit atomic support in
> the RV32 BPF JIT.
> 
> The current implementation ignores the instruction offset field used by
> the bpf instruction set to specify BPF_SDIV/BPF_SMOD and BPF_MOVSX.
> This causes these operations to be treated as unsigned or
> zero-extended, leading to test_bpf failures. Fix this by checking the
> offset and emitting the correct instructions.
> 
> Additionally, we leverage the mandatory A extension to natively support
> 32 bit bpf atomics (and, or, xor, xchg) by mapping them directly to
> amo*.w instructions. BPF_CMPXCHG continues to fall back to the
> interpreter.
> 
> As a result, test_bpf.ko now runs with 0 failures, and the total number
> of successfully JIT'ed test cases increases from 843 to 902.

Is there anything else I need to do for this patchset to land?

Regards,
Kuan-wei

> ---
> - Add missing Fixes tags.
> - Fix memory ordering by emitting aq=1, rl=1
> 
> Kuan-Wei Chiu (3):
>   riscv, bpf: Fix support for BPF_SDIV and BPF_SMOD in RV32 JIT
>   riscv, bpf: Fix support for BPF_MOVSX in RV32 JIT
>   riscv, bpf: Add 32 bit atomic operations to RV32 JIT
> 
>  arch/riscv/net/bpf_jit_comp32.c | 101 +++++++++++++++++++++++++++-----
>  1 file changed, 85 insertions(+), 16 deletions(-)
> 
> -- 
> 2.54.0.563.g4f69b47b94-goog
> 


From conor at kernel.org  Mon Jun 15 09:21:42 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 15 Jun 2026 17:21:42 +0100
Subject: [PATCH v19 1/3] dt-bindings: pwm: opencores: Update compatibles,
 examples and maintainers
In-Reply-To: <20260615155759.129210-2-hal.feng@starfivetech.com>
References: <20260615155759.129210-1-hal.feng@starfivetech.com>
 <20260615155759.129210-2-hal.feng@starfivetech.com>
Message-ID: <20260615-crescent-equation-d948fcc46cd1@spud>

On Mon, Jun 15, 2026 at 11:57:57PM +0800, Hal Feng wrote:
> Remove the jh8100 compatible since the JH8100 SoC has been canceled and
> will not be released. Add the jhb100 compatible to replace it.

> Use a oneOf construct to support the single-string opencores,pwm-v1
> compatible.

No thanks. Simple as this IP might be, I still want soc-specific
compatibles to be a requirement.
pw-bot: changes-requested

Thanks,
Conor.

> 
> Change the register size in examples to 0x10, since an OpenCores PTC IP
> has only 4 32-bit registers: CNTR, HRC, LRC and CTRL.
> 
> I will maintain this pwm module in place of William.
> 
> Signed-off-by: Hal Feng <hal.feng at starfivetech.com>
> ---
>  .../devicetree/bindings/pwm/opencores,pwm.yaml   | 16 +++++++++-------
>  1 file changed, 9 insertions(+), 7 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml b/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
> index 52a59d245cdb..5f05606a2d3d 100644
> --- a/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
> +++ b/Documentation/devicetree/bindings/pwm/opencores,pwm.yaml
> @@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
>  title: OpenCores PWM controller
>  
>  maintainers:
> -  - William Qiu <william.qiu at starfivetech.com>
> +  - Hal Feng <hal.feng at starfivetech.com>
>  
>  description:
>    The OpenCores PTC ip core contains a PWM controller. When operating in PWM
> @@ -19,12 +19,14 @@ allOf:
>  
>  properties:
>    compatible:
> -    items:
> -      - enum:
> -          - starfive,jh7100-pwm
> -          - starfive,jh7110-pwm
> -          - starfive,jh8100-pwm
> +    oneOf:
>        - const: opencores,pwm-v1
> +      - items:
> +        - enum:
> +            - starfive,jh7100-pwm
> +            - starfive,jh7110-pwm
> +            - starfive,jhb100-pwm
> +        - const: opencores,pwm-v1
>  
>    reg:
>      maxItems: 1
> @@ -49,7 +51,7 @@ examples:
>    - |
>      pwm at 12490000 {
>          compatible = "starfive,jh7110-pwm", "opencores,pwm-v1";
> -        reg = <0x12490000 0x10000>;
> +        reg = <0x12490000 0x10>;
>          clocks = <&clkgen 181>;
>          resets = <&rstgen 109>;
>          #pwm-cells = <3>;
> -- 
> 2.43.2
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260615/71f85ad8/attachment.sig>

From conor at kernel.org  Mon Jun 15 09:28:37 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 15 Jun 2026 17:28:37 +0100
Subject: [PATCH 4/7] dt-bindings: mfd: syscon: add ESWIN EIC7700
 compatible
In-Reply-To: <20260615122016.1110206-5-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
 <20260615122016.1110206-5-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615-buccaneer-garland-0617394e9a45@spud>

On Mon, Jun 15, 2026 at 05:50:13PM +0530, Pinkesh Vaghela wrote:
> Document ESWIN EIC7700 SoC compatible for syscon registers.

Some detail about what this syscon does would be nice.

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable

> 
> Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
> ---
>  Documentation/devicetree/bindings/mfd/syscon.yaml | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/mfd/syscon.yaml b/Documentation/devicetree/bindings/mfd/syscon.yaml
> index e22867088063..7d3365601249 100644
> --- a/Documentation/devicetree/bindings/mfd/syscon.yaml
> +++ b/Documentation/devicetree/bindings/mfd/syscon.yaml
> @@ -62,6 +62,7 @@ select:
>            - cirrus,ep7209-syscon3
>            - cnxt,cx92755-uc
>            - econet,en751221-chip-scu
> +          - eswin,eic7700-syscfg
>            - freecom,fsg-cs2-system-controller
>            - fsl,imx93-aonmix-ns-syscfg
>            - fsl,imx93-wakeupmix-syscfg
> @@ -175,6 +176,7 @@ properties:
>                - cirrus,ep7209-syscon3
>                - cnxt,cx92755-uc
>                - econet,en751221-chip-scu
> +              - eswin,eic7700-syscfg
>                - freecom,fsg-cs2-system-controller
>                - fsl,imx93-aonmix-ns-syscfg
>                - fsl,imx93-wakeupmix-syscfg
> -- 
> 2.34.1
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260615/fa6d4c71/attachment.sig>

From conor at kernel.org  Mon Jun 15 09:30:47 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 15 Jun 2026 17:30:47 +0100
Subject: [PATCH 2/7] riscv: dts: eswin: add clock generator for EIC7700
 SoC
In-Reply-To: <20260615122016.1110206-3-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
 <20260615122016.1110206-3-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615-overshot-pellet-5e527a14133e@spud>

On Mon, Jun 15, 2026 at 05:50:11PM +0530, Pinkesh Vaghela wrote:
> From: Pritesh Patel <pritesh.patel at einfochips.com>
> 
> Add clock generator node for EIC7700 SoC.
> HiFive Premier P550 boards have 24MHz crystal oscillator to provide
> the input clock.
> 
> Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
> Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
> ---
>  .../boot/dts/eswin/eic7700-hifive-premier-p550.dts  |  5 +++++
>  arch/riscv/boot/dts/eswin/eic7700.dtsi              | 13 +++++++++++++
>  2 files changed, 18 insertions(+)
> 
> diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> index 131ed1fc6b2e..1fb92f0e7c55 100644
> --- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> +++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> @@ -20,6 +20,11 @@ chosen {
>  	};
>  };
>  
> +&xtal {
> +	clock-frequency = <24000000>;
> +	clock-output-names = "xtal24m";
> +};
> +
>  &uart0 {
>  	status = "okay";
>  };
> diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> index 430a210f01e6..a7ebb1115958 100644
> --- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
> +++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> @@ -4,6 +4,7 @@
>   */
>  
>  /dts-v1/;
> +#include <dt-bindings/clock/eswin,eic7700-clock.h>
>  #include <dt-bindings/reset/eswin,eic7700-reset.h>
>  
>  / {
> @@ -203,6 +204,11 @@ pmu {
>  				<0x00000000 0x0000000f 0xfffffffc 0x000000ff 0x00000078>;
>  	};
>  
> +	xtal: oscillator {

Sashiko feedback here on making this clk-<hz> or clk-<something> should
be implemented.

> +		compatible = "fixed-clock";
> +		#clock-cells = <0>;
> +	};
> +
>  	soc {
>  		compatible = "simple-bus";
>  		ranges;
> @@ -343,6 +349,13 @@ gpioD: gpio-port at 3 {
>  			};
>  		};
>  
> +		clk: clock-controller at 51828000 {
> +			compatible = "eswin,eic7700-clock";
> +			reg = <0x0 0x51828000 0x0 0x300>;
> +			clocks = <&xtal>;
> +			#clock-cells = <1>;
> +		};
> +
>  		reset: reset-controller at 51828300 {
>  			compatible = "eswin,eic7700-reset";
>  			reg = <0x0 0x51828300 0x0 0x200>;
> -- 
> 2.34.1
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260615/3cb54cad/attachment.sig>

From conor at kernel.org  Mon Jun 15 09:33:15 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 15 Jun 2026 17:33:15 +0100
Subject: [PATCH 3/7] riscv: dts: eswin: eic7700: add pinctrl support
In-Reply-To: <20260615122016.1110206-4-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
 <20260615122016.1110206-4-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615-that-scarf-e048ef152676@spud>

On Mon, Jun 15, 2026 at 05:50:12PM +0530, Pinkesh Vaghela wrote:
> From: Yulin Lu <luyulin at eswincomputing.com>
> 
> Add pinctrl node and related pin configuration for EIC7700 SoC
> 
> Co-developed-by: Pritesh Patel <pritesh.patel at einfochips.com>
> Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
> Signed-off-by: Yulin Lu <luyulin at eswincomputing.com>
> Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
> ---
>  .../dts/eswin/eic7700-hifive-premier-p550.dts | 109 +++
>  .../riscv/boot/dts/eswin/eic7700-pinctrl.dtsi | 888 ++++++++++++++++++
>  arch/riscv/boot/dts/eswin/eic7700.dtsi        |   5 +
>  3 files changed, 1002 insertions(+)
>  create mode 100644 arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi
> 
> diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> index 1fb92f0e7c55..e7bb96e14958 100644
> --- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> +++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> @@ -6,6 +6,7 @@
>  /dts-v1/;
>  
>  #include "eic7700.dtsi"
> +#include "eic7700-pinctrl.dtsi"
>  
>  / {
>  	compatible = "sifive,hifive-premier-p550", "eswin,eic7700";
> @@ -18,6 +19,15 @@ aliases {
>  	chosen {
>  		stdout-path = "serial0:115200n8";
>  	};
> +
> +	vcc_1v8: vcc1v8 {

Same here.

> +		 compatible = "regulator-fixed";
> +		 regulator-name = "vcc1v8";
> +		 regulator-always-on;
> +		 regulator-boot-on;
> +		 regulator-min-microvolt = <1800000>;
> +		 regulator-max-microvolt = <1800000>;
> +	 };
>  };
>  
>  &xtal {
> @@ -25,6 +35,105 @@ &xtal {
>  	clock-output-names = "xtal24m";
>  };
>  
> +&gpio0_pins {
> +	bias-disable;
> +	input-enable;
> +};
> +
> +&gpio5_pins {
> +	bias-disable;
> +	input-enable;
> +};
> +
> +&gpio11_pins {
> +	bias-disable;
> +	input-enable;
> +};
> +
> +&gpio14_pins {
> +	bias-pull-up;
> +	input-disable;
> +};
> +
> +&gpio15_pins {
> +	bias-disable;
> +	input-enable;
> +};
> +
> +&gpio28_pins {
> +	bias-disable;
> +	input-enable;
> +};
> +
> +&gpio43_pins {
> +	bias-disable;
> +	input-disable;
> +};
> +
> +&gpio71_pins {
> +	bias-pull-up;
> +	input-disable;
> +};
> +
> +&gpio74_pins {
> +	bias-pull-up;
> +	input-disable;
> +};
> +
> +&gpio76_pins {
> +	bias-disable;
> +	input-disable;
> +};
> +
> +&gpio77_pins {
> +	bias-pull-up;
> +	input-disable;
> +};
> +
> +&gpio79_pins {
> +	bias-disable;
> +	input-disable;
> +};
> +
> +&gpio80_pins {
> +	bias-pull-up;
> +	input-disable;
> +};
> +
> +&gpio82_pins {
> +	bias-pull-up;
> +	input-disable;
> +};
> +
> +&gpio84_pins {
> +	bias-disable;
> +	input-disable;
> +};
> +
> +&gpio85_pins {
> +	bias-pull-up;
> +	input-disable;
> +};
> +
> +&gpio94_pins {
> +	bias-disable;
> +	input-disable;
> +};
> +
> +&gpio106_pins {
> +	bias-disable;
> +	input-disable;
> +};
> +
> +&gpio111_pins {
> +	bias-disable;
> +	input-disable;
> +};
> +
> +&pinctrl {
> +	vrgmii-supply = <&vcc_1v8>;
> +};
> +
>  &uart0 {
>  	status = "okay";
>  };
> diff --git a/arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi b/arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi
> new file mode 100644
> index 000000000000..7293df146aa7
> --- /dev/null
> +++ b/arch/riscv/boot/dts/eswin/eic7700-pinctrl.dtsi
> @@ -0,0 +1,888 @@
> +// SPDX-License-Identifier: (GPL-2.0 OR MIT)
> +/*
> + * Copyright (c) 2025 Beijing ESWIN Computing Technology Co., Ltd.
> + *
> + * ESWIN's EIC7700 SoC pin-mux and pin-config options are listed as
> + * device tree nodes in this file.
> + *
> + * Authors: Yulin Lu <luyulin at eswincomputing.com>
> + */
> +

I don't really understand the groups here. I think you should make more
effort to put more pins in each group.

> +		gpio1_pins: gpio1-pins {
> +			pins = "jtag0_tck";
> +			function = "gpio";
> +		};
> +
> +		gpio2_pins: gpio2-pins {
> +			pins = "jtag0_tms";
> +			function = "gpio";
> +		};
> +
> +		gpio3_pins: gpio3-pins {
> +			pins = "jtag0_tdi";
> +			function = "gpio";
> +		};
> +
> +		gpio4_pins: gpio4-pins {
> +			pins = "jtag0_tdo";
> +			function = "gpio";
> +		};

Like these 4 for example, why not group these?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260615/992678f5/attachment.sig>

From conor at kernel.org  Mon Jun 15 09:35:26 2026
From: conor at kernel.org (Conor Dooley)
Date: Mon, 15 Jun 2026 17:35:26 +0100
Subject: [PATCH 6/7] riscv: dts: eswin: add I2C controller support
In-Reply-To: <20260615122016.1110206-7-pinkesh.vaghela@einfochips.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
 <20260615122016.1110206-7-pinkesh.vaghela@einfochips.com>
Message-ID: <20260615-lumpiness-profusely-155422288c31@spud>

On Mon, Jun 15, 2026 at 05:50:15PM +0530, Pinkesh Vaghela wrote:
> From: Pritesh Patel <pritesh.patel at einfochips.com>
> 
> Add I2C nodes for EIC7700 SoC.
> Also add nodes for corresponding slave devices in dts file and
> enable them for HiFive Premier P550 board
> 
> Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
> Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
> ---
>  .../dts/eswin/eic7700-hifive-premier-p550.dts |  52 ++++++
>  arch/riscv/boot/dts/eswin/eic7700.dtsi        | 156 ++++++++++++++++++
>  2 files changed, 208 insertions(+)
> 
> diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> index e7bb96e14958..0f0c98474c62 100644
> --- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> +++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> @@ -130,6 +130,58 @@ &gpio111_pins {
>  	input-disable;
>  };
>  
> +&aon_i2c0 {
> +	status = "okay";
> +
> +	eeprom at 50 {
> +		compatible = "atmel,24c02";
> +		reg = <0x50>;
> +	};
> +};
> +
> +&aon_i2c1 {
> +	status = "okay";
> +
> +	pac1934 at 10 {

Generic node name here please. adc I think.

> +		compatible = "microchip,pac1934";
> +		reg = <0x10>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +
> +		channel at 1 {
> +			reg = <0x1>;
> +			shunt-resistor-micro-ohms = <1000>;
> +			label = "VDD_SOM";
> +		};
> +
> +		channel at 2 {
> +			reg = <0x2>;
> +			shunt-resistor-micro-ohms = <1000>;
> +			label = "VDD_SOC";
> +		};
> +
> +		channel at 3 {
> +			reg = <0x3>;
> +			shunt-resistor-micro-ohms = <1000>;
> +			label = "VDD_CPU";
> +		};
> +
> +		channel at 4 {
> +			reg = <0x4>;
> +			shunt-resistor-micro-ohms = <1000>;
> +			label = "VDD_LPDDR";
> +		};
> +	};
> +
> +	ina226 at 44 {

And here. power-sensor.

> +		compatible = "ti,ina226";
> +		reg = <0x44>;
> +		#io-channel-cells = <1>;
> +		label = "sys_power";
> +		shunt-resistor = <1000>;
> +	};
> +};
> +
>  &pinctrl {
>  	vrgmii-supply = <&vcc_1v8>;
>  };
> diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> index f8caf39616b2..28706431b2c0 100644
> --- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
> +++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> @@ -315,6 +315,162 @@ uart4: serial at 50940000 {
>  			status = "disabled";
>  		};
>  
> +		i2c0: i2c at 50950000 {
> +			compatible = "snps,designware-i2c";

Missing a soc-specific compatible here for all i2c controllers.


Cheers,
Conor.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260615/7b48999c/attachment.sig>

From fustini at kernel.org  Mon Jun 15 09:52:46 2026
From: fustini at kernel.org (Drew Fustini)
Date: Mon, 15 Jun 2026 09:52:46 -0700
Subject: [GIT PULL] RISC-V defconfig changes for v7.2
Message-ID: <ajAt3ml9pMIMTLTq@x1>

Hi, this is a late pull request so no problem if it misses this window.
It is just a single patch for the WiFi driver on the TH1520-based LPi4a.

I recently setup new branches for riscv defconfig patches and they have
been added to linux-next. I talked with Conor and this seemed like a
good way to pull in defconfig patches that RISC-V SoCs need without
adding more to the plate of the arch maintainer (Paul).

Thanks,
Drew

The following changes since commit 254f49634ee16a731174d2ae34bc50bd5f45e731:

  Linux 7.1-rc1 (2026-04-26 14:19:00 -0700)

are available in the Git repository at:

  git at github.com:tenstorrent/linux.git riscv-config-for-v7.2

for you to fetch changes up to fb266bbe9aef17d547db468a1a7187b59ed33e9a:

  riscv: defconfig: thead: enable PCA953X GPIO driver (2026-06-08 11:31:26 -0700)

----------------------------------------------------------------
RISC-V defconfig changes for 7.2

Enable PCA953X GPIO driver to properly probe Wifi pwrseq driver on
the Sipeed Lichee Pi 4a board which is based on the T-HEAD TH1520 SoC.

----------------------------------------------------------------
Marek Szyprowski (1):
      riscv: defconfig: thead: enable PCA953X GPIO driver

 arch/riscv/configs/defconfig | 2 ++
 1 file changed, 2 insertions(+)


From viro at zeniv.linux.org.uk  Mon Jun 15 10:04:32 2026
From: viro at zeniv.linux.org.uk (Al Viro)
Date: Mon, 15 Jun 2026 18:04:32 +0100
Subject: [PATCH 00/19] init: discoverable root partitions, a.k.a. an
 omittable "root=" cmdline option
In-Reply-To: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>
References: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>
Message-ID: <20260615170432.GW2636677@ZenIV>

On Mon, Jun 15, 2026 at 06:08:56PM +0200, Vincent Mailhol wrote:

> Tested with GRUB, which implements the LoaderDevicePartUUID EFI variable
> in its bli module [3]. With this, I was able to boot a kernel with a
> completely empty cmdline and no initrd.
> 
> [1] The Discoverable Partitions Specification (DPS)
> Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/
> 
> [2] systemd-gpt-auto-generator
> Link: https://www.freedesktop.org/software/systemd/man/latest/systemd-gpt-auto-generator.html
> 
> [3] GRUB -- ?16.2 bli
> Link: https://www.gnu.org/software/grub/manual/grub/html_node/bli_005fmodule.html

So what does that thing, tied to EFI as it is, have to do with architectures where
	* firmware is rather unlike EFI
	* firmware wouldn't know what to do with GPT
	* GRUB is *not* ported to, let alone used
such as, say it, the very first one mentioned at your [1]?

Or is that conditional upon "if anyone wants to design replacement firmware
for those, and if they agree to follow our wishlist"?


From asrinivasan at oss.tenstorrent.com  Mon Jun 15 10:22:18 2026
From: asrinivasan at oss.tenstorrent.com (Anirudh Srinivasan)
Date: Mon, 15 Jun 2026 12:22:18 -0500
Subject: [PATCH] riscv: drop __init from vec_check_unaligned_access_speed_all_cpus
In-Reply-To: <87ecibwiz6.fsf@yellow.woof>
References: <20260612-vec_unaligned_drop_init-v1-1-df969210ae34@oss.tenstorrent.com>
 <87ecibwiz6.fsf@yellow.woof>
Message-ID: <CAEev2e8AH8W_M4=9N8vLJyvRqwGG=p8O-jVa7tdM3LjCRj=6aw@mail.gmail.com>

Hi,

On Fri, Jun 12, 2026 at 4:23?PM Nam Cao <namcao at linutronix.de> wrote:
>
> Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com> writes:
> > This function runs within a kthread and need not necessarily finish
> > before system finishes boot and free_initmem() unmaps the .init.text
> > section. This function makes calls to SBI for probing unaligned access
> > speed, and if this is slow for some reason (say some debug prints were
> > added to SBI), the kthread can still be running at this point and result
> > in an instruction page fault when trying to fetch from the freed region.
> ...
> > Drop __init from its signature so that this doesn't happen.
>
> That should work.
>
> But we should really take a step back and reconsider whether running the
> vector access speed probe in a kthread is really a good idea.
>
> We have a problem in the past that the kthread may not complete before
> user reads vdso, and user gets incorrect values. That was addressed by
> 5d15d2ad36b0 ("riscv: hwprobe: Fix stale vDSO data for late-initialized
> keys at boot") which complicates things.
>
> And now you discover another issue.
>
> The motivation for using a kthread is to avoid boot time slow down. But
> this has been bothering me for quite a while now, because I am not sure
> if using kthread really speeds things up. Sooner or later, the kthread
> has to run. If it runs before the kernel is done booting, then the boot
> is even slower due to overhead of the kthread. If it runs after the
> kernel finishes booting, then we run into these kinds of
> headache. Unfortunately I do not have a riscv cpu with vector to confirm
> my suspicion.
>
> Furthermore, the vector access speed probe takes the same amount of time
> as scalar access speed probe. The scalar one is done without any
> kthread, and no one ever complained about boot time issue (well, someone
> did complain but that has nothing to do with kthread. Their 64-core (?)
> system is slower because the probe was done serially, and we switched to
> parallel probe and it was fine).
>
> So I think we should really get rid of that kthread entirely, the
> headache is not worth. That also allows reverting 5d15d2ad36b0 ("riscv:
> hwprobe: Fix stale vDSO data for late-initialized keys at boot"), making
> the code simplier.
>
> Below is a patch that has only been tested with qemu. It reverts the
> mentioned commit and removes the kthread.
>

I tested your patch on Sifive X280 (RVV 1.0, Vlen 512) and a patched
version of Qemu (qemu doesn't emit traps on misaligned vector
load/stores, so I tried patching it to do that) and it seems to fix my
error in both cases.

Not sure if this is useful info about boot timings on the X280, but

Before your patch (vec_check_unaligned_access_speed_all_cpus runs in kthread)
[    0.393029] cpu1: scalar unaligned word access speed is 0.01x byte
access speed (slow)
[    0.393035] cpu2: scalar unaligned word access speed is 0.01x byte
access speed (slow)
[    0.393037] cpu0: scalar unaligned word access speed is 0.01x byte
access speed (slow)
[    0.393051] cpu3: scalar unaligned word access speed is 0.01x byte
access speed (slow)
[    0.417932] cpu2: vector unaligned word access speed is 0.00x byte
access speed (slow)
[    0.417937] cpu0: vector unaligned word access speed is 0.00x byte
access speed (slow)
[    0.417958] cpu1: vector unaligned word access speed is 0.00x byte
access speed (slow)
[    0.422175] cpu3: vector unaligned word access speed is 0.01x byte
access speed (slow)
[    0.423780] clk: Disabling unused clocks
[    0.427185] PM: genpd: Disabling unused power domains
[    0.458801] EXT4-fs (vda): recovery complete
[    0.459069] EXT4-fs (vda): mounted filesystem
2c88c5b4-f269-4b04-a4c4-2e7270c53919 r/w with ordered data mode. Quota
mode: disabled.
[    0.459146] VFS: Mounted root (ext4 filesystem) on device 254:0.
[    0.461981] devtmpfs: mounted
[    0.462101] VFS: Pivoted into new rootfs
[    0.464377] Freeing unused kernel image (initmem) memory: 2264K
[    0.464474] Run /sbin/init as init process

After your patch (vec_check_unaligned_access_speed_all_cpus doesn't
run in kthread)
[    0.393026] cpu0: scalar unaligned word access speed is 0.01x byte
access speed (slow)
[    0.393027] cpu1: scalar unaligned word access speed is 0.01x byte
access speed (slow)
[    0.393029] cpu3: scalar unaligned word access speed is 0.01x byte
access speed (slow)
[    0.393050] cpu2: scalar unaligned word access speed is 0.01x byte
access speed (slow)
[    0.417781] cpu1: vector unaligned word access speed is 0.00x byte
access speed (slow)
[    0.417784] cpu2: vector unaligned word access speed is 0.00x byte
access speed (slow)
[    0.417797] cpu3: vector unaligned word access speed is 0.00x byte
access speed (slow)
[    0.417803] cpu0: vector unaligned word access speed is 0.00x byte
access speed (slow)
[    0.433944] clk: Disabling unused clocks
[    0.433962] PM: genpd: Disabling unused power domains
[    0.446730] EXT4-fs (vda): recovery complete
[    0.447071] EXT4-fs (vda): mounted filesystem
2c88c5b4-f269-4b04-a4c4-2e7270c53919 r/w with ordered data mode. Quota
mode: disabled.
[    0.447134] VFS: Mounted root (ext4 filesystem) on device 254:0.
[    0.451719] devtmpfs: mounted
[    0.451840] VFS: Pivoted into new rootfs
[    0.455658] Freeing unused kernel image (initmem) memory: 2264K
[    0.457991] Run /sbin/init as init process

I think the difference seems too small here to draw any conclusions.
This is only a 4 core CPU.


From mailhol at kernel.org  Mon Jun 15 13:33:11 2026
From: mailhol at kernel.org (Vincent Mailhol)
Date: Mon, 15 Jun 2026 22:33:11 +0200
Subject: [PATCH 00/19] init: discoverable root partitions, a.k.a. an
 omittable "root=" cmdline option
In-Reply-To: <20260615170432.GW2636677@ZenIV>
References: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>
 <20260615170432.GW2636677@ZenIV>
Message-ID: <131a450f-f9c6-464c-8e4e-a4c7a29fb5de@kernel.org>

On 15/06/2026 at 19:04, Al Viro wrote:
> On Mon, Jun 15, 2026 at 06:08:56PM +0200, Vincent Mailhol wrote:
> 
>> Tested with GRUB, which implements the LoaderDevicePartUUID EFI variable
>> in its bli module [3]. With this, I was able to boot a kernel with a
>> completely empty cmdline and no initrd.
>>
>> [1] The Discoverable Partitions Specification (DPS)
>> Link: https://uapi-group.org/specifications/specs/discoverable_partitions_specification/
>>
>> [2] systemd-gpt-auto-generator
>> Link: https://www.freedesktop.org/software/systemd/man/latest/systemd-gpt-auto-generator.html
>>
>> [3] GRUB -- ?16.2 bli
>> Link: https://www.gnu.org/software/grub/manual/grub/html_node/bli_005fmodule.html
> 
> So what does that thing, tied to EFI as it is, have to do with architectures where
> 	* firmware is rather unlike EFI

I made CONFIG_DPS_ROOT_AUTO_DISCOVERY depend on CONFIG_EFI for this reason.

> 	* firmware wouldn't know what to do with GPT
> 	* GRUB is *not* ported to, let alone used
> such as, say it, the very first one mentioned at your [1]?

Fair point. I just did:

  $ git grep "^config EFI$"
  arch/arm/Kconfig:config EFI
  arch/arm64/Kconfig:config EFI
  arch/loongarch/Kconfig:config EFI
  arch/riscv/Kconfig:config EFI
  arch/x86/Kconfig:config EFI

Anything not in this list is dead code at the moment.

> Or is that conditional upon "if anyone wants to design replacement firmware
> for those, and if they agree to follow our wishlist"?

No, it was just an oversight from my side. I will just keep arm, arm64,
loongarch, riscv and x86 in my v2.


Yours sincerely,
Vincent Mailhol



From vincent.legoll at gmail.com  Mon Jun 15 13:34:34 2026
From: vincent.legoll at gmail.com (Vincent Legoll)
Date: Mon, 15 Jun 2026 22:34:34 +0200
Subject: [PATCH v2] riscv: dts: spacemit: k1-orangepi-rv2: Add cpu scaling
Message-ID: <20260615-k1-cpufreq-orangepi-rv2-v2-1-237f006e580b@gmail.com>

Enable CPU DVFS on OrangePi RV2

Signed-off-by: Vincent Legoll <vincent.legoll at gmail.com>
---
Tested on a 2GB RAM OrangePi RV2 board, patch applied over
spacemit/for-next + Shuwei Wu's V3 series.

On Void linux (musl libc):

uname -a
Linux opirv2 7.1.0-rc1-00043-gb860bca13be4 #14 SMP PREEMPT Sat Jun 13 
11:02:13 CEST 2026 riscv64 GNU/Linux

awk --version | head -1
GNU Awk 5.3.2, API 4.0

echo userspace > /sys/devices/system/cpu/cpufreq/policy0/scaling_governor

echo 1600000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real    0m0.300s
user    0m0.299s
sys     0m0.001s

echo 1228800 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real    0m0.432s
user    0m0.429s
sys     0m0.004s

echo 1000000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real    0m0.476s
user    0m0.476s
sys     0m0.001s

echo 819000 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real    0m0.582s
user    0m0.581s
sys     0m0.001s

echo 614400 > /sys/devices/system/cpu/cpu0/cpufreq/scaling_setspeed
time awk 'BEGIN{for(i=0;i<1000000;i++){}}'
real    0m0.778s
user    0m0.773s
sys     0m0.005s

Changes in v2:
- Fix indentation with TABs
Feedback from Yixun Lan (dlan)
- sort includes in alphabetical order
- use b4
- Link to v1: https://patch.msgid.link/f031e13e-d9f5-414a-b90e-a3d5a60b8d05 at online.fr
---
 arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts | 35 +++++++++++++++++++++++-
 1 file changed, 34 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
index 7c49bce427f3..2c2542e02d6a 100644
--- a/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
+++ b/arch/riscv/boot/dts/spacemit/k1-orangepi-rv2.dts
@@ -7,6 +7,7 @@
 /dts-v1/;
 
 #include "k1.dtsi"
+#include "k1-opp.dtsi"
 #include "k1-pinctrl.dtsi"
 
 / {
@@ -80,6 +81,38 @@ &combo_phy {
 	status = "okay";
 };
 
+&cpu_0 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_1 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_2 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_3 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_4 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_5 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_6 {
+	cpu-supply = <&buck1_0v9>;
+};
+
+&cpu_7 {
+	cpu-supply = <&buck1_0v9>;
+};
+
 &emmc {
 	bus-width = <8>;
 	mmc-hs400-1_8v;
@@ -162,7 +195,7 @@ pmic at 41 {
 		dldoin2-supply = <&buck5>;
 
 		regulators {
-			buck1 {
+			buck1_0v9: buck1 {
 				regulator-min-microvolt = <500000>;
 				regulator-max-microvolt = <3450000>;
 				regulator-ramp-delay = <5000>;

---
base-commit: 32cb211965ea0ba0ab8568959f006c7fa10e9f23
change-id: 20260615-k1-cpufreq-orangepi-rv2-5ece985163cd

Best regards,
--  
Vincent Legoll <vincent.legoll at gmail.com>



From atish.patra at linux.dev  Mon Jun 15 16:28:20 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 15 Jun 2026 16:28:20 -0700
Subject: [PATCH 0/2] riscv: Use EFI runtime services for poweroff and
 restart
Message-ID: <20260615-efi_reset_shutdown-v1-0-9414edcbbab0@meta.com>

Today RISC-V always uses the SBI SRST extension for both poweroff and restart,
even when UEFI runtime services are available. This series makes RISC-V prefer
EFI runtime services for both paths when available. The reset via EFI is
required for EFI capsule updates and also documented as a preferred method
in BRS 1.0 spec (e.g. URT_030)[1] 

Behavior on SBI-only (non-EFI) systems is unchanged.

Tested under QEMU 'virt' with EDK2/UEFI firmware exposing runtime
ResetSystem().

[1] https://docs.riscv.org/reference/brs/uefi.html#uefi

Signed-off-by: Atish Patra <atishp at meta.com>
---
Atish Patra (2):
      riscv: efi: Power off via EFI runtime services when available
      riscv: Restart via EFI runtime services when available

 arch/riscv/kernel/efi.c   | 5 +++++
 arch/riscv/kernel/reset.c | 7 +++++++
 2 files changed, 12 insertions(+)
---
base-commit: 8cd9520d35a6c38db6567e97dd93b1f11f185dc6
change-id: 20260615-efi_reset_shutdown-792040a83f18

Best regards,
-- 
Atish Patra <atishp at meta.com>



From atish.patra at linux.dev  Mon Jun 15 16:28:21 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 15 Jun 2026 16:28:21 -0700
Subject: [PATCH 1/2] riscv: efi: Power off via EFI runtime services when
 available
In-Reply-To: <20260615-efi_reset_shutdown-v1-0-9414edcbbab0@meta.com>
References: <20260615-efi_reset_shutdown-v1-0-9414edcbbab0@meta.com>
Message-ID: <20260615-efi_reset_shutdown-v1-1-9414edcbbab0@meta.com>

From: Atish Patra <atishp at meta.com>

When booted via UEFI with runtime services enabled, EFI Reset Shutdown is
the firmware-preferred shutdown path: it lets firmware run its own
shutdown hooks which may invoke SBI SRST extension internally. However,
RISC-V always powers off via the SBI SRST extension today and EFI runtime
path is never used even when firmware provides it.

Enable the poweroff via EFI by overriding efi_poweroff_required()

Signed-off-by: Atish Patra <atishp at meta.com>
---
 arch/riscv/kernel/efi.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/arch/riscv/kernel/efi.c b/arch/riscv/kernel/efi.c
index b64bf1624a05..2d3cc57b4535 100644
--- a/arch/riscv/kernel/efi.c
+++ b/arch/riscv/kernel/efi.c
@@ -95,3 +95,8 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
 				   md->num_pages << EFI_PAGE_SHIFT,
 				   set_permissions, md);
 }
+
+bool efi_poweroff_required(void)
+{
+	return efi_enabled(EFI_RUNTIME_SERVICES);
+}

-- 
2.53.0-Meta



From atish.patra at linux.dev  Mon Jun 15 16:28:22 2026
From: atish.patra at linux.dev (Atish Patra)
Date: Mon, 15 Jun 2026 16:28:22 -0700
Subject: [PATCH 2/2] riscv: Restart via EFI runtime services when available
In-Reply-To: <20260615-efi_reset_shutdown-v1-0-9414edcbbab0@meta.com>
References: <20260615-efi_reset_shutdown-v1-0-9414edcbbab0@meta.com>
Message-ID: <20260615-efi_reset_shutdown-v1-2-9414edcbbab0@meta.com>

From: Atish Patra <atishp at meta.com>

Firmware-preferred reset and EFI capsule update support requires reset
via EFI runtime services rather than direction M-mode firmware invocation
via SBI. Unlike poweroff, restart mechanism is directly controlled from
machine_restart function though.

Prefer the EFI runtime ResetSystem() service for restart when UEFI
runtime services are available.

Signed-off-by: Atish Patra <atishp at meta.com>
---
 arch/riscv/kernel/reset.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/riscv/kernel/reset.c b/arch/riscv/kernel/reset.c
index 912288572226..541e2162c85a 100644
--- a/arch/riscv/kernel/reset.c
+++ b/arch/riscv/kernel/reset.c
@@ -3,6 +3,7 @@
  * Copyright (C) 2012 Regents of the University of California
  */
 
+#include <linux/efi.h>
 #include <linux/reboot.h>
 #include <linux/pm.h>
 
@@ -17,6 +18,12 @@ EXPORT_SYMBOL(pm_power_off);
 
 void machine_restart(char *cmd)
 {
+	/*
+	 * UpdateCapsule() depends on the system being reset via ResetSystem().
+	 */
+	if (efi_enabled(EFI_RUNTIME_SERVICES))
+		efi_reboot(reboot_mode, NULL);
+
 	do_kernel_restart(cmd);
 	while (1);
 }

-- 
2.53.0-Meta



From pulehui at huawei.com  Mon Jun 15 18:41:21 2026
From: pulehui at huawei.com (Pu Lehui)
Date: Tue, 16 Jun 2026 09:41:21 +0800
Subject: [PATCH bpf-next v2 0/3] riscv, bpf: Fix signed operations and add
 32 bit atomics
In-Reply-To: <ajAlwK990NFUAMwq@google.com>
References: <20260511221648.3251464-1-visitorckw@gmail.com>
 <ajAlwK990NFUAMwq@google.com>
Message-ID: <216ee1df-2945-4266-9c70-ebcd36faeb7f@huawei.com>



On 2026/6/16 0:18, Kuan-Wei Chiu wrote:
> Hi,
> 
> On Mon, May 11, 2026 at 10:16:45PM +0000, Kuan-Wei Chiu wrote:
>> Fix miscompiled signed operations and expands 32 bit atomic support in
>> the RV32 BPF JIT.
>>
>> The current implementation ignores the instruction offset field used by
>> the bpf instruction set to specify BPF_SDIV/BPF_SMOD and BPF_MOVSX.
>> This causes these operations to be treated as unsigned or
>> zero-extended, leading to test_bpf failures. Fix this by checking the
>> offset and emitting the correct instructions.
>>
>> Additionally, we leverage the mandatory A extension to natively support
>> 32 bit bpf atomics (and, or, xor, xchg) by mapping them directly to
>> amo*.w instructions. BPF_CMPXCHG continues to fall back to the
>> interpreter.
>>
>> As a result, test_bpf.ko now runs with 0 failures, and the total number
>> of successfully JIT'ed test cases increases from 843 to 902.
> 
> Is there anything else I need to do for this patchset to land?

Hi Kuan-wei, it seems Luke and Xi haven't been as active in the 
community for a while, I'll make time to cover the review and testing 
for this.

Regards,
Lehui

> 
> Regards,
> Kuan-wei
> 
>> ---
>> - Add missing Fixes tags.
>> - Fix memory ordering by emitting aq=1, rl=1
>>
>> Kuan-Wei Chiu (3):
>>    riscv, bpf: Fix support for BPF_SDIV and BPF_SMOD in RV32 JIT
>>    riscv, bpf: Fix support for BPF_MOVSX in RV32 JIT
>>    riscv, bpf: Add 32 bit atomic operations to RV32 JIT
>>
>>   arch/riscv/net/bpf_jit_comp32.c | 101 +++++++++++++++++++++++++++-----
>>   1 file changed, 85 insertions(+), 16 deletions(-)
>>
>> -- 
>> 2.54.0.563.g4f69b47b94-goog
>>
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv


From visitorckw at gmail.com  Mon Jun 15 19:21:02 2026
From: visitorckw at gmail.com (Kuan-Wei Chiu)
Date: Tue, 16 Jun 2026 10:21:02 +0800
Subject: [PATCH bpf-next v2 0/3] riscv, bpf: Fix signed operations and
 add 32 bit atomics
In-Reply-To: <216ee1df-2945-4266-9c70-ebcd36faeb7f@huawei.com>
References: <20260511221648.3251464-1-visitorckw@gmail.com>
 <ajAlwK990NFUAMwq@google.com>
 <216ee1df-2945-4266-9c70-ebcd36faeb7f@huawei.com>
Message-ID: <ajCzDo7bnUqE0DiW@google.com>

Hi Lehui,

On Tue, Jun 16, 2026 at 09:41:21AM +0800, Pu Lehui wrote:
> 
> 
> On 2026/6/16 0:18, Kuan-Wei Chiu wrote:
> > Hi,
> > 
> > On Mon, May 11, 2026 at 10:16:45PM +0000, Kuan-Wei Chiu wrote:
> > > Fix miscompiled signed operations and expands 32 bit atomic support in
> > > the RV32 BPF JIT.
> > > 
> > > The current implementation ignores the instruction offset field used by
> > > the bpf instruction set to specify BPF_SDIV/BPF_SMOD and BPF_MOVSX.
> > > This causes these operations to be treated as unsigned or
> > > zero-extended, leading to test_bpf failures. Fix this by checking the
> > > offset and emitting the correct instructions.
> > > 
> > > Additionally, we leverage the mandatory A extension to natively support
> > > 32 bit bpf atomics (and, or, xor, xchg) by mapping them directly to
> > > amo*.w instructions. BPF_CMPXCHG continues to fall back to the
> > > interpreter.
> > > 
> > > As a result, test_bpf.ko now runs with 0 failures, and the total number
> > > of successfully JIT'ed test cases increases from 843 to 902.
> > 
> > Is there anything else I need to do for this patchset to land?
> 
> Hi Kuan-wei, it seems Luke and Xi haven't been as active in the community
> for a while, I'll make time to cover the review and testing for this.

Thank you for stepping in to help with the review and testing.
I really appreciate it.

Since Luke and Xi haven't been active for a while, I was wondering if
we should consider updating the MAINTAINERS file to reflect the current
status?

Also, if you need extra hands, I'd be glad to help review and test
future RV32 BPF patches.

Regards,
Kuan-Wei

> 
> Regards,
> Lehui
> 
> > 
> > Regards,
> > Kuan-wei
> > 
> > > ---
> > > - Add missing Fixes tags.
> > > - Fix memory ordering by emitting aq=1, rl=1
> > > 
> > > Kuan-Wei Chiu (3):
> > >    riscv, bpf: Fix support for BPF_SDIV and BPF_SMOD in RV32 JIT
> > >    riscv, bpf: Fix support for BPF_MOVSX in RV32 JIT
> > >    riscv, bpf: Add 32 bit atomic operations to RV32 JIT
> > > 
> > >   arch/riscv/net/bpf_jit_comp32.c | 101 +++++++++++++++++++++++++++-----
> > >   1 file changed, 85 insertions(+), 16 deletions(-)
> > > 
> > > -- 
> > > 2.54.0.563.g4f69b47b94-goog
> > > 
> > 
> > _______________________________________________
> > linux-riscv mailing list
> > linux-riscv at lists.infradead.org
> > http://lists.infradead.org/mailman/listinfo/linux-riscv


From mpe at kernel.org  Mon Jun 15 20:05:09 2026
From: mpe at kernel.org (Michael Ellerman)
Date: Tue, 16 Jun 2026 13:05:09 +1000
Subject: [PATCH] riscv: hwprobe: Avoid uninitialized read in
 hwprobe_get_cpus()
In-Reply-To: <20260612045502.70850-1-mark.hsj@gmail.com>
References: <20260612045502.70850-1-mark.hsj@gmail.com>
Message-ID: <77749c92-ac8a-4074-bb59-59dbbd3d84f2@kernel.org>

On 12/6/26 2:55 pm, Mark Harris wrote:
> When cpusetsize < cpumask_size(), hwprobe_get_cpus() did not fully
> initialize its copy of the cpu mask, which could cause non-deterministic
> results from the riscv_hwprobe syscall on a system with more than 8 CPUs
> when the supplied cpu mask is empty.  Address this by fully initializing
> the cpu mask.
> 
> Signed-off-by: Mark Harris <mark.hsj at gmail.com>
> ---
>   arch/riscv/kernel/sys_hwprobe.c | 1 +
>   1 file changed, 1 insertion(+)

This should have a fixes tag, I think it's:

Fixes: e178bf146e4b ("RISC-V: hwprobe: Introduce which-cpus flag")

> diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
> index 1659d31fd288..caf6762427c8 100644
> --- a/arch/riscv/kernel/sys_hwprobe.c
> +++ b/arch/riscv/kernel/sys_hwprobe.c
> @@ -450,6 +450,7 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,
>   	if (cpusetsize > cpumask_size())
>   		cpusetsize = cpumask_size();
>   
> +	cpumask_clear(&cpus);
>   	ret = copy_from_user(&cpus, cpus_user, cpusetsize);
>   	if (ret)
>   		return -EFAULT;

cpus is on the stack, and is copied back out at the end of the function, 
so this looks like it could be a stack info leak.

But the copy back is also bounded by cpusetsize, so in fact there is not 
any leak of uninitialised stack out to userspace:

         ret = copy_to_user(cpus_user, &cpus, cpusetsize);
         if (ret)
                 return -EFAULT;

Reviewed-by: Michael Ellerman <mpe at kernel.org>

cheers


From mark.hsj at gmail.com  Mon Jun 15 20:53:43 2026
From: mark.hsj at gmail.com (Mark Harris)
Date: Mon, 15 Jun 2026 20:53:43 -0700
Subject: [PATCH] riscv: hwprobe: Avoid uninitialized read in hwprobe_get_cpus()
In-Reply-To: <77749c92-ac8a-4074-bb59-59dbbd3d84f2@kernel.org>
References: <20260612045502.70850-1-mark.hsj@gmail.com> <77749c92-ac8a-4074-bb59-59dbbd3d84f2@kernel.org>
Message-ID: <CAMdZqKEpxT3vzE97LbaxP9grg5wi3aeArzgdyORHyGz=ZsDe0g@mail.gmail.com>

Michael Ellerman wrote:
>
> On 12/6/26 2:55 pm, Mark Harris wrote:
> > When cpusetsize < cpumask_size(), hwprobe_get_cpus() did not fully
> > initialize its copy of the cpu mask, which could cause non-deterministic
> > results from the riscv_hwprobe syscall on a system with more than 8 CPUs
> > when the supplied cpu mask is empty.  Address this by fully initializing
> > the cpu mask.
> >
> > Signed-off-by: Mark Harris <mark.hsj at gmail.com>
> > ---
> >   arch/riscv/kernel/sys_hwprobe.c | 1 +
> >   1 file changed, 1 insertion(+)
>
> This should have a fixes tag, I think it's:
>
> Fixes: e178bf146e4b ("RISC-V: hwprobe: Introduce which-cpus flag")

Yes, that looks correct.

>
> > diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
> > index 1659d31fd288..caf6762427c8 100644
> > --- a/arch/riscv/kernel/sys_hwprobe.c
> > +++ b/arch/riscv/kernel/sys_hwprobe.c
> > @@ -450,6 +450,7 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,
> >       if (cpusetsize > cpumask_size())
> >               cpusetsize = cpumask_size();
> >
> > +     cpumask_clear(&cpus);
> >       ret = copy_from_user(&cpus, cpus_user, cpusetsize);
> >       if (ret)
> >               return -EFAULT;
>
> cpus is on the stack, and is copied back out at the end of the function,
> so this looks like it could be a stack info leak.
>
> But the copy back is also bounded by cpusetsize, so in fact there is not
> any leak of uninitialised stack out to userspace:
>
>          ret = copy_to_user(cpus_user, &cpus, cpusetsize);
>          if (ret)
>                  return -EFAULT;

It can leak 1 bit of information from the kernel stack.  For example
with 16 CPUs, all online, if a 1-byte 0x00 mask is supplied, the
caller can determine whether the second (uninitialized) mask byte is
zero or non-zero due to the cpumask_empty(&cpus) check.

 - Mark

>
> Reviewed-by: Michael Ellerman <mpe at kernel.org>
>
> cheers


From sunilvl at oss.qualcomm.com  Mon Jun 15 21:29:33 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Tue, 16 Jun 2026 09:59:33 +0530
Subject: [PATCH 2/2] riscv: Restart via EFI runtime services when available
In-Reply-To: <20260615-efi_reset_shutdown-v1-2-9414edcbbab0@meta.com>
References: <20260615-efi_reset_shutdown-v1-0-9414edcbbab0@meta.com> <20260615-efi_reset_shutdown-v1-2-9414edcbbab0@meta.com>
Message-ID: <CAB19ukEZhGc=4mi2D1e3FxZdJ_yENGt_=B+2R+3WDkxtT+xmYw@mail.gmail.com>

On Tue, Jun 16, 2026 at 4:59?AM Atish Patra <atish.patra at linux.dev> wrote:
>
> From: Atish Patra <atishp at meta.com>
>
> Firmware-preferred reset and EFI capsule update support requires reset
> via EFI runtime services rather than direction M-mode firmware invocation
> via SBI. Unlike poweroff, restart mechanism is directly controlled from
> machine_restart function though.
>
> Prefer the EFI runtime ResetSystem() service for restart when UEFI
> runtime services are available.
>
> Signed-off-by: Atish Patra <atishp at meta.com>
> ---
>  arch/riscv/kernel/reset.c | 7 +++++++
>  1 file changed, 7 insertions(+)
>
> diff --git a/arch/riscv/kernel/reset.c b/arch/riscv/kernel/reset.c
> index 912288572226..541e2162c85a 100644
> --- a/arch/riscv/kernel/reset.c
> +++ b/arch/riscv/kernel/reset.c
> @@ -3,6 +3,7 @@
>   * Copyright (C) 2012 Regents of the University of California
>   */
>
> +#include <linux/efi.h>
>  #include <linux/reboot.h>
>  #include <linux/pm.h>
>
> @@ -17,6 +18,12 @@ EXPORT_SYMBOL(pm_power_off);
>
>  void machine_restart(char *cmd)
>  {
> +       /*
> +        * UpdateCapsule() depends on the system being reset via ResetSystem().
> +        */
> +       if (efi_enabled(EFI_RUNTIME_SERVICES))
> +               efi_reboot(reboot_mode, NULL);
> +
>         do_kernel_restart(cmd);
>         while (1);
>  }
>
LGTM.
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From sunilvl at oss.qualcomm.com  Mon Jun 15 21:29:58 2026
From: sunilvl at oss.qualcomm.com (Sunil V L)
Date: Tue, 16 Jun 2026 09:59:58 +0530
Subject: [PATCH 1/2] riscv: efi: Power off via EFI runtime services when available
In-Reply-To: <20260615-efi_reset_shutdown-v1-1-9414edcbbab0@meta.com>
References: <20260615-efi_reset_shutdown-v1-0-9414edcbbab0@meta.com> <20260615-efi_reset_shutdown-v1-1-9414edcbbab0@meta.com>
Message-ID: <CAB19ukE7QEVLh8-vbAMbEXemnH6ENREWNTFQ1vBBD3GZyF6i0A@mail.gmail.com>

On Tue, Jun 16, 2026 at 4:59?AM Atish Patra <atish.patra at linux.dev> wrote:
>
> From: Atish Patra <atishp at meta.com>
>
> When booted via UEFI with runtime services enabled, EFI Reset Shutdown is
> the firmware-preferred shutdown path: it lets firmware run its own
> shutdown hooks which may invoke SBI SRST extension internally. However,
> RISC-V always powers off via the SBI SRST extension today and EFI runtime
> path is never used even when firmware provides it.
>
> Enable the poweroff via EFI by overriding efi_poweroff_required()
>
> Signed-off-by: Atish Patra <atishp at meta.com>
> ---
>  arch/riscv/kernel/efi.c | 5 +++++
>  1 file changed, 5 insertions(+)
>
> diff --git a/arch/riscv/kernel/efi.c b/arch/riscv/kernel/efi.c
> index b64bf1624a05..2d3cc57b4535 100644
> --- a/arch/riscv/kernel/efi.c
> +++ b/arch/riscv/kernel/efi.c
> @@ -95,3 +95,8 @@ int __init efi_set_mapping_permissions(struct mm_struct *mm,
>                                    md->num_pages << EFI_PAGE_SHIFT,
>                                    set_permissions, md);
>  }
> +
> +bool efi_poweroff_required(void)
> +{
> +       return efi_enabled(EFI_RUNTIME_SERVICES);
> +}
>
Reviewed-by: Sunil V L <sunilvl at oss.qualcomm.com>


From thecharlesjenkins at gmail.com  Mon Jun 15 22:58:26 2026
From: thecharlesjenkins at gmail.com (Charlie Jenkins)
Date: Mon, 15 Jun 2026 22:58:26 -0700
Subject: [PATCH 01/16] riscv: Introduce instruction table generation
In-Reply-To: <87se6tejoe.fsf@yellow.woof>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-1-54b4736a1e77@gmail.com>
 <878q8m1j9y.fsf@yellow.woof>
 <aioJ_5SIXdGQg55R@blinky>
 <87se6tejoe.fsf@yellow.woof>
Message-ID: <ajDmAmq4_hYCDEfp@blinky>

On Thu, Jun 11, 2026 at 07:21:37AM +0200, Nam Cao wrote:
> Charlie Jenkins <thecharlesjenkins at gmail.com> writes:
> > This is a weird one. The Ziclsd extension introduces it for RV32[1]. All
> > of the data is generated from the riscv-unified-db and because it is in
> > the Ziclsd extension, c.ld is included for 32-bit in the c.ld
> > description [2]. 
> 
> Oh :( We probably should amend the base spec to mention that.
> 
> >> > +        compressed_name=${name##c.*}
> >> 	   ^^^^^^^^^^^^^^^
> >> 	   this name is misleading
> >
> > That's fair, I can rename it to be something like "compressed_inst"?
> 
> My issue is that "compressed_name" indicates that it holds the
> compressed variant of the name. But it actually is empty if the
> instruction is compressed, otherwise it is the original instruction name.
> 
> I am not sure what is a better name. Perhaps just inline this to the
> usage below.

Oh I see, I'll come up with a name that is more clear on inline it.

> 
> Nam


From thecharlesjenkins at gmail.com  Mon Jun 15 23:02:11 2026
From: thecharlesjenkins at gmail.com (Charlie Jenkins)
Date: Mon, 15 Jun 2026 23:02:11 -0700
Subject: [PATCH 03/16] riscv: kgdb: Use generated instruction headers
In-Reply-To: <87pl1xehi4.fsf@yellow.woof>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-3-54b4736a1e77@gmail.com>
 <87pl1xehi4.fsf@yellow.woof>
Message-ID: <ajDm49ucbj6mVRo9@blinky>

On Thu, Jun 11, 2026 at 08:08:35AM +0200, Nam Cao wrote:
> Charlie Jenkins via B4 Relay
> <devnull+thecharlesjenkins.gmail.com at kernel.org> writes:
> > +#define riscv_insn_branch(_insn, regs_ptr, _opcode, _pc, _comparison, type)     \
> > +	({                                                                      \
> > +		unsigned long _ret;                                             \
> > +		if ((type)riscv_insn_reg_get_val(                               \
> > +			    regs_ptr,                                           \
> > +			    riscv_insn_##_insn##_extract_xs1(_opcode))          \
> > +			    _comparison(type) riscv_insn_reg_get_val(           \
> > +				    regs_ptr,                                   \
> > +				    riscv_insn_##_insn##_extract_xs2(_opcode))) \
> > +			_ret = riscv_insn_##_insn##_extract_imm(_opcode);       \
> 
> Should be
> 		_ret = _pc + riscv_insn_##_insn##_extract_imm(_opcode);

Hmm I am surprised my test cases didn't catch that. Thank you!

- Charlie

> 
> > +		else                                                            \
> > +			_ret = _pc + 4;                                         \
> > +		_ret;                                                           \
> > +	})
> > +


From thecharlesjenkins at gmail.com  Mon Jun 15 23:06:30 2026
From: thecharlesjenkins at gmail.com (Charlie Jenkins)
Date: Mon, 15 Jun 2026 23:06:30 -0700
Subject: [PATCH 04/16] riscv: kprobes: Use generated instruction headers
In-Reply-To: <87mrx1eh8c.fsf@yellow.woof>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-4-54b4736a1e77@gmail.com>
 <87mrx1eh8c.fsf@yellow.woof>
Message-ID: <ajDn5oINgUzKhELv@blinky>

On Thu, Jun 11, 2026 at 08:14:27AM +0200, Nam Cao wrote:
> Charlie Jenkins via B4 Relay
> <devnull+thecharlesjenkins.gmail.com at kernel.org> writes:
> >  bool __kprobes simulate_c_jr(u32 opcode, unsigned long addr, struct pt_regs *regs)
> >  {
> > -	return simulate_c_jr_jalr(opcode, addr, regs, false);
> > +	unsigned long next_addr;
> > +	unsigned long *regs_ptr = (unsigned long *)regs;
> > +
> > +	next_addr = regs_ptr[riscv_insn_c_jr_extract_xs1(opcode)];
> > +	instruction_pointer_set(regs, next_addr);
> > +
> > +	regs->ra = addr + 2;
> 
> c.jr does not change ra.

Looks like my tests need some work :/

> 
> > +	return true;
> >  }
> 
> We have CONFIG_RISCV_KPROBES_KUNIT now, please try that.

I can try to extend those to cover more.

- Charlie

> 
> Nam


From xb at ultrarisc.com  Mon Jun 15 23:17:58 2026
From: xb at ultrarisc.com (Xie Bo)
Date: Tue, 16 Jun 2026 14:17:58 +0800
Subject: [PATCH] RISC-V: KVM: Fix lost virtual interrupts during IRQ sync
Message-ID: <178159067899.108868.8176174463274678253@ultrarisc.com>

RISC-V KVM tracks guest pending interrupts with irqs_pending and
irqs_pending_mask. The existing code uses atomic bitops and models the
state as a multiple-producer, single-consumer queue where the vCPU is
the consumer.

The atomic bitops make each individual bitmap operation atomic, but
they do not make the pair of irqs_pending and irqs_pending_mask an
atomic state transition. The vCPU interrupt sync path is also not a
pure consumer: it writes both bitmaps when it reflects guest-visible
HVIP changes back into KVM state.

For example, kvm_riscv_vcpu_set_interrupt() can set IRQ_VS_SOFT in
irqs_pending while the target vCPU is concurrently syncing a
guest-cleared HVIP.VSSIP bit. If sync observes irqs_pending_mask before
the producer sets it, sync can set the mask and clear irqs_pending. The
producer then sets the mask and kicks the vCPU, but the pending bit has
already been lost. A subsequent flush updates HVIP without VSSIP, and
the guest can remain blocked in WFI even though it has work queued.

Serialize all updates to irqs_pending and irqs_pending_mask with a
per-vCPU raw spinlock. This intentionally replaces the lockless
pending/mask protocol with one small critical section per vCPU, so the
pending bit and the dirty mask are updated as one state transition.
Use the same lock for sync, flush, reset, and userspace CSR writes that
clear the dirty mask, so a newly injected interrupt cannot be
overwritten by a concurrent HVIP sync.

Fixes: cce69aff689e ("RISC-V: KVM: Implement VCPU interrupts and requests handling")
Cc: stable at vger.kernel.org
Signed-off-by: Xie Bo <xb at ultrarisc.com>
---
 arch/riscv/include/asm/kvm_host.h | 10 +++++-----
 arch/riscv/kvm/aia.c              | 28 +++++++++++++++++++++-------
 arch/riscv/kvm/vcpu.c             | 27 ++++++++++++++++++++++-----
 arch/riscv/kvm/vcpu_onereg.c      | 13 +++++++++----
 4 files changed, 57 insertions(+), 21 deletions(-)

diff --git a/arch/riscv/include/asm/kvm_host.h b/arch/riscv/include/asm/kvm_host.h
index 75b0a951c..97e42645c 100644
--- a/arch/riscv/include/asm/kvm_host.h
+++ b/arch/riscv/include/asm/kvm_host.h
@@ -207,13 +207,13 @@ struct kvm_vcpu_arch {
 	/*
 	 * VCPU interrupts
 	 *
-	 * We have a lockless approach for tracking pending VCPU interrupts
-	 * implemented using atomic bitops. The irqs_pending bitmap represent
-	 * pending interrupts whereas irqs_pending_mask represent bits changed
-	 * in irqs_pending. Our approach is modeled around multiple producer
-	 * and single consumer problem where the consumer is the VCPU itself.
+	 * The irqs_pending bitmap represents pending interrupts whereas
+	 * irqs_pending_mask represents bits changed in irqs_pending. Updates
+	 * to these bitmaps are serialized so vcpu interrupt sync/flush cannot
+	 * drop a newly injected interrupt while syncing guest-visible HVIP.
 	 */
 #define KVM_RISCV_VCPU_NR_IRQS	64
+	raw_spinlock_t irqs_pending_lock;
 	DECLARE_BITMAP(irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
 	DECLARE_BITMAP(irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
 
diff --git a/arch/riscv/kvm/aia.c b/arch/riscv/kvm/aia.c
index 5ec503288..821d2cb6d 100644
--- a/arch/riscv/kvm/aia.c
+++ b/arch/riscv/kvm/aia.c
@@ -50,17 +50,21 @@ void kvm_riscv_vcpu_aia_flush_interrupts(struct kvm_vcpu *vcpu)
 {
 	struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
 	unsigned long mask, val;
+	unsigned long flags;
 
 	if (!kvm_riscv_aia_available())
 		return;
 
-	if (READ_ONCE(vcpu->arch.irqs_pending_mask[1])) {
-		mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[1], 0);
-		val = READ_ONCE(vcpu->arch.irqs_pending[1]) & mask;
+	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+	mask = vcpu->arch.irqs_pending_mask[1];
+	if (mask) {
+		vcpu->arch.irqs_pending_mask[1] = 0;
+		val = vcpu->arch.irqs_pending[1] & mask;
 
 		csr->hviph &= ~mask;
 		csr->hviph |= val;
 	}
+	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
 }
 
 void kvm_riscv_vcpu_aia_sync_interrupts(struct kvm_vcpu *vcpu)
@@ -205,6 +209,9 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
 {
 	struct kvm_vcpu_aia_csr *csr = &vcpu->arch.aia_context.guest_csr;
 	unsigned long regs_max = sizeof(struct kvm_riscv_aia_csr) / sizeof(unsigned long);
+#ifdef CONFIG_32BIT
+	unsigned long flags;
+#endif
 
 	if (!riscv_isa_extension_available(vcpu->arch.isa, SSAIA))
 		return -ENOENT;
@@ -214,11 +221,18 @@ int kvm_riscv_vcpu_aia_set_csr(struct kvm_vcpu *vcpu,
 	reg_num = array_index_nospec(reg_num, regs_max);
 
 	if (kvm_riscv_aia_available()) {
-		((unsigned long *)csr)[reg_num] = val;
-
 #ifdef CONFIG_32BIT
-		if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph))
-			WRITE_ONCE(vcpu->arch.irqs_pending_mask[1], 0);
+		if (reg_num == KVM_REG_RISCV_CSR_AIA_REG(siph)) {
+			raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+			((unsigned long *)csr)[reg_num] = val;
+			vcpu->arch.irqs_pending_mask[1] = 0;
+			raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock,
+						   flags);
+		} else {
+			((unsigned long *)csr)[reg_num] = val;
+		}
+#else
+		((unsigned long *)csr)[reg_num] = val;
 #endif
 	}
 
diff --git a/arch/riscv/kvm/vcpu.c b/arch/riscv/kvm/vcpu.c
index a73690eda..b04730ccd 100644
--- a/arch/riscv/kvm/vcpu.c
+++ b/arch/riscv/kvm/vcpu.c
@@ -80,6 +80,7 @@ static void kvm_riscv_vcpu_context_reset(struct kvm_vcpu *vcpu,
 
 static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
 {
+	unsigned long flags;
 	bool loaded;
 
 	/**
@@ -104,8 +105,10 @@ static void kvm_riscv_reset_vcpu(struct kvm_vcpu *vcpu, bool kvm_sbi_reset)
 
 	kvm_riscv_vcpu_aia_reset(vcpu);
 
+	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
 	bitmap_zero(vcpu->arch.irqs_pending, KVM_RISCV_VCPU_NR_IRQS);
 	bitmap_zero(vcpu->arch.irqs_pending_mask, KVM_RISCV_VCPU_NR_IRQS);
+	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
 
 	kvm_riscv_vcpu_pmu_reset(vcpu);
 
@@ -151,6 +154,7 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu)
 
 	/* Setup VCPU hfence queue */
 	spin_lock_init(&vcpu->arch.hfence_lock);
+	raw_spin_lock_init(&vcpu->arch.irqs_pending_lock);
 
 	spin_lock_init(&vcpu->arch.reset_state.lock);
 
@@ -352,14 +356,18 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
 {
 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
 	unsigned long mask, val;
+	unsigned long flags;
 
-	if (READ_ONCE(vcpu->arch.irqs_pending_mask[0])) {
-		mask = xchg_acquire(&vcpu->arch.irqs_pending_mask[0], 0);
-		val = READ_ONCE(vcpu->arch.irqs_pending[0]) & mask;
+	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+	mask = vcpu->arch.irqs_pending_mask[0];
+	if (mask) {
+		vcpu->arch.irqs_pending_mask[0] = 0;
+		val = vcpu->arch.irqs_pending[0] & mask;
 
 		csr->hvip &= ~mask;
 		csr->hvip |= val;
 	}
+	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
 
 	/* Flush AIA high interrupts */
 	kvm_riscv_vcpu_aia_flush_interrupts(vcpu);
@@ -368,6 +376,7 @@ void kvm_riscv_vcpu_flush_interrupts(struct kvm_vcpu *vcpu)
 void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
 {
 	unsigned long hvip;
+	unsigned long flags;
 	struct kvm_vcpu_arch *v = &vcpu->arch;
 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
 
@@ -376,6 +385,7 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
 
 	/* Sync-up HVIP.VSSIP bit changes does by Guest */
 	hvip = ncsr_read(CSR_HVIP);
+	raw_spin_lock_irqsave(&v->irqs_pending_lock, flags);
 	if ((csr->hvip ^ hvip) & (1UL << IRQ_VS_SOFT)) {
 		if (hvip & (1UL << IRQ_VS_SOFT)) {
 			if (!test_and_set_bit(IRQ_VS_SOFT,
@@ -394,6 +404,7 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
 		    !test_and_set_bit(IRQ_PMU_OVF, v->irqs_pending_mask))
 			clear_bit(IRQ_PMU_OVF, v->irqs_pending);
 	}
+	raw_spin_unlock_irqrestore(&v->irqs_pending_lock, flags);
 
 	/* Sync-up AIA high interrupts */
 	kvm_riscv_vcpu_aia_sync_interrupts(vcpu);
@@ -404,6 +415,8 @@ void kvm_riscv_vcpu_sync_interrupts(struct kvm_vcpu *vcpu)
 
 int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
 {
+	unsigned long flags;
+
 	/*
 	 * We only allow VS-mode software, timer, and external
 	 * interrupts when irq is one of the local interrupts
@@ -416,9 +429,10 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
 	    irq != IRQ_PMU_OVF)
 		return -EINVAL;
 
+	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
 	set_bit(irq, vcpu->arch.irqs_pending);
-	smp_mb__before_atomic();
 	set_bit(irq, vcpu->arch.irqs_pending_mask);
+	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
 
 	kvm_vcpu_kick(vcpu);
 
@@ -427,6 +441,8 @@ int kvm_riscv_vcpu_set_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
 
 int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
 {
+	unsigned long flags;
+
 	/*
 	 * We only allow VS-mode software, timer, counter overflow and external
 	 * interrupts when irq is one of the local interrupts
@@ -439,9 +455,10 @@ int kvm_riscv_vcpu_unset_interrupt(struct kvm_vcpu *vcpu, unsigned int irq)
 	    irq != IRQ_PMU_OVF)
 		return -EINVAL;
 
+	raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
 	clear_bit(irq, vcpu->arch.irqs_pending);
-	smp_mb__before_atomic();
 	set_bit(irq, vcpu->arch.irqs_pending_mask);
+	raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
 
 	return 0;
 }
diff --git a/arch/riscv/kvm/vcpu_onereg.c b/arch/riscv/kvm/vcpu_onereg.c
index bb920e892..cba368294 100644
--- a/arch/riscv/kvm/vcpu_onereg.c
+++ b/arch/riscv/kvm/vcpu_onereg.c
@@ -298,6 +298,7 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
 {
 	struct kvm_vcpu_csr *csr = &vcpu->arch.guest_csr;
 	unsigned long regs_max = sizeof(struct kvm_riscv_csr) / sizeof(unsigned long);
+	unsigned long flags;
 
 	if (reg_num >= regs_max)
 		return -ENOENT;
@@ -309,10 +310,14 @@ static int kvm_riscv_vcpu_general_set_csr(struct kvm_vcpu *vcpu,
 		reg_val <<= VSIP_TO_HVIP_SHIFT;
 	}
 
-	((unsigned long *)csr)[reg_num] = reg_val;
-
-	if (reg_num == KVM_REG_RISCV_CSR_REG(sip))
-		WRITE_ONCE(vcpu->arch.irqs_pending_mask[0], 0);
+	if (reg_num == KVM_REG_RISCV_CSR_REG(sip)) {
+		raw_spin_lock_irqsave(&vcpu->arch.irqs_pending_lock, flags);
+		((unsigned long *)csr)[reg_num] = reg_val;
+		vcpu->arch.irqs_pending_mask[0] = 0;
+		raw_spin_unlock_irqrestore(&vcpu->arch.irqs_pending_lock, flags);
+	} else {
+		((unsigned long *)csr)[reg_num] = reg_val;
+	}
 
 	return 0;
 }

base-commit: 481329ec5b31d2c48ac6b8b703c8008133884c7e
-- 
2.54.0



From lirongqing at baidu.com  Tue Jun 16 00:26:17 2026
From: lirongqing at baidu.com (lirongqing)
Date: Tue, 16 Jun 2026 15:26:17 +0800
Subject: [PATCH][v2] ACPI: processor_idle: Mark LPI enter functions as __cpuidle
Message-ID: <20260616072617.2272-1-lirongqing@baidu.com>

From: Li RongQing <lirongqing at baidu.com>

When function tracing or Kprobes is enabled, entering an ACPI Low
Power Idle (LPI) state triggers the following RCU splat:

  RCU not on for: acpi_idle_lpi_enter+0x4/0xd8
  WARNING: CPU: 8 PID: 0 at include/linux/trace_recursion.h:162 function_trace_call+0x1e8/0x228

The acpi_idle_lpi_enter() function is invoked within the cpuidle
path after RCU has already been disabled for the current local CPU.
Consequently, ftrace's function_trace_call() expects RCU to be
actively watching before recording trace data, emitting a warning
if it is not.

Fix this by annotating acpi_idle_lpi_enter(), the generic __weak
stub, and the RISC-V implementation of acpi_processor_ffh_lpi_enter()
with __cpuidle. This moves these functions into the '.cpuidle.text'
section, implicitly disabling ftrace instrumentation (notrace) along
this sensitive path and preventing trace-induced RCU warnings during
idle entry.

Fixes: a36a7fecfe60 ("ACPI / processor_idle: Add support for Low Power Idle(LPI) states")
Signed-off-by: Li RongQing <lirongqing at baidu.com>
---
Diff with v1: add __cpuidle to acpi_processor_ffh_lpi_enter

 drivers/acpi/processor_idle.c | 4 ++--
 drivers/acpi/riscv/cpuidle.c  | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 390ab5f..4482cf2 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -1143,7 +1143,7 @@ static int acpi_processor_get_lpi_info(struct acpi_processor *pr)
 	return 0;
 }
 
-int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
+int __weak __cpuidle acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
 {
 	return -ENODEV;
 }
@@ -1156,7 +1156,7 @@ int __weak acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
  *
  * Return: 0 for success or negative value for error
  */
-static int acpi_idle_lpi_enter(struct cpuidle_device *dev,
+static int __cpuidle acpi_idle_lpi_enter(struct cpuidle_device *dev,
 			       struct cpuidle_driver *drv, int index)
 {
 	struct acpi_processor *pr;
diff --git a/drivers/acpi/riscv/cpuidle.c b/drivers/acpi/riscv/cpuidle.c
index 624f9bb..c76dbab 100644
--- a/drivers/acpi/riscv/cpuidle.c
+++ b/drivers/acpi/riscv/cpuidle.c
@@ -66,7 +66,7 @@ int acpi_processor_ffh_lpi_probe(unsigned int cpu)
 	return acpi_cpu_init_idle(cpu);
 }
 
-int acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
+int __cpuidle acpi_processor_ffh_lpi_enter(struct acpi_lpi_state *lpi)
 {
 	u32 state = lpi->address;
 
-- 
2.9.4



From viresh.kumar at linaro.org  Tue Jun 16 01:19:07 2026
From: viresh.kumar at linaro.org (Viresh Kumar)
Date: Tue, 16 Jun 2026 13:49:07 +0530
Subject: [PATCH v3 1/2] cpufreq: spacemit: Add K1 cpufreq driver
In-Reply-To: <DJ9M2IDYE6XZ.20RN5AFBYNB9Y@mailbox.org>
References: <20260612-shadow-deps-v3-0-2f3ba88611ff@mailbox.org>
 <20260612-shadow-deps-v3-1-2f3ba88611ff@mailbox.org>
 <bd4s2icqgusnuujvrpoag4cniy3g2e4bumecqxt5yffl77aqpq@kxg4dj4c2wk3>
 <DJ9EFPG561VZ.1WGRYYHJ2W9J9@mailbox.org>
 <wjwkykv555gkeqxabsqcdfn4lomcopawsv7bgm4bydc5likhjs@p3ca3p7wbri5>
 <DJ9M2IDYE6XZ.20RN5AFBYNB9Y@mailbox.org>
Message-ID: <nffvtnb765pa72xcfhmxe3wepxpld3e6265s7imvldbwounkzk@jmrrhtrwau34>

On 15-06-26, 20:11, Shuwei Wu wrote:
> With two cpufreq-dt policies (one per cluster) and these ranges, neither cluster
> blocks the other. Tested on BPI-F3 and OrangePi Rv2 boards, works as expected.
> 
> Does this look good to you, or would you prefer a different approach?

Looks correct.

-- 
viresh


From namcao at linutronix.de  Tue Jun 16 02:23:46 2026
From: namcao at linutronix.de (Nam Cao)
Date: Tue, 16 Jun 2026 11:23:46 +0200
Subject: [PATCH] riscv: drop __init from
 vec_check_unaligned_access_speed_all_cpus
In-Reply-To: <CAEev2e8AH8W_M4=9N8vLJyvRqwGG=p8O-jVa7tdM3LjCRj=6aw@mail.gmail.com>
References: <20260612-vec_unaligned_drop_init-v1-1-df969210ae34@oss.tenstorrent.com>
 <87ecibwiz6.fsf@yellow.woof>
 <CAEev2e8AH8W_M4=9N8vLJyvRqwGG=p8O-jVa7tdM3LjCRj=6aw@mail.gmail.com>
Message-ID: <87fr2mvnx9.fsf@yellow.woof>

Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com> writes:
> I think the difference seems too small here to draw any conclusions.

So the difference is in the noises. That's good to know, thanks for
testing.

> This is only a 4 core CPU.

The probe is done in parallel, so the number of CPUs won't make any
noticeable difference.

I will send patches in this direction instead.

Thanks,
Nam


From david.laight.linux at gmail.com  Tue Jun 16 03:36:51 2026
From: david.laight.linux at gmail.com (David Laight)
Date: Tue, 16 Jun 2026 11:36:51 +0100
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260615123821.373248-1-guoren@kernel.org>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
	<20260615123821.373248-1-guoren@kernel.org>
Message-ID: <20260616113651.1048a19a@pumpkin>

On Mon, 15 Jun 2026 12:38:17 +0000
Guo Ren <guoren at kernel.org> wrote:

> Hi Zhanpeng Zhang,
..
> 3. Only performance-monitoring counters require 64-bit IO access or the
> high-low-high do-while retry strategy. For ordinary status and control
> MMIO registers, a single read is sufficient.

Actually this sequence should be enough for a counter:
	hi = read_hi();
	lo = read_lo();
	if (hi != read_hi()) {
		// Pick a value that happened while doing the reads.
		hi++;
		lo = 0;
	}

-- David


From aesteve at redhat.com  Tue Jun 16 04:44:01 2026
From: aesteve at redhat.com (Albert Esteve)
Date: Tue, 16 Jun 2026 13:44:01 +0200
Subject: [PATCH v13 0/4] kunit: Add support for suppressing warning backtraces
In-Reply-To: <20260515-kunit_add_support-v13-0-18ee42f96e7b@redhat.com>
References: <20260515-kunit_add_support-v13-0-18ee42f96e7b@redhat.com>
Message-ID: <CADSE00+typ3Zi5Vf0Z276+e0G7PuS7mt7oA9h5awBu3YgYKw0g@mail.gmail.com>

On Fri, May 15, 2026 at 2:29?PM Albert Esteve <aesteve at redhat.com> wrote:
>
> Some unit tests intentionally trigger warning backtraces by passing bad
> parameters to kernel API functions. Such unit tests typically check the
> return value from such calls, not the existence of the warning backtrace.
>
> Such intentionally generated warning backtraces are neither desirable
> nor useful for a number of reasons:
> - They can result in overlooked real problems.
> - A warning that suddenly starts to show up in unit tests needs to be
>   investigated and has to be marked to be ignored, for example by
>   adjusting filter scripts. Such filters are ad hoc because there is
>   no real standard format for warnings. On top of that, such filter
>   scripts would require constant maintenance.
>
> One option to address the problem would be to add messages such as
> "expected warning backtraces start/end here" to the kernel log.
> However, that would again require filter scripts, might result in
> missing real problematic warning backtraces triggered while the test
> is running, and the irrelevant backtrace(s) would still clog the
> kernel log.
>
> Solve the problem by providing a means to suppress warning backtraces
> originating from the current kthread while executing test code.
> Since each KUnit test runs in its own kthread, this effectively scopes
> suppression to the test that enabled it, without requiring any
> architecture-specific code.
>
> Overview:
> Patch#1 Introduces the suppression infrastructure integrated into
>         KUnit's hook mechanism.
> Patch#2 Adds selftests to validate the functionality.
> Patch#3 Demonstrates real-world usage in the DRM subsystem.
> Patch#4 Documents the new API and usage guidelines.
>
> Design Notes:
> Suppression is integrated into the existing KUnit hooks infrastructure,
> reusing the kunit_running static branch for zero overhead
> when no tests are running. The implementation lives entirely in the
> kunit module; only a static-inline wrapper and a function pointer
> slot are added to built-in code.
>
> Suppression is checked at three points in the warning path:
> - In `warn_slowpath_fmt()` (kernel/panic.c), for architectures without
>   __WARN_FLAGS. The check runs before any output, fully suppressing
>   both message and backtrace.
> - In `__warn_printk()` (kernel/panic.c), for architectures that define
>   __WARN_FLAGS but not their own __WARN_printf (arm64, loongarch,
>   parisc, powerpc, riscv, sh). The check suppresses the warning message
>   text that is printed before the trap enters __report_bug().
> - In `__report_bug()` (lib/bug.c), for architectures that define
>   __WARN_FLAGS. The check runs before `__warn()` is called, suppressing
>   the backtrace and stack dump.
>
> To avoid double-counting on architectures where both `__warn_printk()`
> and `__report_bug()` run for the same warning, the hook takes a bool
> parameter: true to increment the suppression counter, false to suppress
> without counting.
>
> The suppression state is dynamically allocated via kunit_kzalloc() and
> tied to the KUnit test lifecycle via `kunit_add_action()`, ensuring
> automatic cleanup at test exit. Writer-side access to the global
> suppression list is serialized with a spinlock; readers use RCU.
>
> Two API forms are provided:
> - kunit_warning_suppress(test) { ... }: scoped blocks with automatic
>   cleanup. The suppression handle is not accessible outside the block,
>   so warning counts (if needed) must be checked inside. Multiple
>   sequential suppression blocks are allowed.
> - kunit_start/end_suppress_warning(test): direct functions that return
>   an explicit handle. Use when the handle needs to be retained, or passed
>   across helpers. Multiple sequential suppression blocks are allowed.
>
> This series is based on the RFC patch and subsequent discussion at
> https://patchwork.kernel.org/project/linux-kselftest/patch/02546e59-1afe-4b08-ba81-d94f3b691c9a at moroto.mountain/
> and offers a more comprehensive solution of the problem discussed there.
>
> Changes since RFC:
> - Introduced CONFIG_KUNIT_SUPPRESS_BACKTRACE
> - Minor cleanups and bug fixes
> - Added support for all affected architectures
> - Added support for counting suppressed warnings
> - Added unit tests using those counters
> - Added patch to suppress warning backtraces in dev_addr_lists tests
>
> Changes since v1:
> - Rebased to v6.9-rc1
> - Added Tested-by:, Acked-by:, and Reviewed-by: tags
>   [I retained those tags since there have been no functional changes]
> - Introduced KUNIT_SUPPRESS_BACKTRACE configuration option, enabled by
>   default.
>
> Changes since v2:
> - Rebased to v6.9-rc2
> - Added comments to drm warning suppression explaining why it is needed.
> - Added patch to move conditional code in arch/sh/include/asm/bug.h
>   to avoid kerneldoc warning
> - Added architecture maintainers to Cc: for architecture specific patches
> - No functional changes
>
> Changes since v3:
> - Rebased to v6.14-rc6
> - Dropped net: "kunit: Suppress lock warning noise at end of dev_addr_lists tests"
>   since 3db3b62955cd6d73afde05a17d7e8e106695c3b9
> - Added __kunit_ and KUNIT_ prefixes.
> - Tested on interessed architectures.
>
> Changes since v4:
> - Rebased to v6.15-rc7
> - Dropped all code in __report_bug()
> - Moved all checks in WARN*() macros.
> - Dropped all architecture specific code.
> - Made __kunit_is_suppressed_warning nice to noinstr functions.
>
> Changes since v5:
> - Rebased to v7.0-rc3
> - Added RCU protection for the suppressed warnings list.
> - Added static key and branching optimization.
> - Removed custom `strcmp` implementation and reworked
>   __kunit_is_suppressed_warning() entrypoint function.
>
> Changes since v6:
> - Moved suppression checks from WARN*() macros to warn_slowpath_fmt()
>   and __report_bug().
> - Replaced stack-allocated suppression struct with kunit_kzalloc() heap
>   allocation tied to the KUnit test lifecycle.
> - Changed suppression strategy from function-name matching to task-scoped:
>   all warnings on the current task are suppressed between START and END,
>   rather than only warnings originating from a specific named function.
> - Simplified macro API: removed KUNIT_DECLARE_SUPPRESSED_WARNING(),
>   the START macro now takes (test) and handles allocation internally.
> - Removed static key and branching optiomization, as by the time it
>   was executed, callers are already in warn slowpaths.
> - Link to v6: https://lore.kernel.org/r/20260317-kunit_add_support-v6-0-dd22aeb3fe5d at redhat.com
>
> Changes since v7:
> - Integrated suppression into existing KUnit hooks infrastructure
> - Removed CONFIG_KUNIT_SUPPRESS_BACKTRACE
> - Added suppression check in __warn_printk()
> - Added spinlock for writer-side RCU protection
> - Replaced explicit rcu_read_lock/unlock with guard(rcu)()
> - Added scoped API (kunit_warning_suppress) using __cleanup attribute
> - Updated DRM patch to use scoped API
> - Expanded self-tests: incremental counting, cross-kthread isolation
> - Rewrote documentation covering all three API forms with examples
> - Link to v7: https://lore.kernel.org/r/20260420-kunit_add_support-v7-0-e8bc6e0f70de at redhat.com
>
> Changes since v8:
> - Rebased to v7.1-rc2
> - Remove KUNIT_START/END_SUPPRESSED_WARNING() macros
> - Add KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT checks to drm tests
> - Link to v8: https://lore.kernel.org/r/20260504-kunit_add_support-v8-0-3e5957cdd235 at redhat.com
>
> Changes since v9:
> - Fix silent false-pass when kunit_start_suppress_warning() returns NULL
> - Fix RCU lockdep splat for kunit_is_suppressed_warning() calls
> - Move disable_trace_on_warning() in __report_bug()
> - Make suppress counter atomic
> - Mark helper warn functions in selftest as noinline
> - Add kunit_skip() for CONFIG_BUG=n in selftests
> - Fix potentially uninitialized data.was_active in kthread seltest
> - Add kthread_stop() in kthread selftest early exit
> - Initialize scaling_factor to INT_MIN in DRM scaling tests
> - Add include for bool in test-bug.h to fix CONFIG_KUNIT=n case
> - Link to v9: https://lore.kernel.org/r/20260508-kunit_add_support-v9-0-99df7aa880f6 at redhat.com
>
> Changes since v10:
> - Remove synchronize_rcu() to avoid sleeping in atomic context
> - Pin task_struct refcount to prevent ABA false-positive matches
> - Loop in suppression selftest to prevent use-after-free on kthread exit
> - Skip DRM rect tests on CONFIG_BUG=n
> - Link to v10: https://lore.kernel.org/r/20260513-kunit_add_support-v10-0-e379d206c8cd at redhat.com
>
> Changes since v11:
> - Use call_rcu() to defer free without blocking
> - Remove #ifdef CONFIG_KUNIT guard in lib/bug.c
> - Remove stale config checks from selftest
> - Replace skip on DRM rect tests with conditional expectation
> - Link to v11: https://lore.kernel.org/r/20260514-kunit_add_support-v11-0-b36a530a6d8f at redhat.com
>
> Changes since v12:
> - Reverted to the v9 synchronize_rcu() approach
> - Add in_task() check at the top of __kunit_is_suppressed_warning_impl()
> - Link to v12: https://lore.kernel.org/r/20260515-kunit_add_support-v12-0-a216dc228be8 at redhat.com

Hi all,

I am not sure if there is a decision to merge this series or if any
work remains to be done.

I reckon I sent a few versions back-to-back last time as I was
struggling with Sashiko. However, there are no significant changes,
the core strategy remains unchanged, involving only the addition of
safety checks and the removal of some redundancies to satisfy the AI.
I am just clarifying in case the last versions/respins were unclear. I
tried running AI reviews locally but Sashiko always found more issues
than my local model could.

BR,
Albert.

> --
> 2.34.1
>
> ---
> To: Brendan Higgins <brendan.higgins at linux.dev>
> To: David Gow <david at davidgow.net>
> To: Rae Moar <raemoar63 at gmail.com>
> To: Andrew Morton <akpm at linux-foundation.org>
> To: Paul Walmsley <pjw at kernel.org>
> To: Palmer Dabbelt <palmer at dabbelt.com>
> To: Albert Ou <aou at eecs.berkeley.edu>
> To: Alexandre Ghiti <alex at ghiti.fr>
> To: Maarten Lankhorst <maarten.lankhorst at linux.intel.com>
> To: Maxime Ripard <mripard at kernel.org>
> To: Thomas Zimmermann <tzimmermann at suse.de>
> To: David Airlie <airlied at gmail.com>
> To: Simona Vetter <simona at ffwll.ch>
> To: Jonathan Corbet <corbet at lwn.net>
> To: Shuah Khan <skhan at linuxfoundation.org>
> Cc: linux-kernel at vger.kernel.org
> Cc: linux-kselftest at vger.kernel.org
> Cc: kunit-dev at googlegroups.com
> Cc: linux-riscv at lists.infradead.org
> Cc: dri-devel at lists.freedesktop.org
> Cc: workflows at vger.kernel.org
> Cc: linux-doc at vger.kernel.org
>
> ---
>
> ---
> Alessandro Carminati (1):
>       bug/kunit: Core support for suppressing warning backtraces
>
> Guenter Roeck (3):
>       kunit: Add backtrace suppression self-tests
>       drm: Suppress intentional warning backtraces in scaling unit tests
>       kunit: Add documentation for warning backtrace suppression API
>
>  Documentation/dev-tools/kunit/usage.rst |  46 +++++++-
>  drivers/gpu/drm/tests/drm_rect_test.c   |  36 +++++-
>  include/kunit/test-bug.h                |  26 +++++
>  include/kunit/test.h                    |  98 ++++++++++++++++
>  kernel/panic.c                          |  11 ++
>  lib/bug.c                               |  12 +-
>  lib/kunit/Makefile                      |   4 +-
>  lib/kunit/backtrace-suppression-test.c  | 192 ++++++++++++++++++++++++++++++++
>  lib/kunit/bug.c                         | 127 +++++++++++++++++++++
>  lib/kunit/hooks-impl.h                  |   2 +
>  10 files changed, 544 insertions(+), 10 deletions(-)
> ---
> base-commit: 74fe02ce122a6103f207d29fafc8b3a53de6abaf
> change-id: 20260312-kunit_add_support-2f35806b19dd
>
> Best regards,
> --
> Albert Esteve <aesteve at redhat.com>
>



From pinkesh.vaghela at einfochips.com  Tue Jun 16 04:53:57 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Tue, 16 Jun 2026 11:53:57 +0000
Subject: [PATCH 2/7] riscv: dts: eswin: add clock generator for EIC7700
 SoC
In-Reply-To: <20260615-overshot-pellet-5e527a14133e@spud>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
 <20260615122016.1110206-3-pinkesh.vaghela@einfochips.com>
 <20260615-overshot-pellet-5e527a14133e@spud>
Message-ID: <SJ2PR04MB8896D17DEC731A635C0856F383E52@SJ2PR04MB8896.namprd04.prod.outlook.com>

Hi Conor,

Thanks for your time to review the patch.

On Mon, Jun 15, 2026 at 10:01 PM +0530, Conor Dooley wrote:
> On Mon, Jun 15, 2026 at 05:50:11PM +0530, Pinkesh Vaghela wrote:
> > From: Pritesh Patel <pritesh.patel at einfochips.com>
> >
> > Add clock generator node for EIC7700 SoC.
> > HiFive Premier P550 boards have 24MHz crystal oscillator to provide
> > the input clock.
> >
> > Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
> > Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
> > ---
> >  .../boot/dts/eswin/eic7700-hifive-premier-p550.dts  |  5 +++++
> >  arch/riscv/boot/dts/eswin/eic7700.dtsi              | 13 +++++++++++++
> >  2 files changed, 18 insertions(+)
> >
> > diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > index 131ed1fc6b2e..1fb92f0e7c55 100644
> > --- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > +++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > @@ -20,6 +20,11 @@ chosen {
> >  	};
> >  };
> >
> > +&xtal {
> > +	clock-frequency = <24000000>;
> > +	clock-output-names = "xtal24m";
> > +};
> > +
> >  &uart0 {
> >  	status = "okay";
> >  };
> > diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > index 430a210f01e6..a7ebb1115958 100644
> > --- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > +++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > @@ -4,6 +4,7 @@
> >   */
> >
> >  /dts-v1/;
> > +#include <dt-bindings/clock/eswin,eic7700-clock.h>
> >  #include <dt-bindings/reset/eswin,eic7700-reset.h>
> >
> >  / {
> > @@ -203,6 +204,11 @@ pmu {
> >  				<0x00000000 0x0000000f 0xfffffffc 0x000000ff
> 0x00000078>;
> >  	};
> >
> > +	xtal: oscillator {
> 
> Sashiko feedback here on making this clk-<hz> or clk-<something> should be
> implemented.

We will change this to "clock-24m" in v2 patch

Regards,
Pinkesh

> 
> > +		compatible = "fixed-clock";
> > +		#clock-cells = <0>;
> > +	};
> > +
> >  	soc {
> >  		compatible = "simple-bus";
> >  		ranges;
> > @@ -343,6 +349,13 @@ gpioD: gpio-port at 3 {
> >  			};
> >  		};
> >
> > +		clk: clock-controller at 51828000 {
> > +			compatible = "eswin,eic7700-clock";
> > +			reg = <0x0 0x51828000 0x0 0x300>;
> > +			clocks = <&xtal>;
> > +			#clock-cells = <1>;
> > +		};
> > +
> >  		reset: reset-controller at 51828300 {
> >  			compatible = "eswin,eic7700-reset";
> >  			reg = <0x0 0x51828300 0x0 0x200>;
> > --
> > 2.34.1
> >


From pinkesh.vaghela at einfochips.com  Tue Jun 16 04:57:33 2026
From: pinkesh.vaghela at einfochips.com (Pinkesh Vaghela)
Date: Tue, 16 Jun 2026 11:57:33 +0000
Subject: [PATCH 6/7] riscv: dts: eswin: add I2C controller support
In-Reply-To: <20260615-lumpiness-profusely-155422288c31@spud>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
 <20260615122016.1110206-7-pinkesh.vaghela@einfochips.com>
 <20260615-lumpiness-profusely-155422288c31@spud>
Message-ID: <SJ2PR04MB8896A5877CCFC177FA5D5A9583E52@SJ2PR04MB8896.namprd04.prod.outlook.com>

Hi Conor,

On Mon, Jun 15, 2026 at 10:05 PM +0530, Conor Dooley wrote:
> On Mon, Jun 15, 2026 at 05:50:15PM +0530, Pinkesh Vaghela wrote:
> > From: Pritesh Patel <pritesh.patel at einfochips.com>
> >
> > Add I2C nodes for EIC7700 SoC.
> > Also add nodes for corresponding slave devices in dts file and enable
> > them for HiFive Premier P550 board
> >
> > Signed-off-by: Pritesh Patel <pritesh.patel at einfochips.com>
> > Signed-off-by: Pinkesh Vaghela <pinkesh.vaghela at einfochips.com>
> > ---
> >  .../dts/eswin/eic7700-hifive-premier-p550.dts |  52 ++++++
> >  arch/riscv/boot/dts/eswin/eic7700.dtsi        | 156 ++++++++++++++++++
> >  2 files changed, 208 insertions(+)
> >
> > diff --git a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > index e7bb96e14958..0f0c98474c62 100644
> > --- a/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > +++ b/arch/riscv/boot/dts/eswin/eic7700-hifive-premier-p550.dts
> > @@ -130,6 +130,58 @@ &gpio111_pins {
> >  	input-disable;
> >  };
> >
> > +&aon_i2c0 {
> > +	status = "okay";
> > +
> > +	eeprom at 50 {
> > +		compatible = "atmel,24c02";
> > +		reg = <0x50>;
> > +	};
> > +};
> > +
> > +&aon_i2c1 {
> > +	status = "okay";
> > +
> > +	pac1934 at 10 {
> 
> Generic node name here please. adc I think.

We will change this to "adc at 10" in v2 patch

> 
> > +		compatible = "microchip,pac1934";
> > +		reg = <0x10>;
> > +		#address-cells = <1>;
> > +		#size-cells = <0>;
> > +
> > +		channel at 1 {
> > +			reg = <0x1>;
> > +			shunt-resistor-micro-ohms = <1000>;
> > +			label = "VDD_SOM";
> > +		};
> > +
> > +		channel at 2 {
> > +			reg = <0x2>;
> > +			shunt-resistor-micro-ohms = <1000>;
> > +			label = "VDD_SOC";
> > +		};
> > +
> > +		channel at 3 {
> > +			reg = <0x3>;
> > +			shunt-resistor-micro-ohms = <1000>;
> > +			label = "VDD_CPU";
> > +		};
> > +
> > +		channel at 4 {
> > +			reg = <0x4>;
> > +			shunt-resistor-micro-ohms = <1000>;
> > +			label = "VDD_LPDDR";
> > +		};
> > +	};
> > +
> > +	ina226 at 44 {
> 
> And here. power-sensor.

We will change this to "power-sensor at 44" in v2 patch

> 
> > +		compatible = "ti,ina226";
> > +		reg = <0x44>;
> > +		#io-channel-cells = <1>;
> > +		label = "sys_power";
> > +		shunt-resistor = <1000>;
> > +	};
> > +};
> > +
> >  &pinctrl {
> >  	vrgmii-supply = <&vcc_1v8>;
> >  };
> > diff --git a/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > index f8caf39616b2..28706431b2c0 100644
> > --- a/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > +++ b/arch/riscv/boot/dts/eswin/eic7700.dtsi
> > @@ -315,6 +315,162 @@ uart4: serial at 50940000 {
> >  			status = "disabled";
> >  		};
> >
> > +		i2c0: i2c at 50950000 {
> > +			compatible = "snps,designware-i2c";
> 
> Missing a soc-specific compatible here for all i2c controllers.

We are using generic DesignWare I2C driver for all I2C controllers with no changes required in the driver. Do we still need to add soc-specific compatible for all i2c controllers?

Regards,
Pinkesh

> 
> 
> Cheers,
> Conor.


From david at davidgow.net  Tue Jun 16 05:06:31 2026
From: david at davidgow.net (David Gow)
Date: Tue, 16 Jun 2026 20:06:31 +0800
Subject: [PATCH v13 0/4] kunit: Add support for suppressing warning
 backtraces
In-Reply-To: <CADSE00+typ3Zi5Vf0Z276+e0G7PuS7mt7oA9h5awBu3YgYKw0g@mail.gmail.com>
References: <20260515-kunit_add_support-v13-0-18ee42f96e7b@redhat.com>
 <CADSE00+typ3Zi5Vf0Z276+e0G7PuS7mt7oA9h5awBu3YgYKw0g@mail.gmail.com>
Message-ID: <51f89811-2976-44c7-99f3-5e24d5535aa8@davidgow.net>

Le 16/06/2026 ? 7:44 PM, Albert Esteve a ?crit?:
> On Fri, May 15, 2026 at 2:29?PM Albert Esteve <aesteve at redhat.com> wrote:
>>
>> Some unit tests intentionally trigger warning backtraces by passing bad
>> parameters to kernel API functions. Such unit tests typically check the
>> return value from such calls, not the existence of the warning backtrace.
>>
>> Such intentionally generated warning backtraces are neither desirable
>> nor useful for a number of reasons:
>> - They can result in overlooked real problems.
>> - A warning that suddenly starts to show up in unit tests needs to be
>>   investigated and has to be marked to be ignored, for example by
>>   adjusting filter scripts. Such filters are ad hoc because there is
>>   no real standard format for warnings. On top of that, such filter
>>   scripts would require constant maintenance.
>>
>> One option to address the problem would be to add messages such as
>> "expected warning backtraces start/end here" to the kernel log.
>> However, that would again require filter scripts, might result in
>> missing real problematic warning backtraces triggered while the test
>> is running, and the irrelevant backtrace(s) would still clog the
>> kernel log.
>>
>> Solve the problem by providing a means to suppress warning backtraces
>> originating from the current kthread while executing test code.
>> Since each KUnit test runs in its own kthread, this effectively scopes
>> suppression to the test that enabled it, without requiring any
>> architecture-specific code.
>>
>> Overview:
>> Patch#1 Introduces the suppression infrastructure integrated into
>>         KUnit's hook mechanism.
>> Patch#2 Adds selftests to validate the functionality.
>> Patch#3 Demonstrates real-world usage in the DRM subsystem.
>> Patch#4 Documents the new API and usage guidelines.
>>
>> Design Notes:
>> Suppression is integrated into the existing KUnit hooks infrastructure,
>> reusing the kunit_running static branch for zero overhead
>> when no tests are running. The implementation lives entirely in the
>> kunit module; only a static-inline wrapper and a function pointer
>> slot are added to built-in code.
>>
>> Suppression is checked at three points in the warning path:
>> - In `warn_slowpath_fmt()` (kernel/panic.c), for architectures without
>>   __WARN_FLAGS. The check runs before any output, fully suppressing
>>   both message and backtrace.
>> - In `__warn_printk()` (kernel/panic.c), for architectures that define
>>   __WARN_FLAGS but not their own __WARN_printf (arm64, loongarch,
>>   parisc, powerpc, riscv, sh). The check suppresses the warning message
>>   text that is printed before the trap enters __report_bug().
>> - In `__report_bug()` (lib/bug.c), for architectures that define
>>   __WARN_FLAGS. The check runs before `__warn()` is called, suppressing
>>   the backtrace and stack dump.
>>
>> To avoid double-counting on architectures where both `__warn_printk()`
>> and `__report_bug()` run for the same warning, the hook takes a bool
>> parameter: true to increment the suppression counter, false to suppress
>> without counting.
>>
>> The suppression state is dynamically allocated via kunit_kzalloc() and
>> tied to the KUnit test lifecycle via `kunit_add_action()`, ensuring
>> automatic cleanup at test exit. Writer-side access to the global
>> suppression list is serialized with a spinlock; readers use RCU.
>>
>> Two API forms are provided:
>> - kunit_warning_suppress(test) { ... }: scoped blocks with automatic
>>   cleanup. The suppression handle is not accessible outside the block,
>>   so warning counts (if needed) must be checked inside. Multiple
>>   sequential suppression blocks are allowed.
>> - kunit_start/end_suppress_warning(test): direct functions that return
>>   an explicit handle. Use when the handle needs to be retained, or passed
>>   across helpers. Multiple sequential suppression blocks are allowed.
>>
>> This series is based on the RFC patch and subsequent discussion at
>> https://patchwork.kernel.org/project/linux-kselftest/patch/02546e59-1afe-4b08-ba81-d94f3b691c9a at moroto.mountain/
>> and offers a more comprehensive solution of the problem discussed there.
>>
>> Changes since RFC:
>> - Introduced CONFIG_KUNIT_SUPPRESS_BACKTRACE
>> - Minor cleanups and bug fixes
>> - Added support for all affected architectures
>> - Added support for counting suppressed warnings
>> - Added unit tests using those counters
>> - Added patch to suppress warning backtraces in dev_addr_lists tests
>>
>> Changes since v1:
>> - Rebased to v6.9-rc1
>> - Added Tested-by:, Acked-by:, and Reviewed-by: tags
>>   [I retained those tags since there have been no functional changes]
>> - Introduced KUNIT_SUPPRESS_BACKTRACE configuration option, enabled by
>>   default.
>>
>> Changes since v2:
>> - Rebased to v6.9-rc2
>> - Added comments to drm warning suppression explaining why it is needed.
>> - Added patch to move conditional code in arch/sh/include/asm/bug.h
>>   to avoid kerneldoc warning
>> - Added architecture maintainers to Cc: for architecture specific patches
>> - No functional changes
>>
>> Changes since v3:
>> - Rebased to v6.14-rc6
>> - Dropped net: "kunit: Suppress lock warning noise at end of dev_addr_lists tests"
>>   since 3db3b62955cd6d73afde05a17d7e8e106695c3b9
>> - Added __kunit_ and KUNIT_ prefixes.
>> - Tested on interessed architectures.
>>
>> Changes since v4:
>> - Rebased to v6.15-rc7
>> - Dropped all code in __report_bug()
>> - Moved all checks in WARN*() macros.
>> - Dropped all architecture specific code.
>> - Made __kunit_is_suppressed_warning nice to noinstr functions.
>>
>> Changes since v5:
>> - Rebased to v7.0-rc3
>> - Added RCU protection for the suppressed warnings list.
>> - Added static key and branching optimization.
>> - Removed custom `strcmp` implementation and reworked
>>   __kunit_is_suppressed_warning() entrypoint function.
>>
>> Changes since v6:
>> - Moved suppression checks from WARN*() macros to warn_slowpath_fmt()
>>   and __report_bug().
>> - Replaced stack-allocated suppression struct with kunit_kzalloc() heap
>>   allocation tied to the KUnit test lifecycle.
>> - Changed suppression strategy from function-name matching to task-scoped:
>>   all warnings on the current task are suppressed between START and END,
>>   rather than only warnings originating from a specific named function.
>> - Simplified macro API: removed KUNIT_DECLARE_SUPPRESSED_WARNING(),
>>   the START macro now takes (test) and handles allocation internally.
>> - Removed static key and branching optiomization, as by the time it
>>   was executed, callers are already in warn slowpaths.
>> - Link to v6: https://lore.kernel.org/r/20260317-kunit_add_support-v6-0-dd22aeb3fe5d at redhat.com
>>
>> Changes since v7:
>> - Integrated suppression into existing KUnit hooks infrastructure
>> - Removed CONFIG_KUNIT_SUPPRESS_BACKTRACE
>> - Added suppression check in __warn_printk()
>> - Added spinlock for writer-side RCU protection
>> - Replaced explicit rcu_read_lock/unlock with guard(rcu)()
>> - Added scoped API (kunit_warning_suppress) using __cleanup attribute
>> - Updated DRM patch to use scoped API
>> - Expanded self-tests: incremental counting, cross-kthread isolation
>> - Rewrote documentation covering all three API forms with examples
>> - Link to v7: https://lore.kernel.org/r/20260420-kunit_add_support-v7-0-e8bc6e0f70de at redhat.com
>>
>> Changes since v8:
>> - Rebased to v7.1-rc2
>> - Remove KUNIT_START/END_SUPPRESSED_WARNING() macros
>> - Add KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT checks to drm tests
>> - Link to v8: https://lore.kernel.org/r/20260504-kunit_add_support-v8-0-3e5957cdd235 at redhat.com
>>
>> Changes since v9:
>> - Fix silent false-pass when kunit_start_suppress_warning() returns NULL
>> - Fix RCU lockdep splat for kunit_is_suppressed_warning() calls
>> - Move disable_trace_on_warning() in __report_bug()
>> - Make suppress counter atomic
>> - Mark helper warn functions in selftest as noinline
>> - Add kunit_skip() for CONFIG_BUG=n in selftests
>> - Fix potentially uninitialized data.was_active in kthread seltest
>> - Add kthread_stop() in kthread selftest early exit
>> - Initialize scaling_factor to INT_MIN in DRM scaling tests
>> - Add include for bool in test-bug.h to fix CONFIG_KUNIT=n case
>> - Link to v9: https://lore.kernel.org/r/20260508-kunit_add_support-v9-0-99df7aa880f6 at redhat.com
>>
>> Changes since v10:
>> - Remove synchronize_rcu() to avoid sleeping in atomic context
>> - Pin task_struct refcount to prevent ABA false-positive matches
>> - Loop in suppression selftest to prevent use-after-free on kthread exit
>> - Skip DRM rect tests on CONFIG_BUG=n
>> - Link to v10: https://lore.kernel.org/r/20260513-kunit_add_support-v10-0-e379d206c8cd at redhat.com
>>
>> Changes since v11:
>> - Use call_rcu() to defer free without blocking
>> - Remove #ifdef CONFIG_KUNIT guard in lib/bug.c
>> - Remove stale config checks from selftest
>> - Replace skip on DRM rect tests with conditional expectation
>> - Link to v11: https://lore.kernel.org/r/20260514-kunit_add_support-v11-0-b36a530a6d8f at redhat.com
>>
>> Changes since v12:
>> - Reverted to the v9 synchronize_rcu() approach
>> - Add in_task() check at the top of __kunit_is_suppressed_warning_impl()
>> - Link to v12: https://lore.kernel.org/r/20260515-kunit_add_support-v12-0-a216dc228be8 at redhat.com
> 
> Hi all,
> 
> I am not sure if there is a decision to merge this series or if any
> work remains to be done.
> 
> I reckon I sent a few versions back-to-back last time as I was
> struggling with Sashiko. However, there are no significant changes,
> the core strategy remains unchanged, involving only the addition of
> safety checks and the removal of some redundancies to satisfy the AI.
> I am just clarifying in case the last versions/respins were unclear. I
> tried running AI reviews locally but Sashiko always found more issues
> than my local model could.
> 
The latest version was fine. It's just landed for 7.2:
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=42eb3a5ef6bc56192bf450c79a3f274e081f8131

Thanks for all of your work,
-- David


From lihuisong at huawei.com  Tue Jun 16 06:12:46 2026
From: lihuisong at huawei.com (lihuisong (C))
Date: Tue, 16 Jun 2026 21:12:46 +0800
Subject: [PATCH][v2] ACPI: processor_idle: Mark LPI enter functions as
 __cpuidle
In-Reply-To: <20260616072617.2272-1-lirongqing@baidu.com>
References: <20260616072617.2272-1-lirongqing@baidu.com>
Message-ID: <a2483bf9-0a78-43df-ae03-b017bc72c380@huawei.com>


On 6/16/2026 3:26 PM, lirongqing wrote:
> From: Li RongQing <lirongqing at baidu.com>
>
> When function tracing or Kprobes is enabled, entering an ACPI Low
> Power Idle (LPI) state triggers the following RCU splat:
>
>    RCU not on for: acpi_idle_lpi_enter+0x4/0xd8
>    WARNING: CPU: 8 PID: 0 at include/linux/trace_recursion.h:162 function_trace_call+0x1e8/0x228
>
> The acpi_idle_lpi_enter() function is invoked within the cpuidle
> path after RCU has already been disabled for the current local CPU.
> Consequently, ftrace's function_trace_call() expects RCU to be
> actively watching before recording trace data, emitting a warning
> if it is not.
>
> Fix this by annotating acpi_idle_lpi_enter(), the generic __weak
> stub, and the RISC-V implementation of acpi_processor_ffh_lpi_enter()
> with __cpuidle. This moves these functions into the '.cpuidle.text'
> section, implicitly disabling ftrace instrumentation (notrace) along
> this sensitive path and preventing trace-induced RCU warnings during
> idle entry.
>
> Fixes: a36a7fecfe60 ("ACPI / processor_idle: Add support for Low Power Idle(LPI) states")
> Signed-off-by: Li RongQing <lirongqing at baidu.com>
> ---
LGTM,
Acked-by: lihuisong at huawei.com


From wangruikang at iscas.ac.cn  Tue Jun 16 06:51:31 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Tue, 16 Jun 2026 21:51:31 +0800
Subject: [PATCH 1/2] ACPI: tables: Add missing #include <asm/fixmap.h>
In-Reply-To: <20260616-riscv-acpi-table-upgrade-v1-0-45902d2dedf9@iscas.ac.cn>
References: <20260616-riscv-acpi-table-upgrade-v1-0-45902d2dedf9@iscas.ac.cn>
Message-ID: <20260616-riscv-acpi-table-upgrade-v1-1-45902d2dedf9@iscas.ac.cn>

drivers/acpi/tables.c uses NR_FIX_BTMAPS without including
<asm/fixmap.h>. This isn't a problem for existing archs, but would be
when ARCH_HAS_ACPI_TABLE_UPGRADE is enabled for RISC-V. Add the missing
include.

Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
---
 drivers/acpi/tables.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 4286e4af1092..eb93c060426f 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -22,6 +22,7 @@
 #include <linux/initrd.h>
 #include <linux/security.h>
 #include <linux/kmemleak.h>
+#include <asm/fixmap.h>
 #include "internal.h"
 
 #ifdef CONFIG_ACPI_CUSTOM_DSDT

-- 
2.54.0



From wangruikang at iscas.ac.cn  Tue Jun 16 06:51:30 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Tue, 16 Jun 2026 21:51:30 +0800
Subject: [PATCH 0/2] riscv: acpi: Enable ARCH_HAS_ACPI_TABLE_UPGRADE
Message-ID: <20260616-riscv-acpi-table-upgrade-v1-0-45902d2dedf9@iscas.ac.cn>

I did end up using this for something, so this is probably also useful
for others.

---
Vivian Wang (2):
      ACPI: tables: Add missing #include <asm/fixmap.h>
      riscv: acpi: Enable ARCH_HAS_ACPI_TABLE_UPGRADE

 arch/riscv/Kconfig            | 1 +
 arch/riscv/include/asm/acpi.h | 2 ++
 arch/riscv/kernel/acpi.c      | 5 +++++
 arch/riscv/kernel/setup.c     | 2 ++
 drivers/acpi/tables.c         | 1 +
 5 files changed, 11 insertions(+)
---
base-commit: 254f49634ee16a731174d2ae34bc50bd5f45e731
change-id: 20260616-riscv-acpi-table-upgrade-fb5e69c5bf66

Best regards,
--  
Vivian "dramforever" Wang



From wangruikang at iscas.ac.cn  Tue Jun 16 06:51:32 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Tue, 16 Jun 2026 21:51:32 +0800
Subject: [PATCH 2/2] riscv: acpi: Enable ARCH_HAS_ACPI_TABLE_UPGRADE
In-Reply-To: <20260616-riscv-acpi-table-upgrade-v1-0-45902d2dedf9@iscas.ac.cn>
References: <20260616-riscv-acpi-table-upgrade-v1-0-45902d2dedf9@iscas.ac.cn>
Message-ID: <20260616-riscv-acpi-table-upgrade-v1-2-45902d2dedf9@iscas.ac.cn>

Implement the various required hooks and enable
ARCH_HAS_ACPI_TABLE_UPGRADE to allow use for ACPI_TABLE_UPGRADE, which
is useful for debugging ACPI table problems.

The implementation is based on arm64's of the same feature due to the
similarities of the requirements of the two platforms.

Signed-off-by: Vivian Wang <wangruikang at iscas.ac.cn>
---
 arch/riscv/Kconfig            | 1 +
 arch/riscv/include/asm/acpi.h | 2 ++
 arch/riscv/kernel/acpi.c      | 5 +++++
 arch/riscv/kernel/setup.c     | 2 ++
 4 files changed, 10 insertions(+)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index d235396c4514..2986d45bdc72 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -23,6 +23,7 @@ config RISCV
 	select ARCH_ENABLE_MEMORY_HOTPLUG if SPARSEMEM_VMEMMAP
 	select ARCH_ENABLE_SPLIT_PMD_PTLOCK if PGTABLE_LEVELS > 2
 	select ARCH_ENABLE_THP_MIGRATION if TRANSPARENT_HUGEPAGE
+	select ARCH_HAS_ACPI_TABLE_UPGRADE if ACPI
 	select ARCH_HAS_BINFMT_FLAT
 	select ARCH_HAS_CURRENT_STACK_POINTER
 	select ARCH_HAS_DEBUG_VIRTUAL if MMU
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index 26ab37c171bc..d59bd06347cc 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -92,4 +92,6 @@ void acpi_map_cpus_to_nodes(void);
 static inline void acpi_map_cpus_to_nodes(void) { }
 #endif /* CONFIG_ACPI_NUMA */
 
+#define ACPI_TABLE_UPGRADE_MAX_PHYS MEMBLOCK_ALLOC_ACCESSIBLE
+
 #endif /*_ASM_ACPI_H*/
diff --git a/arch/riscv/kernel/acpi.c b/arch/riscv/kernel/acpi.c
index 068e0b404b6f..efd52a5d05b5 100644
--- a/arch/riscv/kernel/acpi.c
+++ b/arch/riscv/kernel/acpi.c
@@ -353,3 +353,8 @@ int acpi_get_cpu_uid(unsigned int cpu, u32 *uid)
 	return 0;
 }
 EXPORT_SYMBOL_GPL(acpi_get_cpu_uid);
+
+void __init arch_reserve_mem_area(acpi_physical_address addr, size_t size)
+{
+	memblock_mark_nomap(addr, size);
+}
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index c89cc272440b..96b6a166ede1 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -324,6 +324,8 @@ void __init setup_arch(char **cmdline_p)
 	efi_init();
 	paging_init();
 
+	acpi_table_upgrade();
+
 	/* Parse the ACPI tables for possible boot-time configuration */
 	acpi_boot_table_init();
 

-- 
2.54.0



From pengpeng at iscas.ac.cn  Tue Jun 16 08:13:14 2026
From: pengpeng at iscas.ac.cn (Pengpeng Hou)
Date: Tue, 16 Jun 2026 23:13:14 +0800
Subject: [PATCH] cache: sifive_ccache: remove debugfs on driver register failure
Message-ID: <20260616151314.87102-1-pengpeng@iscas.ac.cn>

sifive_ccache_init() creates the debugfs injection file before
registering the platform driver. If platform_driver_register() fails, the
error path unmaps ccache_base while the debugfs file remains and its
write callback still uses that global mapping.

Remove the debugfs tree before unmapping the cache controller registers
on the registration failure path.

Signed-off-by: Pengpeng Hou <pengpeng at iscas.ac.cn>
---
 drivers/cache/sifive_ccache.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/cache/sifive_ccache.c b/drivers/cache/sifive_ccache.c
index a86800b123b9..cf7877d8e3e5 100644
--- a/drivers/cache/sifive_ccache.c
+++ b/drivers/cache/sifive_ccache.c
@@ -100,6 +100,12 @@ static void setup_sifive_debug(void)
 	debugfs_create_file("sifive_debug_inject_error", 0200,
 			    sifive_test, NULL, &ccache_fops);
 }
+
+static void remove_sifive_debug(void)
+{
+	debugfs_remove_recursive(sifive_test);
+	sifive_test = NULL;
+}
 #endif
 
 static void ccache_config_read(void)
@@ -336,12 +342,16 @@ static int __init sifive_ccache_init(void)
 
 	rc = platform_driver_register(&sifive_ccache_driver);
 	if (rc)
-		goto err_unmap;
+		goto err_remove_debug;
 
 	of_node_put(np);
 
 	return 0;
 
+err_remove_debug:
+#ifdef CONFIG_DEBUG_FS
+	remove_sifive_debug();
+#endif
 err_unmap:
 	iounmap(ccache_base);
 err_node_put:
-- 
2.43.0



From conor at kernel.org  Tue Jun 16 08:29:22 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 16 Jun 2026 16:29:22 +0100
Subject: [PATCH] cache: sifive_ccache: remove debugfs on driver register
 failure
In-Reply-To: <20260616151314.87102-1-pengpeng@iscas.ac.cn>
References: <20260616151314.87102-1-pengpeng@iscas.ac.cn>
Message-ID: <20260616-fossil-labored-ea8b8b08c856@spud>

On Tue, Jun 16, 2026 at 11:13:14PM +0800, Pengpeng Hou wrote:
> sifive_ccache_init() creates the debugfs injection file before
> registering the platform driver. If platform_driver_register() fails, the
> error path unmaps ccache_base while the debugfs file remains and its
> write callback still uses that global mapping.
> 
> Remove the debugfs tree before unmapping the cache controller registers
> on the registration failure path.
> 
> Signed-off-by: Pengpeng Hou <pengpeng at iscas.ac.cn>
> ---
>  drivers/cache/sifive_ccache.c | 12 +++++++++++-
>  1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/cache/sifive_ccache.c b/drivers/cache/sifive_ccache.c
> index a86800b123b9..cf7877d8e3e5 100644
> --- a/drivers/cache/sifive_ccache.c
> +++ b/drivers/cache/sifive_ccache.c
> @@ -100,6 +100,12 @@ static void setup_sifive_debug(void)
>  	debugfs_create_file("sifive_debug_inject_error", 0200,
>  			    sifive_test, NULL, &ccache_fops);
>  }
> +
> +static void remove_sifive_debug(void)
> +{
> +	debugfs_remove_recursive(sifive_test);
> +	sifive_test = NULL;

Firstly, do we really need a function for this?
Secondly, is there any reason to actually explicitly NULL this after
we're done removing? The driver has failed to probe so it's not as if
something is going to refer to this dentry pointer anyway?

Am I missing something?


Cheers,
Conor.

> +}
>  #endif
>  
>  static void ccache_config_read(void)
> @@ -336,12 +342,16 @@ static int __init sifive_ccache_init(void)
>  
>  	rc = platform_driver_register(&sifive_ccache_driver);
>  	if (rc)
> -		goto err_unmap;
> +		goto err_remove_debug;
>  
>  	of_node_put(np);
>  
>  	return 0;
>  
> +err_remove_debug:
> +#ifdef CONFIG_DEBUG_FS
> +	remove_sifive_debug();
> +#endif
>  err_unmap:
>  	iounmap(ccache_base);
>  err_node_put:
> -- 
> 2.43.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260616/df6a091c/attachment.sig>

From conor at kernel.org  Tue Jun 16 08:31:04 2026
From: conor at kernel.org (Conor Dooley)
Date: Tue, 16 Jun 2026 16:31:04 +0100
Subject: [PATCH 6/7] riscv: dts: eswin: add I2C controller support
In-Reply-To: <SJ2PR04MB8896A5877CCFC177FA5D5A9583E52@SJ2PR04MB8896.namprd04.prod.outlook.com>
References: <20260615122016.1110206-1-pinkesh.vaghela@einfochips.com>
 <20260615122016.1110206-7-pinkesh.vaghela@einfochips.com>
 <20260615-lumpiness-profusely-155422288c31@spud>
 <SJ2PR04MB8896A5877CCFC177FA5D5A9583E52@SJ2PR04MB8896.namprd04.prod.outlook.com>
Message-ID: <20260616-greeter-securely-16e742490a4a@spud>

On Tue, Jun 16, 2026 at 11:57:33AM +0000, Pinkesh Vaghela wrote:
> On Mon, Jun 15, 2026 at 10:05 PM +0530, Conor Dooley wrote:
> > On Mon, Jun 15, 2026 at 05:50:15PM +0530, Pinkesh Vaghela wrote:
> > > +		i2c0: i2c at 50950000 {
> > > +			compatible = "snps,designware-i2c";
> > 
> > Missing a soc-specific compatible here for all i2c controllers.
> 
> We are using generic DesignWare I2C driver for all I2C controllers with
> no changes required in the driver. Do we still need to add soc-specific
> compatible for all i2c controllers?

Yes. Just use "snps,designware-i2c" as a fallback.

Thanks,
Conor.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260616/e3c3cafd/attachment.sig>

From guoren at kernel.org  Tue Jun 16 08:47:05 2026
From: guoren at kernel.org (Guo Ren)
Date: Tue, 16 Jun 2026 23:47:05 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260616113651.1048a19a@pumpkin>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org> <20260616113651.1048a19a@pumpkin>
Message-ID: <CAJF2gTTh1zyAZkKt7AQNZptG_H=-8xSum6PVTyxEmw23pN6-9g@mail.gmail.com>

On Tue, Jun 16, 2026 at 6:36?PM David Laight
<david.laight.linux at gmail.com> wrote:
>
> On Mon, 15 Jun 2026 12:38:17 +0000
> Guo Ren <guoren at kernel.org> wrote:
>
> > Hi Zhanpeng Zhang,
> ..
> > 3. Only performance-monitoring counters require 64-bit IO access or the
> > high-low-high do-while retry strategy. For ordinary status and control
> > MMIO registers, a single read is sufficient.
>
> Actually this sequence should be enough for a counter:
>         hi = read_hi();
>         lo = read_lo();
>         if (hi != read_hi()) {
>                 // Pick a value that happened while doing the reads.
>                 hi++;
>                 lo = 0;
>         }
This is not a free optimization ? it does not preserve the same
semantics as an atomic 64-bit read. There are at least two correctness
issues:

1. Loss of precision: If hi changed during the read, setting lo = 0
discards the actual lo value. The correct approach is to re-read lo
after detecting the change, not fabricate a value.

2. Multiple overflows: This assumes at most one overflow occurs
between reads. If two overflows happen (e.g., due to interrupt
injection), hi++ will produce an incorrect result, silently corrupting
the counter value.

Negligible benefit: hi changing between reads is an extremely rare
event. Optimizing away the retry loop for such a rare case provides no
meaningful performance gain. And if hi never stabilizes, that
indicates a hardware failure ? in which case hanging in the retry loop
is actually the more appropriate behavior, as it makes the failure
visible rather than silently producing garbage values.

The high-low-high do-while retry strategy exists precisely to handle
these cases correctly. I don't think this proposed sequence is a valid
replacement.

-- 
Best Regards
 Guo Ren


From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Tue Jun 16 09:03:36 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Tue, 16 Jun 2026 18:03:36 +0200
Subject: [PATCH v9 0/3] riscv: Use GCR.U timer device as clocksource
Message-ID: <20260616-riscv-time-mmio-v9-0-03af7bc8f2d8@htecgroup.com>

This series adds bindings for the GCR.U timer device and corresponding
driver support. Accessing the memory mapped shadow of the mtime register
in the GCR.U region should be faster
than trapping to M mode each time the timer needs to be read.
The timer device does not implement any interrupts, therefore the
timer-riscv clockevent implementation should suffice.

We tested the patchset both on QEMU and the Boston board with the P8700 bitfile:
- v7, v8 testing:
  - Coremark and timer kselftests on QEMU emulating an 8 core CPU
  - Coremark and timer kselftests on the Boston board with a single core CPU.

Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
Signed-off-by: Djordje Todorovic <djordje.todorovic at htecgroup.com>
Signed-off-by: Chao-ying Fu <cfu at mips.com>
---
Changes in v9:
- Fix timer base address in dt-bindings
- Link to v8: https://lore.kernel.org/r/20260610-riscv-time-mmio-v8-0-a865206675c6 at htecgroup.com

Changes in v8:
- Make the 64 bit timer mmio reads and the main timer driver depend on CONFIG_64BIT
- Add timer_of_cleanup to the driver code
- Link to v7: https://lore.kernel.org/r/20260311-riscv-time-mmio-v7-0-016845a0f808 at htecgroup.com

Changes in v7:
- Replace the previous implementation with a new timer driver for mips,p8700-gcru
- Add a patch for 64bit reads for timer mmio
- Link to v6: https://lore.kernel.org/r/20250806-riscv-time-mmio-v6-0-2df0e8219998 at htecgroup.com

Changes in v6:
- Rename mti,gcru to mips,p8700-gcru
- Link to v5: https://lore.kernel.org/r/20250711-riscv-time-mmio-v5-0-9ed1f825ad5e at htecgroup.com

Changes in v5:
- Fixed build issues on 32-bit RISC-V and sparse warnings
- Remove clint_time_val and clint.h, replace with riscv_time_val
- Depend on RISCV_TIMER in Kconfig

Changes in v4:
- Remove "select" from mti,gcru.yaml.
- Refactor the driver to use function pointers instead of static keys.

Previous versions:
v1: https://lore.kernel.org/lkml/20241227150056.191794-1-arikalo at gmail.com/#t
v2: https://lore.kernel.org/linux-riscv/20250409143816.15802-1-aleksa.paunovic at htecgroup.com/
v3: https://lore.kernel.org/linux-riscv/DU0PR09MB61968695A2A3146EE83B7708F6BA2 at DU0PR09MB6196.eurprd09.prod.outlook.com/
v4: https://lore.kernel.org/r/20250514-riscv-time-mmio-v4-0-cb0cf2922d66 at htecgroup.com
v5: https://lore.kernel.org/r/20250711-riscv-time-mmio-v5-0-9ed1f825ad5e at htecgroup.com
v6: https://lore.kernel.org/r/20250806-riscv-time-mmio-v6-0-2df0e8219998 at htecgroup.com
v7: https://lore.kernel.org/r/20260311-riscv-time-mmio-v7-0-016845a0f808 at htecgroup.com
v8: https://lore.kernel.org/r/20260610-riscv-time-mmio-v8-0-a865206675c6 at htecgroup.com

---
Aleksa Paunovic (3):
      dt-bindings: timer: mips,p8700-gcru
      riscv: clocksource: Add readq options to clocksource mmio
      riscv: clocksource: Add p8700-gcru driver

 .../devicetree/bindings/timer/mips,p8700-gcru.yaml | 38 +++++++++++++++++
 drivers/clocksource/Kconfig                        |  9 +++++
 drivers/clocksource/Makefile                       |  1 +
 drivers/clocksource/mmio.c                         | 14 +++++++
 drivers/clocksource/timer-p8700.c                  | 47 ++++++++++++++++++++++
 include/linux/clocksource.h                        |  4 ++
 6 files changed, 113 insertions(+)
---
base-commit: ac3fd01e4c1efce8f2c054cdeb2ddd2fc0fb150d
change-id: 20250424-riscv-time-mmio-5628e0fca8af

Best regards,
-- 
Aleksa Paunovic <aleksa.paunovic at htecgroup.com>




From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Tue Jun 16 09:03:37 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Tue, 16 Jun 2026 18:03:37 +0200
Subject: [PATCH v9 1/3] dt-bindings: timer: mips,p8700-gcru
In-Reply-To: <20260616-riscv-time-mmio-v9-0-03af7bc8f2d8@htecgroup.com>
References: <20260616-riscv-time-mmio-v9-0-03af7bc8f2d8@htecgroup.com>
Message-ID: <20260616-riscv-time-mmio-v9-1-03af7bc8f2d8@htecgroup.com>

From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>

Add dt-bindings for the GCR.U memory mapped timer device for RISC-V
platforms. The GCR.U memory region contains shadow copies of the RISC-V
mtime register and the hrtime Global Configuration Register.

Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
Acked-by: Conor Dooley <conor.dooley at microchip.com>
---
 .../devicetree/bindings/timer/mips,p8700-gcru.yaml | 38 ++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git a/Documentation/devicetree/bindings/timer/mips,p8700-gcru.yaml b/Documentation/devicetree/bindings/timer/mips,p8700-gcru.yaml
new file mode 100644
index 0000000000000000000000000000000000000000..e6f25e769f461d58c87194fba3540eee13cb322b
--- /dev/null
+++ b/Documentation/devicetree/bindings/timer/mips,p8700-gcru.yaml
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/timer/mips,p8700-gcru.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GCR.U timer device for the MIPS P8700 platform
+
+maintainers:
+  - Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
+
+description:
+  The GCR.U memory region contains memory mapped shadow copies of
+  mtime and hrtime Global Configuration Registers,
+  which software can choose to make accessible from user mode.
+
+properties:
+  compatible:
+    const: mips,p8700-gcru
+
+  reg:
+    items:
+      - description: Read-only shadow copy of the RISC-V mtime register.
+      - description: Read-only shadow copy of the P8700 high resolution timer register.
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    timer at 1617f050 {
+        compatible = "mips,p8700-gcru";
+        reg = <0x1617f050 0x8>,
+              <0x1617f090 0x8>;
+    };

-- 
2.43.0




From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Tue Jun 16 09:03:38 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Tue, 16 Jun 2026 18:03:38 +0200
Subject: [PATCH v9 2/3] riscv: clocksource: Add readq options to
 clocksource mmio
In-Reply-To: <20260616-riscv-time-mmio-v9-0-03af7bc8f2d8@htecgroup.com>
References: <20260616-riscv-time-mmio-v9-0-03af7bc8f2d8@htecgroup.com>
Message-ID: <20260616-riscv-time-mmio-v9-2-03af7bc8f2d8@htecgroup.com>

From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>

Add read functions for 64-bit register size to the generic
mmio clocksource, covering both up and down counters.

Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
---
 drivers/clocksource/mmio.c  | 14 ++++++++++++++
 include/linux/clocksource.h |  4 ++++
 2 files changed, 18 insertions(+)

diff --git a/drivers/clocksource/mmio.c b/drivers/clocksource/mmio.c
index 9de75153183124cc8997c6ab61d0c01d9b2637bc..f3b6f7e93ffbf0ed68e56c58c3d9f711d2193caa 100644
--- a/drivers/clocksource/mmio.c
+++ b/drivers/clocksource/mmio.c
@@ -17,6 +17,20 @@ static inline struct clocksource_mmio *to_mmio_clksrc(struct clocksource *c)
 	return container_of(c, struct clocksource_mmio, clksrc);
 }
 
+#if defined(CONFIG_64BIT) && defined(readq_relaxed)
+
+u64 clocksource_mmio_readq_up(struct clocksource *c)
+{
+	return (u64)readq_relaxed(to_mmio_clksrc(c)->reg);
+}
+
+u64 clocksource_mmio_readq_down(struct clocksource *c)
+{
+	return ~(u64)readq_relaxed(to_mmio_clksrc(c)->reg) & c->mask;
+}
+
+#endif
+
 u64 clocksource_mmio_readl_up(struct clocksource *c)
 {
 	return (u64)readl_relaxed(to_mmio_clksrc(c)->reg);
diff --git a/include/linux/clocksource.h b/include/linux/clocksource.h
index 65b7c41471c390463770c2da13694e58e83b84ea..39e0df5a0ab52cbb7016b53a4d7500f2697e2797 100644
--- a/include/linux/clocksource.h
+++ b/include/linux/clocksource.h
@@ -276,6 +276,10 @@ static inline void clocksource_arch_init(struct clocksource *cs) { }
 
 extern int timekeeping_notify(struct clocksource *clock);
 
+#if defined(CONFIG_64BIT) && defined(readq_relaxed)
+extern u64 clocksource_mmio_readq_up(struct clocksource *c);
+extern u64 clocksource_mmio_readq_down(struct clocksource *c);
+#endif
 extern u64 clocksource_mmio_readl_up(struct clocksource *);
 extern u64 clocksource_mmio_readl_down(struct clocksource *);
 extern u64 clocksource_mmio_readw_up(struct clocksource *);

-- 
2.43.0




From devnull+aleksa.paunovic.htecgroup.com at kernel.org  Tue Jun 16 09:03:39 2026
From: devnull+aleksa.paunovic.htecgroup.com at kernel.org (Aleksa Paunovic via B4 Relay)
Date: Tue, 16 Jun 2026 18:03:39 +0200
Subject: [PATCH v9 3/3] riscv: clocksource: Add p8700-gcru driver
In-Reply-To: <20260616-riscv-time-mmio-v9-0-03af7bc8f2d8@htecgroup.com>
References: <20260616-riscv-time-mmio-v9-0-03af7bc8f2d8@htecgroup.com>
Message-ID: <20260616-riscv-time-mmio-v9-3-03af7bc8f2d8@htecgroup.com>

From: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>

Add a clocksource driver for the P8700 GCRU.

Initialization uses helper functions
provided by clocksource/mmio.c and timer-of.c.

Since the GCRU does not support any kind of interrupts,
the default RISC-V clockevent implementation should suffice.

Signed-off-by: Aleksa Paunovic <aleksa.paunovic at htecgroup.com>
---
 drivers/clocksource/Kconfig       |  9 ++++++++
 drivers/clocksource/Makefile      |  1 +
 drivers/clocksource/timer-p8700.c | 47 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+)

diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index ffcd23668763fe7707a4e917bf240caadbb09a8c..a775a301f3f08ca97699e46aaf3ccfaf99734e6b 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -672,6 +672,15 @@ config CLINT_TIMER
 	  This option enables the CLINT timer for RISC-V systems.  The CLINT
 	  driver is usually used for NoMMU RISC-V systems.
 
+config P8700_TIMER
+	bool "MIPS P8700 timer driver"
+	depends on GENERIC_SCHED_CLOCK && RISCV && RISCV_SBI && 64BIT
+	select CLKSRC_MMIO
+	select TIMER_PROBE
+	select TIMER_OF
+	help
+	  Enables support for MIPS P8700 timer driver.
+
 config CSKY_MP_TIMER
 	bool "SMP Timer for the C-SKY platform" if COMPILE_TEST
 	depends on CSKY
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index ec4452ee958f1a814c708aeba6412bea61d24892..fae9a58d6c8663a7c857b9ab7fdae05782b3551c 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -95,3 +95,4 @@ obj-$(CONFIG_CLKSRC_LOONGSON1_PWM)	+= timer-loongson1-pwm.o
 obj-$(CONFIG_EP93XX_TIMER)		+= timer-ep93xx.o
 obj-$(CONFIG_RALINK_TIMER)		+= timer-ralink.o
 obj-$(CONFIG_NXP_STM_TIMER)		+= timer-nxp-stm.o
+obj-$(CONFIG_P8700_TIMER)		+= timer-p8700.o
diff --git a/drivers/clocksource/timer-p8700.c b/drivers/clocksource/timer-p8700.c
new file mode 100644
index 0000000000000000000000000000000000000000..dd20b4e72fcdd77a6b33775f286d0945c2a2b659
--- /dev/null
+++ b/drivers/clocksource/timer-p8700.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2025 MIPS.
+ */
+
+#include <linux/sched_clock.h>
+#include <linux/delay.h>
+#include <linux/of_address.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/clocksource.h>
+
+#include "timer-of.h"
+
+static struct timer_of gcru_of = { .flags = TIMER_OF_BASE };
+static u64 __iomem *p8700_time_val __ro_after_init;
+
+static u64 notrace p8700_timer_sched_read(void)
+{
+	return (u64)readq_relaxed(p8700_time_val);
+}
+
+static int __init p8700_timer_init(struct device_node *node)
+{
+	int error = 0;
+
+	error = timer_of_init(node, &gcru_of);
+	if (error)
+		return error;
+
+	p8700_time_val = timer_of_base(&gcru_of);
+	/* Now init the mmio timer with the address we got from DT */
+	error = clocksource_mmio_init(p8700_time_val, "mips,p8700-gcru",
+				      riscv_timebase, 450, 64,
+				      clocksource_mmio_readq_up);
+	if (error) {
+		timer_of_cleanup(&gcru_of);
+		return error;
+	}
+
+	/* Sched clock */
+	sched_clock_register(p8700_timer_sched_read, 64, riscv_timebase);
+
+	return error;
+}
+
+TIMER_OF_DECLARE(p8700_timer, "mips,p8700-gcru", p8700_timer_init);

-- 
2.43.0




From david.laight.linux at gmail.com  Tue Jun 16 12:51:47 2026
From: david.laight.linux at gmail.com (David Laight)
Date: Tue, 16 Jun 2026 20:51:47 +0100
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <CAJF2gTTh1zyAZkKt7AQNZptG_H=-8xSum6PVTyxEmw23pN6-9g@mail.gmail.com>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
	<20260615123821.373248-1-guoren@kernel.org>
	<20260616113651.1048a19a@pumpkin>
	<CAJF2gTTh1zyAZkKt7AQNZptG_H=-8xSum6PVTyxEmw23pN6-9g@mail.gmail.com>
Message-ID: <20260616205147.6aa7df98@pumpkin>

On Tue, 16 Jun 2026 23:47:05 +0800
Guo Ren <guoren at kernel.org> wrote:

> On Tue, Jun 16, 2026 at 6:36?PM David Laight
> <david.laight.linux at gmail.com> wrote:
> >
> > On Mon, 15 Jun 2026 12:38:17 +0000
> > Guo Ren <guoren at kernel.org> wrote:
> >  
> > > Hi Zhanpeng Zhang,  
> > ..  
> > > 3. Only performance-monitoring counters require 64-bit IO access or the
> > > high-low-high do-while retry strategy. For ordinary status and control
> > > MMIO registers, a single read is sufficient.  
> >
> > Actually this sequence should be enough for a counter:
> >         hi = read_hi();
> >         lo = read_lo();
> >         if (hi != read_hi()) {
> >                 // Pick a value that happened while doing the reads.
> >                 hi++;
> >                 lo = 0;
> >         }  
> This is not a free optimization ? it does not preserve the same
> semantics as an atomic 64-bit read. There are at least two correctness
> issues:
> 
> 1. Loss of precision: If hi changed during the read, setting lo = 0
> discards the actual lo value. The correct approach is to re-read lo
> after detecting the change, not fabricate a value.
> 
> 2. Multiple overflows: This assumes at most one overflow occurs
> between reads. If two overflows happen (e.g., due to interrupt
> injection), hi++ will produce an incorrect result, silently corrupting
> the counter value.
> 
> Negligible benefit: hi changing between reads is an extremely rare
> event. Optimizing away the retry loop for such a rare case provides no
> meaningful performance gain. And if hi never stabilizes, that
> indicates a hardware failure ? in which case hanging in the retry loop
> is actually the more appropriate behavior, as it makes the failure
> visible rather than silently producing garbage values.
> 
> The high-low-high do-while retry strategy exists precisely to handle
> these cases correctly. I don't think this proposed sequence is a valid
> replacement.
> 

The point is that if the value is an incrementing counter (of some form)
then the value is stale by the time the reading sequence completes.
So all the code can be assumed to do is return a value the counter had
sometime between when the code started and when it finished.
If hi changes then hi+1:0 must have happened while the code was running
so it is a safe return value.

It is likely that the reads are also much slower than memory reads.
If hi changes relatively infrequently (compared to the number of reads)
it may be worth saving the previously read value and avoiding the second
read of hi if it is the same as the previous read hi and lo has got larger.

	David



From andi.shyti at kernel.org  Tue Jun 16 16:18:14 2026
From: andi.shyti at kernel.org (Andi Shyti)
Date: Wed, 17 Jun 2026 01:18:14 +0200
Subject: [PATCH v7 0/2] i2c: spacemit: improve clock handling and cleanups
In-Reply-To: <20260508-k1-i2c-ilcr-v7-0-8c2dde5c3ed5@linux.spacemit.com>
References: <20260508-k1-i2c-ilcr-v7-0-8c2dde5c3ed5@linux.spacemit.com>
Message-ID: <ajHZlsTAp3bWRF1V@zenone.zhora.eu>

Hi Troy,

> Troy Mitchell (2):
>       i2c: spacemit: configure ILCR/IWCR for accurate SCL frequency
>       i2c: spacemit: drop warning when clock-frequency property is absent

Sorry for the big delay, merged to i2c/i2c-for-7.2.

Thanks,
Andi


From andi.shyti at kernel.org  Tue Jun 16 16:45:18 2026
From: andi.shyti at kernel.org (Andi Shyti)
Date: Wed, 17 Jun 2026 01:45:18 +0200
Subject: [PATCH v2] dt-bindings: i2c: microchip,corei2c: permit resets
In-Reply-To: <20260506-bronchial-kitten-e3697fb66ba7@spud>
References: <20260506-bronchial-kitten-e3697fb66ba7@spud>
Message-ID: <ajHf_colM2_15FZU@zenone.zhora.eu>

Hi Conor,

On Wed, May 06, 2026 at 04:00:46PM +0100, Conor Dooley wrote:
> From: Conor Dooley <conor.dooley at microchip.com>
> 
> Both CoreI2C and the hardened versions of it on mpfs and pic64gx have a
> reset pin. For the former, usually this is wired to a common fabric
> reset not managed by software and for the latter two the platform
> firmware takes them out of reset on first-party boards (or those using
> modified versions of the vendor firmware), but not all boards may take
> this approach. Permit providing a reset in devicetree for Linux, or
> other devicetree-consuming software, to use.
> 
> Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski at oss.qualcomm.com>
> Signed-off-by: Conor Dooley <conor.dooley at microchip.com>

merged to i2c/i2c-host.

Thanks,
Andi


From namcao at linutronix.de  Tue Jun 16 20:38:24 2026
From: namcao at linutronix.de (Nam Cao)
Date: Wed, 17 Jun 2026 05:38:24 +0200
Subject: [PATCH 1/2] riscv: unaligned: stop using kthread for check_vector_unaligned_access()
In-Reply-To: <cover.1781666867.git.namcao@linutronix.de>
References: <cover.1781666867.git.namcao@linutronix.de>
Message-ID: <1c378963f27c5960e8a57c50b8b444d30954cb54.1781666867.git.namcao@linutronix.de>

A kthread is used to run check_vector_unaligned_access() to optimize boot
time, allowing the kernel to continue booting without waiting for the
unaligned vector speed probe to finish.

However, this asynchronous approach introduces several complications.
First, the kthread may not complete before a user reads vDSO data,
resulting in incorrect values. This was previously addressed by
commit 5d15d2ad36b0 ("riscv: hwprobe: Fix stale vDSO data for
late-initialized keys at boot"), which added complex synchronization
between the kthread and vDSO reads.

Second, it was discovered that the kthread may not finish before
vec_check_unaligned_access_speed_all_cpus() (marked with __init) is freed,
triggering a page fault.

These issues raise the question of whether the kthread is worth the added
complexity. A past boot time regression report was actually unrelated to
synchronous probing; it was caused by the probe running serially. Since
switching to a parallel probe, no further complaints have been made.
Furthermore, the unaligned scalar access speed probe takes the same amount
of time, runs synchronously, and has caused no issues.

Testing shows no noticeable boot time slowdown when running the vector
probe synchronously (0.464474s with kthread vs. 0.457991s without).

Remove the kthread usage and run the probe synchronously. This simplifies
the boot flow and allows for the revert of commit 5d15d2ad36b0 ("riscv:
hwprobe: Fix stale vDSO data for late-initialized keys at boot")

Reported-by: Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>
Closes: https://lore.kernel.org/linux-riscv/20260612-vec_unaligned_drop_init-v1-1-df969210ae34 at oss.tenstorrent.com/
Fixes: a00e022be531 ("riscv: Annotate unaligned access init functions")
Cc: <stable at vger.kernel.org>
Signed-off-by: Nam Cao <namcao at linutronix.de>
---
 arch/riscv/kernel/unaligned_access_speed.c | 19 ++-----------------
 1 file changed, 2 insertions(+), 17 deletions(-)

diff --git a/arch/riscv/kernel/unaligned_access_speed.c b/arch/riscv/kernel/unaligned_access_speed.c
index bb57eb5d19df..6e35bca568de 100644
--- a/arch/riscv/kernel/unaligned_access_speed.c
+++ b/arch/riscv/kernel/unaligned_access_speed.c
@@ -6,7 +6,6 @@
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
 #include <linux/jump_label.h>
-#include <linux/kthread.h>
 #include <linux/mm.h>
 #include <linux/smp.h>
 #include <linux/types.h>
@@ -288,18 +287,9 @@ static void check_vector_unaligned_access(struct work_struct *work __always_unus
 	__free_pages(page, MISALIGNED_BUFFER_ORDER);
 }
 
-/* Measure unaligned access speed on all CPUs present at boot in parallel. */
-static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
-{
-	schedule_on_each_cpu(check_vector_unaligned_access);
-	riscv_hwprobe_complete_async_probe();
-
-	return 0;
-}
 #else /* CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS */
-static int __init vec_check_unaligned_access_speed_all_cpus(void *unused __always_unused)
+static void check_vector_unaligned_access(struct work_struct *work __always_unused)
 {
-	return 0;
 }
 #endif
 
@@ -387,12 +377,7 @@ static int __init check_unaligned_access_all_cpus(void)
 			per_cpu(vector_misaligned_access, cpu) = unaligned_vector_speed_param;
 	} else if (!check_vector_unaligned_access_emulated_all_cpus() &&
 		   IS_ENABLED(CONFIG_RISCV_PROBE_VECTOR_UNALIGNED_ACCESS)) {
-		riscv_hwprobe_register_async_probe();
-		if (IS_ERR(kthread_run(vec_check_unaligned_access_speed_all_cpus,
-				       NULL, "vec_check_unaligned_access_speed_all_cpus"))) {
-			pr_warn("Failed to create vec_unalign_check kthread\n");
-			riscv_hwprobe_complete_async_probe();
-		}
+		schedule_on_each_cpu(check_vector_unaligned_access);
 	}
 
 	/*
-- 
2.47.3



From namcao at linutronix.de  Tue Jun 16 20:38:23 2026
From: namcao at linutronix.de (Nam Cao)
Date: Wed, 17 Jun 2026 05:38:23 +0200
Subject: [PATCH 0/2] riscv: unaligned: stop using kthread for vector speed probe
Message-ID: <cover.1781666867.git.namcao@linutronix.de>

Hi,

This series is follow-up to the discussion at:
https://lore.kernel.org/linux-riscv/20260612-vec_unaligned_drop_init-v1-1-df969210ae34 at oss.tenstorrent.com/

It removes the kthread usage for unaligned vector access speed probe, avoiding
a bug that the kthread may still be excuting a __init function that have
already been freed.

It also allows removing some vdso synchronization, simplify the code.

This kthread has been bothering me for a while now, and the recent bug report
pushed me to post this series.

Nam Cao (2):
  riscv: unaligned: stop using kthread for
    check_vector_unaligned_access()
  Revert "riscv: hwprobe: Fix stale vDSO data for late-initialized keys
    at boot"

 arch/riscv/include/asm/hwprobe.h           |  7 ---
 arch/riscv/include/asm/vdso/arch_data.h    |  6 --
 arch/riscv/kernel/sys_hwprobe.c            | 70 ++++------------------
 arch/riscv/kernel/unaligned_access_speed.c | 19 +-----
 arch/riscv/kernel/vdso/hwprobe.c           |  2 +-
 5 files changed, 15 insertions(+), 89 deletions(-)

-- 
2.47.3



From namcao at linutronix.de  Tue Jun 16 20:38:25 2026
From: namcao at linutronix.de (Nam Cao)
Date: Wed, 17 Jun 2026 05:38:25 +0200
Subject: [PATCH 2/2] Revert "riscv: hwprobe: Fix stale vDSO data for late-initialized keys at boot"
In-Reply-To: <cover.1781666867.git.namcao@linutronix.de>
References: <cover.1781666867.git.namcao@linutronix.de>
Message-ID: <50ca78a649faf53f8941bc94c9cf8268b3644d38.1781666867.git.namcao@linutronix.de>

This reverts commit 5d15d2ad36b0 ("riscv: hwprobe: Fix stale vDSO data for
late-initialized keys at boot"). The commit ensures synchronization between
the unaligned vector access speed probe kthread and vDSO data read. But now
that the kthread has been removed, this commit can be reverted.

Signed-off-by: Nam Cao <namcao at linutronix.de>
---
 arch/riscv/include/asm/hwprobe.h        |  7 ---
 arch/riscv/include/asm/vdso/arch_data.h |  6 ---
 arch/riscv/kernel/sys_hwprobe.c         | 70 +++++--------------------
 arch/riscv/kernel/vdso/hwprobe.c        |  2 +-
 4 files changed, 13 insertions(+), 72 deletions(-)

diff --git a/arch/riscv/include/asm/hwprobe.h b/arch/riscv/include/asm/hwprobe.h
index 8b9f5e1cf4cb..9b04377c0f98 100644
--- a/arch/riscv/include/asm/hwprobe.h
+++ b/arch/riscv/include/asm/hwprobe.h
@@ -43,11 +43,4 @@ static inline bool riscv_hwprobe_pair_cmp(struct riscv_hwprobe *pair,
 	return pair->value == other_pair->value;
 }
 
-#ifdef CONFIG_MMU
-void riscv_hwprobe_register_async_probe(void);
-void riscv_hwprobe_complete_async_probe(void);
-#else
-static inline void riscv_hwprobe_register_async_probe(void) {}
-static inline void riscv_hwprobe_complete_async_probe(void) {}
-#endif
 #endif
diff --git a/arch/riscv/include/asm/vdso/arch_data.h b/arch/riscv/include/asm/vdso/arch_data.h
index 88b37af55175..da57a3786f7a 100644
--- a/arch/riscv/include/asm/vdso/arch_data.h
+++ b/arch/riscv/include/asm/vdso/arch_data.h
@@ -12,12 +12,6 @@ struct vdso_arch_data {
 
 	/* Boolean indicating all CPUs have the same static hwprobe values. */
 	__u8 homogeneous_cpus;
-
-	/*
-	 * A gate to check and see if the hwprobe data is actually ready, as
-	 * probing is deferred to avoid boot slowdowns.
-	 */
-	__u8 ready;
 };
 
 #endif /* __RISCV_ASM_VDSO_ARCH_DATA_H */
diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
index 1659d31fd288..2ce162f5cf7c 100644
--- a/arch/riscv/kernel/sys_hwprobe.c
+++ b/arch/riscv/kernel/sys_hwprobe.c
@@ -5,9 +5,6 @@
  * more details.
  */
 #include <linux/syscalls.h>
-#include <linux/completion.h>
-#include <linux/atomic.h>
-#include <linux/once.h>
 #include <asm/cacheflush.h>
 #include <asm/cpufeature.h>
 #include <asm/hwprobe.h>
@@ -504,32 +501,28 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,
 	return 0;
 }
 
-#ifdef CONFIG_MMU
-
-static DECLARE_COMPLETION(boot_probes_done);
-static atomic_t pending_boot_probes = ATOMIC_INIT(1);
-
-void riscv_hwprobe_register_async_probe(void)
+static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs,
+			    size_t pair_count, size_t cpusetsize,
+			    unsigned long __user *cpus_user,
+			    unsigned int flags)
 {
-	atomic_inc(&pending_boot_probes);
-}
+	if (flags & RISCV_HWPROBE_WHICH_CPUS)
+		return hwprobe_get_cpus(pairs, pair_count, cpusetsize,
+					cpus_user, flags);
 
-void riscv_hwprobe_complete_async_probe(void)
-{
-	if (atomic_dec_and_test(&pending_boot_probes))
-		complete(&boot_probes_done);
+	return hwprobe_get_values(pairs, pair_count, cpusetsize,
+				  cpus_user, flags);
 }
 
-static int complete_hwprobe_vdso_data(void)
+#ifdef CONFIG_MMU
+
+static int __init init_hwprobe_vdso_data(void)
 {
 	struct vdso_arch_data *avd = vdso_k_arch_data;
 	u64 id_bitsmash = 0;
 	struct riscv_hwprobe pair;
 	int key;
 
-	if (unlikely(!atomic_dec_and_test(&pending_boot_probes)))
-		wait_for_completion(&boot_probes_done);
-
 	/*
 	 * Initialize vDSO data with the answers for the "all CPUs" case, to
 	 * save a syscall in the common case.
@@ -557,52 +550,13 @@ static int complete_hwprobe_vdso_data(void)
 	 * vDSO should defer to the kernel for exotic cpu masks.
 	 */
 	avd->homogeneous_cpus = id_bitsmash != 0 && id_bitsmash != -1;
-
-	/*
-	 * Make sure all the VDSO values are visible before we look at them.
-	 * This pairs with the implicit "no speculativly visible accesses"
-	 * barrier in the VDSO hwprobe code.
-	 */
-	smp_wmb();
-	avd->ready = true;
-	return 0;
-}
-
-static int __init init_hwprobe_vdso_data(void)
-{
-	struct vdso_arch_data *avd = vdso_k_arch_data;
-
-	/*
-	 * Prevent the vDSO cached values from being used, as they're not ready
-	 * yet.
-	 */
-	avd->ready = false;
 	return 0;
 }
 
 arch_initcall_sync(init_hwprobe_vdso_data);
 
-#else
-
-static int complete_hwprobe_vdso_data(void) { return 0; }
-
 #endif /* CONFIG_MMU */
 
-static int do_riscv_hwprobe(struct riscv_hwprobe __user *pairs,
-			    size_t pair_count, size_t cpusetsize,
-			    unsigned long __user *cpus_user,
-			    unsigned int flags)
-{
-	DO_ONCE_SLEEPABLE(complete_hwprobe_vdso_data);
-
-	if (flags & RISCV_HWPROBE_WHICH_CPUS)
-		return hwprobe_get_cpus(pairs, pair_count, cpusetsize,
-					cpus_user, flags);
-
-	return hwprobe_get_values(pairs, pair_count, cpusetsize,
-				cpus_user, flags);
-}
-
 SYSCALL_DEFINE5(riscv_hwprobe, struct riscv_hwprobe __user *, pairs,
 		size_t, pair_count, size_t, cpusetsize, unsigned long __user *,
 		cpus, unsigned int, flags)
diff --git a/arch/riscv/kernel/vdso/hwprobe.c b/arch/riscv/kernel/vdso/hwprobe.c
index 8f45500d0a6e..2ddeba6c68dd 100644
--- a/arch/riscv/kernel/vdso/hwprobe.c
+++ b/arch/riscv/kernel/vdso/hwprobe.c
@@ -27,7 +27,7 @@ static int riscv_vdso_get_values(struct riscv_hwprobe *pairs, size_t pair_count,
 	 * homogeneous, then this function can handle requests for arbitrary
 	 * masks.
 	 */
-	if (flags != 0 || (!all_cpus && !avd->homogeneous_cpus) || unlikely(!avd->ready))
+	if ((flags != 0) || (!all_cpus && !avd->homogeneous_cpus))
 		return riscv_hwprobe(pairs, pair_count, cpusetsize, cpus, flags);
 
 	/* This is something we can handle, fill out the pairs. */
-- 
2.47.3



From pulehui at huawei.com  Tue Jun 16 20:43:37 2026
From: pulehui at huawei.com (Pu Lehui)
Date: Wed, 17 Jun 2026 11:43:37 +0800
Subject: [PATCH RFC bpf-next 1/2] selftests/bpf: Add riscv support for
 get_preempt_count()
In-Reply-To: <20260420111516.19982-2-yangtiezhu@loongson.cn>
References: <20260420111516.19982-1-yangtiezhu@loongson.cn>
 <20260420111516.19982-2-yangtiezhu@loongson.cn>
Message-ID: <0191fe3f-b956-480d-aef2-a4d75f9e02de@huawei.com>


On 2026/4/20 19:15, Tiezhu Yang wrote:
> There is no riscv support for get_preempt_count() currently and its
> fallback path always returns 0, just add it so that bpf_in_interrupt(),
> bpf_in_nmi(), bpf_in_hardirq(), bpf_in_serving_softirq(), bpf_in_task()
> works for riscv as well. With this patch, "./test_progs -t exe_ctx"
> should pass on riscv.
> 
> Signed-off-by: Tiezhu Yang <yangtiezhu at loongson.cn>
> ---
>   tools/testing/selftests/bpf/bpf_experimental.h | 7 +++++++
>   1 file changed, 7 insertions(+)
> 
> diff --git a/tools/testing/selftests/bpf/bpf_experimental.h b/tools/testing/selftests/bpf/bpf_experimental.h
> index 2234bd6bc9d3..e5c039bc44cb 100644
> --- a/tools/testing/selftests/bpf/bpf_experimental.h
> +++ b/tools/testing/selftests/bpf/bpf_experimental.h
> @@ -505,6 +505,8 @@ static inline int get_preempt_count(void)
>   	return bpf_get_current_task_btf()->thread_info.preempt_count;
>   #elif defined(bpf_target_s390)
>   	return bpf_get_lowcore()->preempt_count;
> +#elif defined(bpf_target_riscv)
> +	return bpf_get_current_task_btf()->thread_info.preempt_count;
>   #endif
>   	return 0;
>   }
> @@ -515,6 +517,7 @@ static inline int get_preempt_count(void)
>    *	* arm64
>    *	* powerpc64
>    *	* s390x
> + *	* riscv
>    */
>   static inline int bpf_in_interrupt(void)
>   {
> @@ -536,6 +539,7 @@ static inline int bpf_in_interrupt(void)
>    *	* arm64
>    *	* powerpc64
>    *	* s390x
> + *	* riscv
>    */
>   static inline int bpf_in_nmi(void)
>   {
> @@ -548,6 +552,7 @@ static inline int bpf_in_nmi(void)
>    *	* arm64
>    *	* powerpc64
>    *	* s390x
> + *	* riscv
>    */
>   static inline int bpf_in_hardirq(void)
>   {
> @@ -560,6 +565,7 @@ static inline int bpf_in_hardirq(void)
>    *	* arm64
>    *	* powerpc64
>    *	* s390x
> + *	* riscv
>    */
>   static inline int bpf_in_serving_softirq(void)
>   {
> @@ -580,6 +586,7 @@ static inline int bpf_in_serving_softirq(void)
>    *	* arm64
>    *	* powerpc64
>    *	* s390x
> + *	* riscv
>    */
>   static inline int bpf_in_task(void)
>   {

Hi Tiezhu,

Thanks for doing this, feel free to add:

Tested-by: Pu Lehui <pulehui at huawei.com>
Reviewed-by: Pu Lehui <pulehui at huawei.com>


From mpe at kernel.org  Tue Jun 16 23:24:45 2026
From: mpe at kernel.org (Michael Ellerman)
Date: Wed, 17 Jun 2026 16:24:45 +1000
Subject: [PATCH] riscv: hwprobe: Avoid uninitialized read in
 hwprobe_get_cpus()
In-Reply-To: <CAMdZqKEpxT3vzE97LbaxP9grg5wi3aeArzgdyORHyGz=ZsDe0g@mail.gmail.com>
References: <20260612045502.70850-1-mark.hsj@gmail.com>
 <77749c92-ac8a-4074-bb59-59dbbd3d84f2@kernel.org>
 <CAMdZqKEpxT3vzE97LbaxP9grg5wi3aeArzgdyORHyGz=ZsDe0g@mail.gmail.com>
Message-ID: <dda194a3-aa0f-4284-882d-7bfd0317edb1@kernel.org>

On 16/6/26 1:53 pm, Mark Harris wrote:
> Michael Ellerman wrote:
>>
>> On 12/6/26 2:55 pm, Mark Harris wrote:
>>> When cpusetsize < cpumask_size(), hwprobe_get_cpus() did not fully
>>> initialize its copy of the cpu mask, which could cause non-deterministic
>>> results from the riscv_hwprobe syscall on a system with more than 8 CPUs
>>> when the supplied cpu mask is empty.  Address this by fully initializing
>>> the cpu mask.
>>>
>>> Signed-off-by: Mark Harris <mark.hsj at gmail.com>
>>> ---
>>>    arch/riscv/kernel/sys_hwprobe.c | 1 +
>>>    1 file changed, 1 insertion(+)
>>
>> This should have a fixes tag, I think it's:
>>
>> Fixes: e178bf146e4b ("RISC-V: hwprobe: Introduce which-cpus flag")
> 
> Yes, that looks correct.
> 
>>
>>> diff --git a/arch/riscv/kernel/sys_hwprobe.c b/arch/riscv/kernel/sys_hwprobe.c
>>> index 1659d31fd288..caf6762427c8 100644
>>> --- a/arch/riscv/kernel/sys_hwprobe.c
>>> +++ b/arch/riscv/kernel/sys_hwprobe.c
>>> @@ -450,6 +450,7 @@ static int hwprobe_get_cpus(struct riscv_hwprobe __user *pairs,
>>>        if (cpusetsize > cpumask_size())
>>>                cpusetsize = cpumask_size();
>>>
>>> +     cpumask_clear(&cpus);
>>>        ret = copy_from_user(&cpus, cpus_user, cpusetsize);
>>>        if (ret)
>>>                return -EFAULT;
>>
>> cpus is on the stack, and is copied back out at the end of the function,
>> so this looks like it could be a stack info leak.
>>
>> But the copy back is also bounded by cpusetsize, so in fact there is not
>> any leak of uninitialised stack out to userspace:
>>
>>           ret = copy_to_user(cpus_user, &cpus, cpusetsize);
>>           if (ret)
>>                   return -EFAULT;
> 
> It can leak 1 bit of information from the kernel stack.  For example
> with 16 CPUs, all online, if a 1-byte 0x00 mask is supplied, the
> caller can determine whether the second (uninitialized) mask byte is
> zero or non-zero due to the cpumask_empty(&cpus) check.
Oh yep, because the caller can observe if cpus was/wasn't overwritten 
with the cpus_online_mask.

I guess that counts as an info leak, it doesn't let an attacker 
reconstruct actual values from the stack, but a zero/non-zero check 
could be useful in theory.

cheers


From pulehui at huawei.com  Tue Jun 16 23:53:16 2026
From: pulehui at huawei.com (Pu Lehui)
Date: Wed, 17 Jun 2026 14:53:16 +0800
Subject: [PATCH bpf-next v2 1/3] riscv, bpf: Fix support for BPF_SDIV and
 BPF_SMOD in RV32 JIT
In-Reply-To: <20260511221648.3251464-2-visitorckw@gmail.com>
References: <20260511221648.3251464-1-visitorckw@gmail.com>
 <20260511221648.3251464-2-visitorckw@gmail.com>
Message-ID: <c20a7c0e-121f-474c-945a-2a4705a45bd5@huawei.com>


lgtm, just some nits

On 2026/5/12 6:16, Kuan-Wei Chiu wrote:
> The current rv32 bpf jit compiler incorrectly treats BPF_SDIV and
> BPF_SMOD as unsigned operations. The BPF instruction set allows
> signed division and modulo by reusing the BPF_DIV and BPF_MOD opcodes
> with the instruction offset set to 1.
> 
> Update the emit_alu_r32() function to accept an 'is_sdiv' variable and
> emit the correct div and rem instructions when the offset is 1.
> 
> Before this patch:
> [   44.161771] test_bpf: #165 ALU_SDIV_X: -6 / 2 = -3 jited:1 ret 2147483645 != -3 (0x7ffffffd != 0xfffffffd)FAIL (1 times)
> [   44.167385] test_bpf: #166 ALU_SDIV_K: -6 / 2 = -3 jited:1 ret 2147483645 != -3 (0x7ffffffd != 0xfffffffd)FAIL (1 times)
> [   44.171053] test_bpf: #169 ALU_SMOD_X: -7 % 2 = -1 jited:1 ret 1 != -1 (0x1 != 0xffffffff)FAIL (1 times)
> [   44.172081] test_bpf: #170 ALU_SMOD_K: -7 % 2 = -1 jited:1 ret 1 != -1 (0x1 != 0xffffffff)FAIL (1 times)
> 
> After this patch:
> [   16.002192] test_bpf: #165 ALU_SDIV_X: -6 / 2 = -3 jited:1 95 PASS
> [   16.002983] test_bpf: #166 ALU_SDIV_K: -6 / 2 = -3 jited:1 1059 PASS
> [   16.017167] test_bpf: #169 ALU_SMOD_X: -7 % 2 = -1 jited:1 136 PASS
> [   16.023002] test_bpf: #170 ALU_SMOD_K: -7 % 2 = -1 jited:1 109 PASS
> 
> Fixes: ec0e2da95f72 ("bpf: Support new signed div/mod instructions.")
> Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> ---
>   arch/riscv/net/bpf_jit_comp32.c | 19 ++++++++++++++-----
>   1 file changed, 14 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/riscv/net/bpf_jit_comp32.c b/arch/riscv/net/bpf_jit_comp32.c
> index 592dd86fbf81..7396899ea276 100644
> --- a/arch/riscv/net/bpf_jit_comp32.c
> +++ b/arch/riscv/net/bpf_jit_comp32.c
> @@ -509,7 +509,7 @@ static void emit_alu_r64(const s8 *dst, const s8 *src,
>   }
>   
>   static void emit_alu_r32(const s8 *dst, const s8 *src,
> -			 struct rv_jit_context *ctx, const u8 op)
> +			 struct rv_jit_context *ctx, const u8 op, bool is_sdiv)

let's combind `op` and `is_sdiv` to `const struct bpf_insn *insn`, and 
better to name `is_signed = insn->off == 1`

>   {
>   	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
>   	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
> @@ -539,10 +539,16 @@ static void emit_alu_r32(const s8 *dst, const s8 *src,
>   		emit(rv_mul(lo(rd), lo(rd), lo(rs)), ctx);
>   		break;
>   	case BPF_DIV:
> -		emit(rv_divu(lo(rd), lo(rd), lo(rs)), ctx);
> +		if (is_sdiv)
> +			emit(rv_div(lo(rd), lo(rd), lo(rs)), ctx);
> +		else
> +			emit(rv_divu(lo(rd), lo(rd), lo(rs)), ctx);
>   		break;
>   	case BPF_MOD:
> -		emit(rv_remu(lo(rd), lo(rd), lo(rs)), ctx);
> +		if (is_sdiv)
> +			emit(rv_rem(lo(rd), lo(rd), lo(rs)), ctx);
> +		else
> +			emit(rv_remu(lo(rd), lo(rd), lo(rs)), ctx);

how about
emit(is_signed ? rv_rem(lo(rd) : rv_remu(lo(rd), lo(rd), lo(rs)), ctx)

>   		break;
>   	case BPF_LSH:
>   		emit(rv_sll(lo(rd), lo(rd), lo(rs)), ctx);
> @@ -959,6 +965,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   	u8 code = insn->code;
>   	s16 off = insn->off;
>   	s32 imm = insn->imm;
> +	bool is_sdiv = false;
>   
>   	const s8 *dst = bpf2rv32[insn->dst_reg];
>   	const s8 *src = bpf2rv32[insn->src_reg];
> @@ -1041,7 +1048,9 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   			emit_imm32(tmp2, imm, ctx);
>   			src = tmp2;
>   		}
> -		emit_alu_r32(dst, src, ctx, BPF_OP(code));
> +		if ((BPF_OP(code) == BPF_DIV || BPF_OP(code) == BPF_MOD) && insn->off == 1)
> +			is_sdiv = true;
> +		emit_alu_r32(dst, src, ctx, BPF_OP(code), is_sdiv);
>   		break;
>   
>   	case BPF_ALU | BPF_MOV | BPF_K:
> @@ -1065,7 +1074,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   		 * src is ignored---choose tmp2 as a dummy register since it
>   		 * is not on the stack.
>   		 */
> -		emit_alu_r32(dst, tmp2, ctx, BPF_OP(code));
> +		emit_alu_r32(dst, tmp2, ctx, BPF_OP(code), false);
>   		break;
>   
>   	case BPF_ALU | BPF_END | BPF_FROM_LE:


From pulehui at huawei.com  Wed Jun 17 00:30:03 2026
From: pulehui at huawei.com (Pu Lehui)
Date: Wed, 17 Jun 2026 15:30:03 +0800
Subject: [PATCH bpf-next v2 2/3] riscv, bpf: Fix support for BPF_MOVSX in
 RV32 JIT
In-Reply-To: <20260511221648.3251464-3-visitorckw@gmail.com>
References: <20260511221648.3251464-1-visitorckw@gmail.com>
 <20260511221648.3251464-3-visitorckw@gmail.com>
Message-ID: <2ca2a85a-d4a9-4459-a534-6159de6e5890@huawei.com>



On 2026/5/12 6:16, Kuan-Wei Chiu wrote:
> The current rv32 bpf jit compiler incorrectly treats BPF_MOVSX as a
> standard zero-extended move operation. The bpf instruction set allows
> sign-extension moves by reusing the BPF_MOV opcode with the instruction
> offset set to 8, 16, or 32.
> 
> Update the bpf_jit_emit_insn() function to check the offset field for
> both ALU and ALU64 MOV operations. If the offset is non-zero, emit the
> correct slli and srai instructions to perform the sign extension.
> 
> Before this patch:
> [   19.549705] test_bpf: #82 ALU_MOVSX | BPF_B jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
> [   19.551354] test_bpf: #83 ALU_MOVSX | BPF_H jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
> [   19.552576] test_bpf: #84 ALU64_MOVSX | BPF_B jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
> [   19.553542] test_bpf: #85 ALU64_MOVSX | BPF_H jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
> [   19.554807] test_bpf: #86 ALU64_MOVSX | BPF_W jited:1 ret 2 != 1 (0x2 != 0x1)FAIL (1 times)
> 
> After this patch:
> [   17.931172] test_bpf: #82 ALU_MOVSX | BPF_B jited:1 125 PASS
> [   17.932198] test_bpf: #83 ALU_MOVSX | BPF_H jited:1 124 PASS
> [   17.933039] test_bpf: #84 ALU64_MOVSX | BPF_B jited:1 124 PASS
> [   17.933918] test_bpf: #85 ALU64_MOVSX | BPF_H jited:1 124 PASS
> [   17.934751] test_bpf: #86 ALU64_MOVSX | BPF_W jited:1 122 PASS
> 
> Fixes: 8100928c8814 ("bpf: Support new sign-extension mov insns")

not a fix, the fixes tag should remove. And the title should `Add 
support for xxx`

others lgtm,

Reviewed-by: Pu Lehui <pulehui at huawei.com>

> Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> ---
>   arch/riscv/net/bpf_jit_comp32.c | 32 ++++++++++++++++++++++++++++++++
>   1 file changed, 32 insertions(+)
> 
> diff --git a/arch/riscv/net/bpf_jit_comp32.c b/arch/riscv/net/bpf_jit_comp32.c
> index 7396899ea276..f8509950fed4 100644
> --- a/arch/riscv/net/bpf_jit_comp32.c
> +++ b/arch/riscv/net/bpf_jit_comp32.c
> @@ -974,6 +974,24 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   
>   	switch (code) {
>   	case BPF_ALU64 | BPF_MOV | BPF_X:
> +		if (insn->off != 0) {
> +			const s8 *rd = bpf_get_reg64(dst, tmp1, ctx);
> +			const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
> +
> +			if (insn->off == 8) {
> +				emit(rv_slli(lo(rd), lo(rs), 24), ctx);
> +				emit(rv_srai(lo(rd), lo(rd), 24), ctx);
> +			} else if (insn->off == 16) {
> +				emit(rv_slli(lo(rd), lo(rs), 16), ctx);
> +				emit(rv_srai(lo(rd), lo(rd), 16), ctx);
> +			} else {
> +				emit(rv_addi(lo(rd), lo(rs), 0), ctx);
> +			}
> +			emit(rv_srai(hi(rd), lo(rd), 31), ctx);
> +			bpf_put_reg64(dst, rd, ctx);
> +			break;
> +		}
> +		fallthrough;
>   
>   	case BPF_ALU64 | BPF_ADD | BPF_X:
>   	case BPF_ALU64 | BPF_ADD | BPF_K:
> @@ -1024,6 +1042,20 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   			emit_zext64(dst, ctx);
>   			break;
>   		}
> +		if (insn->off != 0) {
> +			const s8 *rd = bpf_get_reg32(dst, tmp1, ctx);
> +			const s8 *rs = bpf_get_reg32(src, tmp2, ctx);
> +
> +			if (insn->off == 8) {
> +				emit(rv_slli(lo(rd), lo(rs), 24), ctx);
> +				emit(rv_srai(lo(rd), lo(rd), 24), ctx);
> +			} else if (insn->off == 16) {
> +				emit(rv_slli(lo(rd), lo(rs), 16), ctx);
> +				emit(rv_srai(lo(rd), lo(rd), 16), ctx);
> +			}
> +			bpf_put_reg32(dst, rd, ctx);
> +			break;
> +		}
>   		fallthrough;
>   
>   	case BPF_ALU | BPF_ADD | BPF_X:


From pulehui at huawei.com  Wed Jun 17 00:54:30 2026
From: pulehui at huawei.com (Pu Lehui)
Date: Wed, 17 Jun 2026 15:54:30 +0800
Subject: [PATCH bpf-next v2 3/3] riscv, bpf: Add 32 bit atomic operations
 to RV32 JIT
In-Reply-To: <20260511221648.3251464-4-visitorckw@gmail.com>
References: <20260511221648.3251464-1-visitorckw@gmail.com>
 <20260511221648.3251464-4-visitorckw@gmail.com>
Message-ID: <1a44ce6d-58cd-4d0a-86bf-2670962e89f7@huawei.com>


On 2026/5/12 6:16, Kuan-Wei Chiu wrote:
> The RV32 BPF JIT compiler currently only supports the BPF_ADD atomic
> operation. Other 32 bit atomic operations (and, or, xor, xchg) and
> their BPF_FETCH variants are not supported and gracefully fall back to
> the interpreter.
> 
> Since the RISC-V A extension is required for Linux on RV32, we can
> natively support these 32-bit BPF atomic operations by mapping them
> directly to the corresponding RISC-V amo*.w instructions.
> 
> Implement BPF_ADD, BPF_AND, BPF_OR, BPF_XOR, and BPF_XCHG with and
> without BPF_FETCH. BPF_CMPXCHG requires a more complex lr.w/sc.w
> loop and is left to fall back to the interpreter.
> 
> Before this patch:
> [  138.862161] test_bpf: Summary: 1054 PASSED, 0 FAILED, [843/1042 JIT'ed]
> 
> After this patch:
> [  157.024124] test_bpf: Summary: 1054 PASSED, 0 FAILED, [902/1042 JIT'ed]
> 
> Signed-off-by: Kuan-Wei Chiu <visitorckw at gmail.com>
> ---
>   arch/riscv/net/bpf_jit_comp32.c | 50 +++++++++++++++++++++++++--------
>   1 file changed, 39 insertions(+), 11 deletions(-)
> 
> diff --git a/arch/riscv/net/bpf_jit_comp32.c b/arch/riscv/net/bpf_jit_comp32.c
> index f8509950fed4..7fd726a09b26 100644
> --- a/arch/riscv/net/bpf_jit_comp32.c
> +++ b/arch/riscv/net/bpf_jit_comp32.c
> @@ -877,7 +877,7 @@ static int emit_load_r64(const s8 *dst, const s8 *src, s16 off,
>   
>   static int emit_store_r64(const s8 *dst, const s8 *src, s16 off,
>   			  struct rv_jit_context *ctx, const u8 size,
> -			  const u8 mode)
> +			  const u8 mode, s32 imm)
>   {
>   	const s8 *tmp1 = bpf2rv32[TMP_REG_1];
>   	const s8 *tmp2 = bpf2rv32[TMP_REG_2];
> @@ -902,11 +902,43 @@ static int emit_store_r64(const s8 *dst, const s8 *src, s16 off,
>   		case BPF_MEM:
>   			emit(rv_sw(RV_REG_T0, 0, lo(rs)), ctx);
>   			break;
> -		case BPF_ATOMIC: /* Only BPF_ADD supported */
> -			emit(rv_amoadd_w(RV_REG_ZERO, lo(rs), RV_REG_T0, 0, 0),
> -			     ctx);
> +		case BPF_ATOMIC:
> +		{
> +			bool is_fetch = (imm & BPF_FETCH) || (imm == BPF_XCHG);
> +			s8 fetch_reg = is_fetch ? lo(rs) : RV_REG_ZERO;
> +			int aq = is_fetch ? 1 : 0;
> +			int rl = is_fetch ? 1 : 0;
> +
> +			switch (imm) {
> +			case BPF_ADD:
> +			case BPF_ADD | BPF_FETCH:
> +				emit(rv_amoadd_w(fetch_reg, lo(rs), RV_REG_T0, aq, rl), ctx);
> +				break;
> +			case BPF_AND:
> +			case BPF_AND | BPF_FETCH:
> +				emit(rv_amoand_w(fetch_reg, lo(rs), RV_REG_T0, aq, rl), ctx);
> +				break;
> +			case BPF_OR:
> +			case BPF_OR | BPF_FETCH:
> +				emit(rv_amoor_w(fetch_reg, lo(rs), RV_REG_T0, aq, rl), ctx);
> +				break;
> +			case BPF_XOR:
> +			case BPF_XOR | BPF_FETCH:
> +				emit(rv_amoxor_w(fetch_reg, lo(rs), RV_REG_T0, aq, rl), ctx);
> +				break;
> +			case BPF_XCHG:
> +				emit(rv_amoswap_w(fetch_reg, lo(rs), RV_REG_T0, aq, rl), ctx);
> +				break;
> +			default:
> +				return -1;
> +			}
> +			if (is_fetch) {
> +				emit(rv_addi(hi(rs), RV_REG_ZERO, 0), ctx);
> +				bpf_put_reg64(src, rs, ctx); > +			}
>   			break;

rv32 code looks elegant, let's factor out an atomic function

>   		}
> +		}
>   		break;
>   	case BPF_DW:
>   		emit(rv_sw(RV_REG_T0, 0, lo(rs)), ctx);
> @@ -1308,20 +1340,16 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,
>   		}
>   
>   		if (emit_store_r64(dst, src, off, ctx, BPF_SIZE(code),
> -				   BPF_MODE(code)))
> +				   BPF_MODE(code), 0))
>   			return -1;
>   		break;
>   
>   	case BPF_STX | BPF_ATOMIC | BPF_W:
> -		if (insn->imm != BPF_ADD) {

just `insn->imm == BPF_CMPXCHG` here, and not miss the warning message.

> -			pr_info_once(
> -				"bpf-jit: not supported: atomic operation %02x ***\n",
> -				insn->imm);
> +		if (insn->imm == BPF_CMPXCHG)
>   			return -EFAULT;
> -		}
>   
>   		if (emit_store_r64(dst, src, off, ctx, BPF_SIZE(code),
> -				   BPF_MODE(code)))
> +				   BPF_MODE(code), insn->imm))
>   			return -1;
>   		break;
>   


From namcao at linutronix.de  Wed Jun 17 01:49:06 2026
From: namcao at linutronix.de (Nam Cao)
Date: Wed, 17 Jun 2026 10:49:06 +0200
Subject: [PATCH 1/2] riscv: unaligned: stop using kthread for
 check_vector_unaligned_access()
In-Reply-To: <1c378963f27c5960e8a57c50b8b444d30954cb54.1781666867.git.namcao@linutronix.de>
References: <cover.1781666867.git.namcao@linutronix.de>
 <1c378963f27c5960e8a57c50b8b444d30954cb54.1781666867.git.namcao@linutronix.de>
Message-ID: <87tsr1zh4t.fsf@yellow.woof>

Nam Cao <namcao at linutronix.de> writes:
> A kthread is used to run check_vector_unaligned_access() to optimize boot
> time, allowing the kernel to continue booting without waiting for the
> unaligned vector speed probe to finish.
>
> However, this asynchronous approach introduces several complications.
> First, the kthread may not complete before a user reads vDSO data,
> resulting in incorrect values. This was previously addressed by
> commit 5d15d2ad36b0 ("riscv: hwprobe: Fix stale vDSO data for
> late-initialized keys at boot"), which added complex synchronization
> between the kthread and vDSO reads.
>
> Second, it was discovered that the kthread may not finish before
> vec_check_unaligned_access_speed_all_cpus() (marked with __init) is freed,
> triggering a page fault.
>
> These issues raise the question of whether the kthread is worth the added
> complexity. A past boot time regression report was actually unrelated to
> synchronous probing; it was caused by the probe running serially. Since
> switching to a parallel probe, no further complaints have been made.
> Furthermore, the unaligned scalar access speed probe takes the same amount
> of time, runs synchronously, and has caused no issues.

Another point I forgot to include. We start the kthread to run
asynchronously, but the probe is executed on all CPUs including the boot
CPU. Therefore if the kthread is executed before boot is completed,
asynchronous probe will actually slow down boot time due to the overhead
with kthread. If the kthread is executed after boot is completed, we run
into the two race conditions mentioned above.

> Testing shows no noticeable boot time slowdown when running the vector
> probe synchronously (0.464474s with kthread vs. 0.457991s without).
>
> Remove the kthread usage and run the probe synchronously. This simplifies
> the boot flow and allows for the revert of commit 5d15d2ad36b0 ("riscv:
> hwprobe: Fix stale vDSO data for late-initialized keys at boot")
>
> Reported-by: Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>
> Closes: https://lore.kernel.org/linux-riscv/20260612-vec_unaligned_drop_init-v1-1-df969210ae34 at oss.tenstorrent.com/
> Fixes: a00e022be531 ("riscv: Annotate unaligned access init functions")
> Cc: <stable at vger.kernel.org>
> Signed-off-by: Nam Cao <namcao at linutronix.de>


From shanbeeyoo at gmail.com  Wed Jun 17 01:52:26 2026
From: shanbeeyoo at gmail.com (bingyu.xian)
Date: Wed, 17 Jun 2026 16:52:26 +0800
Subject: [PATCH v1] iommu/riscv: Add page request queue and IOPF support
Message-ID: <20260617085226.3189819-1-shanbeeyoo@gmail.com>

From: "bingyu.xian" <shanbeenyoo at gmail.com>

The RISC-V IOMMU Architecture Specification, Version 1.0, Chapter 3.3
defines a Page-request Queue (PQ) for handling PCIe Page Request
Interface (PRI) messages. The current driver implements only the
Command Queue (CQ) and Fault Queue (FQ); the PQ is left
unimplemented, which is the biggest functional gap compared with the
ARM SMMUv3 driver.

Add PQ and IOPF support:

- Initialize and enable the PQ when the hardware advertises ATS
  capability (RISCV_IOMMU_CAPABILITIES_ATS), and add an IOMMU_IOPF
  Kconfig dependency.
- Implement the PQ interrupt handler riscv_iommu_priq_process(),
  which consumes PQ records from the hardware ring buffer.
- Translate PQ records into the kernel's generic iopf_fault format
  and pass them to the IOPF framework via
  iommu_report_device_fault().
- Implement the .page_response callback, which builds an ATS.PRGR
  (Page Request Group Response) command and sends it through the
  command queue to notify the requesting device.

Tested on QEMU 10.0 with '-M virt,iommu-sys=on' and
CONFIG_IOMMU_IOPF=y; the PQ comes up cleanly:

  riscv,iommu 3010000.iommu: page request queue enabled
  
Test patch
==========

diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index b1c2d3e4f5a6..3af3f19de94f 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -16,6 +16,7 @@
 #include <linux/acpi_rimt.h>
 #include <linux/compiler.h>
 #include <linux/crash_dump.h>
+#include <linux/debugfs.h>
 #include <linux/init.h>
 #include <linux/iommu.h>
 #include <linux/iopoll.h>
@@ -1608,9 +1609,62 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
 	return 0;
 }

+#ifdef CONFIG_DEBUG_FS
+/*
+ * debugfs interface to inject a fake PQ record without real PRI hardware.
+ *
+ * Writing a PCI BDF-encoded device id to the 'inject_pq' file constructs a
+ * synthetic riscv_iommu_pq_record and feeds it directly to
+ * riscv_iommu_handle_pq(), exercising the IOPF report path and, via the
+ * IOPF framework, the .page_response -> ATS.PRGR command path.
+ *
+ * The IRQ-driven priq_process() consumer loop is not exercised here, but it
+ * reuses the same queue infrastructure as the existing fltq_process().
+ */
+static struct dentry *riscv_iommu_debugfs_dir;
+
+static int riscv_iommu_inject_pq_set(void *data, u64 val)
+{
+	struct riscv_iommu_device *iommu = data;
+	struct riscv_iommu_pq_record fake_req;
+	unsigned int devid = (unsigned int)val;
+
+	if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)) {
+		dev_err(iommu->dev, "inject_pq: ATS not supported\n");
+		return -ENODEV;
+	}
+
+	memset(&fake_req, 0, sizeof(fake_req));
+	fake_req.hdr = FIELD_PREP(RISCV_IOMMU_PQ_HDR_DID, devid);
+	fake_req.payload = FIELD_PREP(RISCV_IOMMU_PQ_PAYLOAD_ADDR, 0xdead0) |
+			   FIELD_PREP(RISCV_IOMMU_PQ_PAYLOAD_PRGI, 1) |
+			   RISCV_IOMMU_PQ_PAYLOAD_L |
+			   RISCV_IOMMU_PQ_PAYLOAD_R;
+
+	dev_info(iommu->dev,
+		 "inject_pq: injecting fake PQ record for devid 0x%x\n", devid);
+	riscv_iommu_handle_pq(iommu, &fake_req);
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(riscv_iommu_inject_pq_fops, NULL,
+			 riscv_iommu_inject_pq_set, "%llu\n");
+
+static void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu)
+{
+	riscv_iommu_debugfs_dir = debugfs_create_dir("riscv-iommu", NULL);
+	debugfs_create_file("inject_pq", 0200, riscv_iommu_debugfs_dir,
+			    iommu, &riscv_iommu_inject_pq_fops);
+}
+
+static void riscv_iommu_debugfs_remove(void)
+{
+	debugfs_remove_recursive(riscv_iommu_debugfs_dir);
+	riscv_iommu_debugfs_dir = NULL;
+}
+#else
+static inline void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu) { }
+static inline void riscv_iommu_debugfs_remove(void) { }
+#endif /* CONFIG_DEBUG_FS */
+
 void riscv_iommu_remove(struct riscv_iommu_device *iommu)
 {
+	riscv_iommu_debugfs_remove();
 	iommu_device_unregister(&iommu->iommu);
 	iommu_device_sysfs_remove(&iommu->iommu);
 	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
@@ -1754,6 +1808,8 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
 		goto err_remove_sysfs;
 	}

+	riscv_iommu_debugfs_init(iommu);
+
 	return 0;

 err_remove_sysfs:
---

Test logs:
  root at Ubuntu-riscv64:~# dmesg | grep "iommu"
  [    0.590293] iommu: Default domain type: Translated
  [    0.590379] iommu: DMA domain TLB invalidation policy: lazy mode
  [    1.374106] riscv,iommu 3010000.iommu: failed to find an MSI domain
  [    1.374429] riscv,iommu 3010000.iommu: using wire-signaled interrupts
  [    1.384786] riscv,iommu 3010000.iommu: page request queue enabled
  [    1.391279] pci 0000:00:00.0: Adding to iommu group 0
  [    1.391798] pci 0000:00:01.0: Adding to iommu group 1
  [    1.392023] pci 0000:00:02.0: Adding to iommu group 2
  [    1.392252] pci 0000:00:03.0: Adding to iommu group 3

  root at Ubuntu-riscv64:~# echo 8 > /sys/kernel/debug/riscv-iommu/inject_pq

  root at Ubuntu-riscv64:~# dmesg | grep "iommu"
  [    0.590293] iommu: Default domain type: Translated
  [    0.590379] iommu: DMA domain TLB invalidation policy: lazy mode
  [    1.374106] riscv,iommu 3010000.iommu: failed to find an MSI domain
  [    1.374429] riscv,iommu 3010000.iommu: using wire-signaled interrupts
  [    1.384786] riscv,iommu 3010000.iommu: page request queue enabled
  [    1.391279] pci 0000:00:00.0: Adding to iommu group 0
  [    1.391798] pci 0000:00:01.0: Adding to iommu group 1
  [    1.392023] pci 0000:00:02.0: Adding to iommu group 2
  [    1.392252] pci 0000:00:03.0: Adding to iommu group 3
  [ 1308.301611] riscv,iommu 3010000.iommu: inject_pq: injecting fake PQ record for devid 0x8
  [ 1308.303467] riscv,iommu 3010000.iommu: page request fault report failed: -22

Assisted-by: YuanSheng: deepseek-v4-pro
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: bingyu.xian <shanbeenyoo at gmail.com>
---
 drivers/iommu/riscv/Kconfig |   1 +
 drivers/iommu/riscv/iommu.c | 178 +++++++++++++++++++++++++++++++++++-
 drivers/iommu/riscv/iommu.h |   3 +
 3 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
index b86e5ab94183..c5abb7b4ba8f 100644
--- a/drivers/iommu/riscv/Kconfig
+++ b/drivers/iommu/riscv/Kconfig
@@ -7,6 +7,7 @@ config RISCV_IOMMU
 	depends on GENERIC_MSI_IRQ
 	depends on (RISCV || COMPILE_TEST) && 64BIT
 	select IOMMU_API
+	select IOMMU_IOPF
 	select GENERIC_PT
 	select IOMMU_PT
 	select IOMMU_PT_RISCV64
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index a31f50bbad35..b1c2d3e4f5a6 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -33,9 +33,10 @@
 #define RISCV_IOMMU_DDTP_TIMEOUT	10000000
 #define RISCV_IOMMU_IOTINVAL_TIMEOUT	90000000

-/* Number of entries per CMD/FLT queue, should be <= INT_MAX */
+/* Number of entries per CMD/FLT/PRI queue, should be <= INT_MAX */
 #define RISCV_IOMMU_DEF_CQ_COUNT	8192
 #define RISCV_IOMMU_DEF_FQ_COUNT	4096
+#define RISCV_IOMMU_DEF_PQ_COUNT	4096

 /* RISC-V IOMMU PPN <> PHYS address conversions, PHYS <=> PPN[53:10] */
 #define phys_to_ppn(pa)  (((pa) >> 2) & (((1ULL << 44) - 1) << 10))
@@ -565,6 +566,151 @@ static irqreturn_t riscv_iommu_fltq_process(int irq, void *data)
 	return IRQ_HANDLED;
 }


+static struct device *riscv_iommu_find_dev(struct riscv_iommu_device *iommu,
+					   unsigned int devid)
+{
+	struct pci_bus *bus;
+	struct pci_dev *pdev;
+
+	bus = pci_find_bus(0, devid >> 8);
+	if (!bus)
+		return NULL;
+
+	pdev = pci_get_slot(bus, devid & 0xff);
+	if (!pdev)
+		return NULL;
+
+	return &pdev->dev;
+}
+
+static void riscv_iommu_handle_pq(struct riscv_iommu_device *iommu,
+				  struct riscv_iommu_pq_record *req)
+{
+	struct iopf_fault fault;
+	struct device *dev;
+	unsigned int devid;
+	int ret;
+
+	devid = FIELD_GET(RISCV_IOMMU_PQ_HDR_DID, req->hdr);
+	dev = riscv_iommu_find_dev(iommu, devid);
+	if (!dev) {
+		dev_warn_ratelimited(iommu->dev,
+				     "page request for unknown devid 0x%x\n", devid);
+		return;
+	}
+
+	memset(&fault, 0, sizeof(fault));
+	fault.fault.type = IOMMU_FAULT_PAGE_REQ;
+	fault.fault.prm.addr = FIELD_GET(RISCV_IOMMU_PQ_PAYLOAD_ADDR, req->payload) << 12;
+	fault.fault.prm.grpid = FIELD_GET(RISCV_IOMMU_PQ_PAYLOAD_PRGI, req->payload);
+
+	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_R)
+		fault.fault.prm.perm |= IOMMU_FAULT_PERM_READ;
+	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_W)
+		fault.fault.prm.perm |= IOMMU_FAULT_PERM_WRITE;
+	if (req->hdr & RISCV_IOMMU_PQ_HDR_EXEC)
+		fault.fault.prm.perm |= IOMMU_FAULT_PERM_EXEC;
+	if (req->hdr & RISCV_IOMMU_PQ_HDR_PRIV)
+		fault.fault.prm.perm |= IOMMU_FAULT_PERM_PRIV;
+
+	if (req->hdr & RISCV_IOMMU_PQ_HDR_PV) {
+		fault.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID |
+					 IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID;
+		fault.fault.prm.pasid = FIELD_GET(RISCV_IOMMU_PQ_HDR_PID, req->hdr);
+	}
+
+	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_L)
+		fault.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
+
+	/* Store DID in private_data for page_response to send ATS.PRGR */
+	fault.fault.prm.private_data[0] = devid;
+
+	ret = iommu_report_device_fault(dev, &fault);
+	if (ret) {
+		dev_warn_ratelimited(iommu->dev,
+				     "page request fault report failed: %d\n", ret);
+	}
+}
+
+/* Page request queue interrupt handler thread function */
+static irqreturn_t riscv_iommu_priq_process(int irq, void *data)
+{
+	struct riscv_iommu_queue *queue = (struct riscv_iommu_queue *)data;
+	struct riscv_iommu_device *iommu = queue->iommu;
+	struct riscv_iommu_pq_record *requests;
+	unsigned int ctrl, idx;
+	int cnt, len;
+
+	requests = (struct riscv_iommu_pq_record *)queue->base;
+
+	/* Clear page request interrupt pending and process all records. */
+	riscv_iommu_writel(iommu, RISCV_IOMMU_REG_IPSR, Q_IPSR(queue));
+
+	do {
+		cnt = riscv_iommu_queue_consume(queue, &idx);
+		for (len = 0; len < cnt; idx++, len++)
+			riscv_iommu_handle_pq(iommu, &requests[Q_ITEM(queue, idx)]);
+		riscv_iommu_queue_release(queue, cnt);
+	} while (cnt > 0);
+
+	/* Clear MF/OF errors */
+	ctrl = riscv_iommu_readl(iommu, queue->qcr);
+	if (ctrl & (RISCV_IOMMU_PQCSR_PQMF | RISCV_IOMMU_PQCSR_PQOF)) {
+		riscv_iommu_writel(iommu, queue->qcr, ctrl);
+		dev_warn(iommu->dev,
+			 "Queue #%u error; memory fault:%d overflow:%d\n",
+			 queue->qid,
+			 !!(ctrl & RISCV_IOMMU_PQCSR_PQMF),
+			 !!(ctrl & RISCV_IOMMU_PQCSR_PQOF));
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* Send ATS.PRGR page response through the command queue */
+static void riscv_iommu_page_response(struct device *dev,
+				      struct iopf_fault *evt,
+				      struct iommu_page_response *msg)
+{
+	struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+	struct riscv_iommu_command cmd;
+	unsigned int devid;
+	u8 resp_code;
+
+	/* Recover DID from private_data stored during PQ processing */
+	devid = evt->fault.prm.private_data[0];
+
+	switch (msg->code) {
+	case IOMMU_PAGE_RESP_SUCCESS:
+		resp_code = 0; /* Success */
+		break;
+	case IOMMU_PAGE_RESP_INVALID:
+		resp_code = 1; /* Invalid Request */
+		break;
+	case IOMMU_PAGE_RESP_FAILURE:
+	default:
+		resp_code = 0xF; /* Response Failure */
+		break;
+	}
+
+	/* Build ATS.PRGR command */
+	cmd.dword0 = FIELD_PREP(RISCV_IOMMU_CMD_OPCODE, RISCV_IOMMU_CMD_ATS_OPCODE) |
+		     FIELD_PREP(RISCV_IOMMU_CMD_FUNC, RISCV_IOMMU_CMD_ATS_FUNC_PRGR) |
+		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_RID, devid);
+
+	if (evt->fault.prm.flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID)
+		cmd.dword0 |= FIELD_PREP(RISCV_IOMMU_CMD_ATS_PID, evt->fault.prm.pasid) |
+			      RISCV_IOMMU_CMD_ATS_PV;
+
+	cmd.dword1 = FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_PRG_INDEX, msg->grpid) |
+		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE, resp_code) |
+		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_DST_ID, devid);
+
+	riscv_iommu_cmd_send(iommu, &cmd);
+}
+
 /* Lookup and initialize device context info structure. */
 static struct riscv_iommu_dc *riscv_iommu_get_dc(struct riscv_iommu_device *iommu,
 						 unsigned int devid)
@@ -1404,6 +1550,7 @@ static const struct iommu_ops riscv_iommu_ops = {
 	.device_group = riscv_iommu_device_group,
 	.probe_device = riscv_iommu_probe_device,
 	.release_device	= riscv_iommu_release_device,
+	.page_response = riscv_iommu_page_response,
 };

 static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
@@ -1466,6 +1613,8 @@ void riscv_iommu_remove(struct riscv_iommu_device *iommu)
 	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
 	riscv_iommu_queue_disable(&iommu->cmdq);
 	riscv_iommu_queue_disable(&iommu->fltq);
+	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)
+		riscv_iommu_queue_disable(&iommu->priq);
 }

 int riscv_iommu_init(struct riscv_iommu_device *iommu)
@@ -1494,6 +1643,15 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
 	if (rc)
 		return rc;

+	/* Allocate page request queue if ATS is supported */
+	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) {
+		RISCV_IOMMU_QUEUE_INIT(&iommu->priq, PQ);
+		rc = riscv_iommu_queue_alloc(iommu, &iommu->priq,
+					     sizeof(struct riscv_iommu_pq_record));
+		if (rc)
+			return rc;
+	}
+
 	rc = riscv_iommu_queue_enable(iommu, &iommu->cmdq, riscv_iommu_cmdq_process);
 	if (rc)
 		return rc;
@@ -1502,6 +1660,15 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
 	if (rc)
 		goto err_queue_disable;

+	/* Enable page request queue if ATS is supported */
+	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) {
+		rc = riscv_iommu_queue_enable(iommu, &iommu->priq,
+					      riscv_iommu_priq_process);
+		if (rc)
+			goto err_queue_disable;
+		dev_info(iommu->dev, "page request queue enabled\n");
+	}
+
 	rc = riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_MAX);
 	if (rc)
 		goto err_queue_disable;
@@ -1534,6 +1701,8 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
 err_iodir_off:
 	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
 err_queue_disable:
+	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)
+		riscv_iommu_queue_disable(&iommu->priq);
 	riscv_iommu_queue_disable(&iommu->fltq);
 	riscv_iommu_queue_disable(&iommu->cmdq);
 	return rc;
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 46df79dd5495..5c5ab24539f2 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -14,6 +14,8 @@
 #include <linux/iommu.h>
 #include <linux/types.h>
 #include <linux/iopoll.h>
+#include <linux/pci.h>
+#include <linux/pci-ats.h>

 #include "iommu-bits.h"

@@ -55,6 +57,7 @@ struct riscv_iommu_device {
 	/* hardware queues */
 	struct riscv_iommu_queue cmdq;
 	struct riscv_iommu_queue fltq;
+	struct riscv_iommu_queue priq;

 	/* device directory */
 	unsigned int ddt_mode;
--
2.53.0



From shanbeeyoo at gmail.com  Wed Jun 17 02:01:16 2026
From: shanbeeyoo at gmail.com (bingyu.xian)
Date: Wed, 17 Jun 2026 17:01:16 +0800
Subject: [PATCH v1] iommu/riscv: Add page request queue and IOPF support
Message-ID: <20260617090116.3254505-1-shanbeeyoo@gmail.com>

The RISC-V IOMMU Architecture Specification, Version 1.0, Chapter 3.3
defines a Page-request Queue (PQ) for handling PCIe Page Request
Interface (PRI) messages. The current driver implements only the
Command Queue (CQ) and Fault Queue (FQ); the PQ is left
unimplemented, which is the biggest functional gap compared with the
ARM SMMUv3 driver.

Add PQ and IOPF support:

- Initialize and enable the PQ when the hardware advertises ATS
  capability (RISCV_IOMMU_CAPABILITIES_ATS), and add an IOMMU_IOPF
  Kconfig dependency.
- Implement the PQ interrupt handler riscv_iommu_priq_process(),
  which consumes PQ records from the hardware ring buffer.
- Translate PQ records into the kernel's generic iopf_fault format
  and pass them to the IOPF framework via
  iommu_report_device_fault().
- Implement the .page_response callback, which builds an ATS.PRGR
  (Page Request Group Response) command and sends it through the
  command queue to notify the requesting device.

Tested on QEMU 10.0 with '-M virt,iommu-sys=on' and
CONFIG_IOMMU_IOPF=y; the PQ comes up cleanly:

  riscv,iommu 3010000.iommu: page request queue enabled
  
Test patch
==========

diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index b1c2d3e4f5a6..3af3f19de94f 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -16,6 +16,7 @@
 #include <linux/acpi_rimt.h>
 #include <linux/compiler.h>
 #include <linux/crash_dump.h>
+#include <linux/debugfs.h>
 #include <linux/init.h>
 #include <linux/iommu.h>
 #include <linux/iopoll.h>
@@ -1608,9 +1609,62 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
 	return 0;
 }

+#ifdef CONFIG_DEBUG_FS
+/*
+ * debugfs interface to inject a fake PQ record without real PRI hardware.
+ *
+ * Writing a PCI BDF-encoded device id to the 'inject_pq' file constructs a
+ * synthetic riscv_iommu_pq_record and feeds it directly to
+ * riscv_iommu_handle_pq(), exercising the IOPF report path and, via the
+ * IOPF framework, the .page_response -> ATS.PRGR command path.
+ *
+ * The IRQ-driven priq_process() consumer loop is not exercised here, but it
+ * reuses the same queue infrastructure as the existing fltq_process().
+ */
+static struct dentry *riscv_iommu_debugfs_dir;
+
+static int riscv_iommu_inject_pq_set(void *data, u64 val)
+{
+	struct riscv_iommu_device *iommu = data;
+	struct riscv_iommu_pq_record fake_req;
+	unsigned int devid = (unsigned int)val;
+
+	if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)) {
+		dev_err(iommu->dev, "inject_pq: ATS not supported\n");
+		return -ENODEV;
+	}
+
+	memset(&fake_req, 0, sizeof(fake_req));
+	fake_req.hdr = FIELD_PREP(RISCV_IOMMU_PQ_HDR_DID, devid);
+	fake_req.payload = FIELD_PREP(RISCV_IOMMU_PQ_PAYLOAD_ADDR, 0xdead0) |
+			   FIELD_PREP(RISCV_IOMMU_PQ_PAYLOAD_PRGI, 1) |
+			   RISCV_IOMMU_PQ_PAYLOAD_L |
+			   RISCV_IOMMU_PQ_PAYLOAD_R;
+
+	dev_info(iommu->dev,
+		 "inject_pq: injecting fake PQ record for devid 0x%x\n", devid);
+	riscv_iommu_handle_pq(iommu, &fake_req);
+	return 0;
+}
+
+DEFINE_DEBUGFS_ATTRIBUTE(riscv_iommu_inject_pq_fops, NULL,
+			 riscv_iommu_inject_pq_set, "%llu\n");
+
+static void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu)
+{
+	riscv_iommu_debugfs_dir = debugfs_create_dir("riscv-iommu", NULL);
+	debugfs_create_file("inject_pq", 0200, riscv_iommu_debugfs_dir,
+			    iommu, &riscv_iommu_inject_pq_fops);
+}
+
+static void riscv_iommu_debugfs_remove(void)
+{
+	debugfs_remove_recursive(riscv_iommu_debugfs_dir);
+	riscv_iommu_debugfs_dir = NULL;
+}
+#else
+static inline void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu) { }
+static inline void riscv_iommu_debugfs_remove(void) { }
+#endif /* CONFIG_DEBUG_FS */
+
 void riscv_iommu_remove(struct riscv_iommu_device *iommu)
 {
+	riscv_iommu_debugfs_remove();
 	iommu_device_unregister(&iommu->iommu);
 	iommu_device_sysfs_remove(&iommu->iommu);
 	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
@@ -1754,6 +1808,8 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
 		goto err_remove_sysfs;
 	}

+	riscv_iommu_debugfs_init(iommu);
+
 	return 0;

 err_remove_sysfs:
---

Test logs:
  root at Ubuntu-riscv64:~# dmesg | grep "iommu"
  [    0.590293] iommu: Default domain type: Translated
  [    0.590379] iommu: DMA domain TLB invalidation policy: lazy mode
  [    1.374106] riscv,iommu 3010000.iommu: failed to find an MSI domain
  [    1.374429] riscv,iommu 3010000.iommu: using wire-signaled interrupts
  [    1.384786] riscv,iommu 3010000.iommu: page request queue enabled
  [    1.391279] pci 0000:00:00.0: Adding to iommu group 0
  [    1.391798] pci 0000:00:01.0: Adding to iommu group 1
  [    1.392023] pci 0000:00:02.0: Adding to iommu group 2
  [    1.392252] pci 0000:00:03.0: Adding to iommu group 3

  root at Ubuntu-riscv64:~# echo 8 > /sys/kernel/debug/riscv-iommu/inject_pq

  root at Ubuntu-riscv64:~# dmesg | grep "iommu"
  [    0.590293] iommu: Default domain type: Translated
  [    0.590379] iommu: DMA domain TLB invalidation policy: lazy mode
  [    1.374106] riscv,iommu 3010000.iommu: failed to find an MSI domain
  [    1.374429] riscv,iommu 3010000.iommu: using wire-signaled interrupts
  [    1.384786] riscv,iommu 3010000.iommu: page request queue enabled
  [    1.391279] pci 0000:00:00.0: Adding to iommu group 0
  [    1.391798] pci 0000:00:01.0: Adding to iommu group 1
  [    1.392023] pci 0000:00:02.0: Adding to iommu group 2
  [    1.392252] pci 0000:00:03.0: Adding to iommu group 3
  [ 1308.301611] riscv,iommu 3010000.iommu: inject_pq: injecting fake PQ record for devid 0x8
  [ 1308.303467] riscv,iommu 3010000.iommu: page request fault report failed: -22

Assisted-by: YuanSheng: deepseek-v4-pro
Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
Signed-off-by: bingyu.xian <shanbeeyoo at gmail.com>
---
 drivers/iommu/riscv/Kconfig |   1 +
 drivers/iommu/riscv/iommu.c | 178 +++++++++++++++++++++++++++++++++++-
 drivers/iommu/riscv/iommu.h |   3 +
 3 files changed, 181 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
index b86e5ab94183..c5abb7b4ba8f 100644
--- a/drivers/iommu/riscv/Kconfig
+++ b/drivers/iommu/riscv/Kconfig
@@ -7,6 +7,7 @@ config RISCV_IOMMU
 	depends on GENERIC_MSI_IRQ
 	depends on (RISCV || COMPILE_TEST) && 64BIT
 	select IOMMU_API
+	select IOMMU_IOPF
 	select GENERIC_PT
 	select IOMMU_PT
 	select IOMMU_PT_RISCV64
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index a31f50bbad35..b1c2d3e4f5a6 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -33,9 +33,10 @@
 #define RISCV_IOMMU_DDTP_TIMEOUT	10000000
 #define RISCV_IOMMU_IOTINVAL_TIMEOUT	90000000

-/* Number of entries per CMD/FLT queue, should be <= INT_MAX */
+/* Number of entries per CMD/FLT/PRI queue, should be <= INT_MAX */
 #define RISCV_IOMMU_DEF_CQ_COUNT	8192
 #define RISCV_IOMMU_DEF_FQ_COUNT	4096
+#define RISCV_IOMMU_DEF_PQ_COUNT	4096

 /* RISC-V IOMMU PPN <> PHYS address conversions, PHYS <=> PPN[53:10] */
 #define phys_to_ppn(pa)  (((pa) >> 2) & (((1ULL << 44) - 1) << 10))
@@ -565,6 +566,151 @@ static irqreturn_t riscv_iommu_fltq_process(int irq, void *data)
 	return IRQ_HANDLED;
 }


+static struct device *riscv_iommu_find_dev(struct riscv_iommu_device *iommu,
+					   unsigned int devid)
+{
+	struct pci_bus *bus;
+	struct pci_dev *pdev;
+
+	bus = pci_find_bus(0, devid >> 8);
+	if (!bus)
+		return NULL;
+
+	pdev = pci_get_slot(bus, devid & 0xff);
+	if (!pdev)
+		return NULL;
+
+	return &pdev->dev;
+}
+
+static void riscv_iommu_handle_pq(struct riscv_iommu_device *iommu,
+				  struct riscv_iommu_pq_record *req)
+{
+	struct iopf_fault fault;
+	struct device *dev;
+	unsigned int devid;
+	int ret;
+
+	devid = FIELD_GET(RISCV_IOMMU_PQ_HDR_DID, req->hdr);
+	dev = riscv_iommu_find_dev(iommu, devid);
+	if (!dev) {
+		dev_warn_ratelimited(iommu->dev,
+				     "page request for unknown devid 0x%x\n", devid);
+		return;
+	}
+
+	memset(&fault, 0, sizeof(fault));
+	fault.fault.type = IOMMU_FAULT_PAGE_REQ;
+	fault.fault.prm.addr = FIELD_GET(RISCV_IOMMU_PQ_PAYLOAD_ADDR, req->payload) << 12;
+	fault.fault.prm.grpid = FIELD_GET(RISCV_IOMMU_PQ_PAYLOAD_PRGI, req->payload);
+
+	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_R)
+		fault.fault.prm.perm |= IOMMU_FAULT_PERM_READ;
+	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_W)
+		fault.fault.prm.perm |= IOMMU_FAULT_PERM_WRITE;
+	if (req->hdr & RISCV_IOMMU_PQ_HDR_EXEC)
+		fault.fault.prm.perm |= IOMMU_FAULT_PERM_EXEC;
+	if (req->hdr & RISCV_IOMMU_PQ_HDR_PRIV)
+		fault.fault.prm.perm |= IOMMU_FAULT_PERM_PRIV;
+
+	if (req->hdr & RISCV_IOMMU_PQ_HDR_PV) {
+		fault.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID |
+					 IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID;
+		fault.fault.prm.pasid = FIELD_GET(RISCV_IOMMU_PQ_HDR_PID, req->hdr);
+	}
+
+	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_L)
+		fault.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
+
+	/* Store DID in private_data for page_response to send ATS.PRGR */
+	fault.fault.prm.private_data[0] = devid;
+
+	ret = iommu_report_device_fault(dev, &fault);
+	if (ret) {
+		dev_warn_ratelimited(iommu->dev,
+				     "page request fault report failed: %d\n", ret);
+	}
+}
+
+/* Page request queue interrupt handler thread function */
+static irqreturn_t riscv_iommu_priq_process(int irq, void *data)
+{
+	struct riscv_iommu_queue *queue = (struct riscv_iommu_queue *)data;
+	struct riscv_iommu_device *iommu = queue->iommu;
+	struct riscv_iommu_pq_record *requests;
+	unsigned int ctrl, idx;
+	int cnt, len;
+
+	requests = (struct riscv_iommu_pq_record *)queue->base;
+
+	/* Clear page request interrupt pending and process all records. */
+	riscv_iommu_writel(iommu, RISCV_IOMMU_REG_IPSR, Q_IPSR(queue));
+
+	do {
+		cnt = riscv_iommu_queue_consume(queue, &idx);
+		for (len = 0; len < cnt; idx++, len++)
+			riscv_iommu_handle_pq(iommu, &requests[Q_ITEM(queue, idx)]);
+		riscv_iommu_queue_release(queue, cnt);
+	} while (cnt > 0);
+
+	/* Clear MF/OF errors */
+	ctrl = riscv_iommu_readl(iommu, queue->qcr);
+	if (ctrl & (RISCV_IOMMU_PQCSR_PQMF | RISCV_IOMMU_PQCSR_PQOF)) {
+		riscv_iommu_writel(iommu, queue->qcr, ctrl);
+		dev_warn(iommu->dev,
+			 "Queue #%u error; memory fault:%d overflow:%d\n",
+			 queue->qid,
+			 !!(ctrl & RISCV_IOMMU_PQCSR_PQMF),
+			 !!(ctrl & RISCV_IOMMU_PQCSR_PQOF));
+	}
+
+	return IRQ_HANDLED;
+}
+
+/* Send ATS.PRGR page response through the command queue */
+static void riscv_iommu_page_response(struct device *dev,
+				      struct iopf_fault *evt,
+				      struct iommu_page_response *msg)
+{
+	struct riscv_iommu_device *iommu = dev_to_iommu(dev);
+	struct riscv_iommu_command cmd;
+	unsigned int devid;
+	u8 resp_code;
+
+	/* Recover DID from private_data stored during PQ processing */
+	devid = evt->fault.prm.private_data[0];
+
+	switch (msg->code) {
+	case IOMMU_PAGE_RESP_SUCCESS:
+		resp_code = 0; /* Success */
+		break;
+	case IOMMU_PAGE_RESP_INVALID:
+		resp_code = 1; /* Invalid Request */
+		break;
+	case IOMMU_PAGE_RESP_FAILURE:
+	default:
+		resp_code = 0xF; /* Response Failure */
+		break;
+	}
+
+	/* Build ATS.PRGR command */
+	cmd.dword0 = FIELD_PREP(RISCV_IOMMU_CMD_OPCODE, RISCV_IOMMU_CMD_ATS_OPCODE) |
+		     FIELD_PREP(RISCV_IOMMU_CMD_FUNC, RISCV_IOMMU_CMD_ATS_FUNC_PRGR) |
+		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_RID, devid);
+
+	if (evt->fault.prm.flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID)
+		cmd.dword0 |= FIELD_PREP(RISCV_IOMMU_CMD_ATS_PID, evt->fault.prm.pasid) |
+			      RISCV_IOMMU_CMD_ATS_PV;
+
+	cmd.dword1 = FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_PRG_INDEX, msg->grpid) |
+		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE, resp_code) |
+		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_DST_ID, devid);
+
+	riscv_iommu_cmd_send(iommu, &cmd);
+}
+
 /* Lookup and initialize device context info structure. */
 static struct riscv_iommu_dc *riscv_iommu_get_dc(struct riscv_iommu_device *iommu,
 						 unsigned int devid)
@@ -1404,6 +1550,7 @@ static const struct iommu_ops riscv_iommu_ops = {
 	.device_group = riscv_iommu_device_group,
 	.probe_device = riscv_iommu_probe_device,
 	.release_device	= riscv_iommu_release_device,
+	.page_response = riscv_iommu_page_response,
 };

 static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
@@ -1466,6 +1613,8 @@ void riscv_iommu_remove(struct riscv_iommu_device *iommu)
 	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
 	riscv_iommu_queue_disable(&iommu->cmdq);
 	riscv_iommu_queue_disable(&iommu->fltq);
+	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)
+		riscv_iommu_queue_disable(&iommu->priq);
 }

 int riscv_iommu_init(struct riscv_iommu_device *iommu)
@@ -1494,6 +1643,15 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
 	if (rc)
 		return rc;

+	/* Allocate page request queue if ATS is supported */
+	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) {
+		RISCV_IOMMU_QUEUE_INIT(&iommu->priq, PQ);
+		rc = riscv_iommu_queue_alloc(iommu, &iommu->priq,
+					     sizeof(struct riscv_iommu_pq_record));
+		if (rc)
+			return rc;
+	}
+
 	rc = riscv_iommu_queue_enable(iommu, &iommu->cmdq, riscv_iommu_cmdq_process);
 	if (rc)
 		return rc;
@@ -1502,6 +1660,15 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
 	if (rc)
 		goto err_queue_disable;

+	/* Enable page request queue if ATS is supported */
+	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) {
+		rc = riscv_iommu_queue_enable(iommu, &iommu->priq,
+					      riscv_iommu_priq_process);
+		if (rc)
+			goto err_queue_disable;
+		dev_info(iommu->dev, "page request queue enabled\n");
+	}
+
 	rc = riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_MAX);
 	if (rc)
 		goto err_queue_disable;
@@ -1534,6 +1701,8 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
 err_iodir_off:
 	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
 err_queue_disable:
+	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)
+		riscv_iommu_queue_disable(&iommu->priq);
 	riscv_iommu_queue_disable(&iommu->fltq);
 	riscv_iommu_queue_disable(&iommu->cmdq);
 	return rc;
diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
index 46df79dd5495..5c5ab24539f2 100644
--- a/drivers/iommu/riscv/iommu.h
+++ b/drivers/iommu/riscv/iommu.h
@@ -14,6 +14,8 @@
 #include <linux/iommu.h>
 #include <linux/types.h>
 #include <linux/iopoll.h>
+#include <linux/pci.h>
+#include <linux/pci-ats.h>

 #include "iommu-bits.h"

@@ -55,6 +57,7 @@ struct riscv_iommu_device {
 	/* hardware queues */
 	struct riscv_iommu_queue cmdq;
 	struct riscv_iommu_queue fltq;
+	struct riscv_iommu_queue priq;

 	/* device directory */
 	unsigned int ddt_mode;
--
2.53.0



From david at kernel.org  Wed Jun 17 04:07:14 2026
From: david at kernel.org (David Hildenbrand (Arm))
Date: Wed, 17 Jun 2026 13:07:14 +0200
Subject: [PATCH] mm/page_table_check: do not track special (PFN-mapped)
 PTEs
In-Reply-To: <20260608155758.1220420-1-andrey.smirnov@siderolabs.com>
References: <20260608155758.1220420-1-andrey.smirnov@siderolabs.com>
Message-ID: <e37721e1-75d6-4908-8f93-7c0f68a73eb9@kernel.org>

On 6/8/26 17:57, Andrey Smirnov wrote:
> The vDSO data store ("[vvar]") special mapping is created as a VM_PFNMAP
> mapping and its pages are installed into userspace with vmf_insert_pfn(),
> which produces special PTEs (pte_special()). On x86 and arm64 (and riscv)
> pte_user_accessible_page() only tests the PRESENT/USER bits and does not
> exclude special PTEs, so page_table_check accounts these PFN mappings in
> the per-page anon/file map counters even though they are not rmap-managed
> pages (vm_normal_page() returns NULL for them).
> 
> Most of these data pages live in the kernel image and are never freed, so
> the stray accounting is invisible. The time-namespace VVAR page is the
> exception: it is a real alloc_page() page that is released with
> __free_page() in free_time_ns() when the last task of a time namespace
> exits. Across the map / unmap / vdso_join_timens() zap transitions the
> special-PTE accounting is not balanced for this page, so a non-zero
> file_map_count survives to the free path and trips:
> 
>   kernel BUG at mm/page_table_check.c:143!
>   __page_table_check_zero+0xfb/0x130
>   __free_frozen_pages+0x52f/0x650
>   free_time_ns+0x85/0xc0
>   free_nsproxy+0x7f/0x130
>   do_exit+0x313/0xa60
>   do_group_exit+0x77/0x90
> 
> This is reliably reproducible on x86_64 and arm64 under heavy container/CI
> churn that rapidly creates and destroys time namespaces (CLONE_NEWTIME via
> runc / docker-init / tini), and was independently reported by syzbot on
> riscv. It only manifests when CONFIG_PAGE_TABLE_CHECK is active.
> 
> Special PTEs have no struct-page rmap semantics and must never have been
> tracked by page table check. Skip them in both the set and clear paths so
> the counters stay balanced (always zero) for PFN-mapped pages, regardless
> of how the architecture defines pte_user_accessible_page(). pte_special()
> is available generically (it is a no-op returning false on architectures
> without ARCH_HAS_PTE_SPECIAL), so this is a single, arch-independent fix.

Using pte_special() is usually a sign that something is likely shaky, as it
misses architectures that don't support CONFIG_ARCH_HAS_PTE_SPECIAL.

I assume relevant architectures (loongarch32?) do not support
CONFIG_PAGE_TABLE_CHECK.

arch/arm64/Kconfig:     select ARCH_SUPPORTS_PAGE_TABLE_CHECK
arch/powerpc/Kconfig:   select ARCH_SUPPORTS_PAGE_TABLE_CHECK   if !HUGETLB_PAGE
arch/riscv/Kconfig:     select ARCH_SUPPORTS_PAGE_TABLE_CHECK if MMU
arch/s390/Kconfig:      select ARCH_SUPPORTS_PAGE_TABLE_CHECK
arch/x86/Kconfig:       select ARCH_SUPPORTS_PAGE_TABLE_CHECK   if X86_64
mm/Kconfig.debug:       depends on ARCH_SUPPORTS_PAGE_TABLE_CHECK

Can we enforce somehow that we expect CONFIG_ARCH_HAS_PTE_SPECIAL, so anybody
unlocking ARCH_SUPPORTS_PAGE_TABLE_CHECK is aware of this?

For example, through a BUILD_BUG_ON?

-- 
Cheers,

David


From devnexen at gmail.com  Wed Jun 17 04:53:42 2026
From: devnexen at gmail.com (David Carlier)
Date: Wed, 17 Jun 2026 12:53:42 +0100
Subject: [PATCH v5] mm: pgtable: free kernel page tables via RCU to fix ptdump UAF
Message-ID: <20260617115342.156775-1-devnexen@gmail.com>

ptdump_walk_pgd() walks the kernel page tables under get_online_mems() and
mmap_write_lock(&init_mm). Neither lock stops vmalloc from freeing a kernel
PTE page underneath the walk.

When vmap_try_huge_pmd() promotes a range to a huge PMD it collapses the
existing PTE table and frees it via pmd_free_pte_page(). On x86, riscv and
powerpc this runs without the init_mm mmap lock; only arm64 takes it, and not
on the block-split path. So ptdump can dereference a just-freed PTE page,
which is the use after free syzbot hit in ptdump_pte_entry().

The race is not new. ptdump walks the whole kernel address space, including
ranges other code is actively mapping, so it reads page tables it does not
own. 5ba2f0a15564 ("mm: introduce deferred freeing for kernel page tables")
only widened the window; the Fixes tag points there for that reason.

Every other walker works on a range it owns and is the only one mutating it:
set_memory() on arm64/riscv/loongarch, the arm64 block-split path, the
openrisc DMA path and the hugetlb_vmemmap remap. Nothing frees those ranges
concurrently, so they cannot race and do not need RCU. ptdump is the only
walker that traverses ranges it does not own.

Defer the free by an RCU grace period. pagetable_free_kernel() now frees via
call_rcu() in both the async and non-async configs. The async path still
flushes the TLB first, then queues the per-page RCU free. The page stays
valid until any walk that may have observed it drops its RCU read lock.

On the read side ptdump_walk_pgd() takes the RCU read lock around the walk,
and walk_page_range_debug() asserts it with RCU_LOCKDEP_WARN() for the
init_mm case rather than taking it, matching pagewalk.c convention. A walker
either sees the cleared PMD and skips, or keeps the page alive until it drops
the lock. The owned-range walkers are unchanged.

ptdump callbacks now run under RCU, so they must not sleep. The arch
note_page() and effective_prot() callbacks only format into the preallocated
seq_file buffer, and the walker does not call cond_resched(); the only
GFP_KERNEL marker setup runs before the walk.

Fixes: 5ba2f0a15564 ("mm: introduce deferred freeing for kernel page tables")
Reported-by: syzbot+fd95a72470f5a44e464c at syzkaller.appspotmail.com
Closes: https://lore.kernel.org/all/6a287988.39669fcc.33b062.00a0.GAE at google.com/T/
Assisted-by: Claude:claude-opus-4-8
Signed-off-by: David Carlier <devnexen at gmail.com>
---
v5: reframe changelog around the pre-existing race and range ownership;
    correct the mmap-lock description (arm64 is the exception, not x86);
    move rcu_read_lock() into ptdump_walk_pgd() and assert it in
    walk_page_range_debug(); drop walk_kernel_page_table_range_rcu(); fix the
    pgtable-generic.c comment; document the no-sleep audit of the callbacks.
v4: defer the free in both the async and non async configs, not just
    the async one. Move the walk under a named
    walk_kernel_page_table_range_rcu() helper instead of open coding
    rcu_read_lock() in walk_page_range_debug().
v3: take rcu_read_lock() in the init_mm branch of
    walk_page_range_debug() rather than inside the lockless walker,
    which the arm64 split paths also use with GFP_PGTABLE_KERNEL and
    can sleep.
v2: use call_rcu() instead of synchronize_rcu().
---
 include/linux/mm.h   |  7 -------
 mm/pagewalk.c        | 14 +++++++++-----
 mm/pgtable-generic.c | 22 +++++++++++++++++++++-
 mm/ptdump.c          |  2 ++
 4 files changed, 32 insertions(+), 13 deletions(-)

diff --git a/include/linux/mm.h b/include/linux/mm.h
index 485df9c2dbdd..79408a17a1b0 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -3695,14 +3695,7 @@ static inline void __pagetable_free(struct ptdesc *pt)
 	__free_pages(page, compound_order(page));
 }
 
-#ifdef CONFIG_ASYNC_KERNEL_PGTABLE_FREE
 void pagetable_free_kernel(struct ptdesc *pt);
-#else
-static inline void pagetable_free_kernel(struct ptdesc *pt)
-{
-	__pagetable_free(pt);
-}
-#endif
 /**
  * pagetable_free - Free pagetables
  * @pt:	The page table descriptor
diff --git a/mm/pagewalk.c b/mm/pagewalk.c
index 3ae2586ff45b..c0be87580989 100644
--- a/mm/pagewalk.c
+++ b/mm/pagewalk.c
@@ -620,7 +620,7 @@ int walk_page_range(struct mm_struct *mm, unsigned long start,
  * Note: Be careful to walk the kernel pages tables, the caller may be need to
  * take other effective approaches (mmap lock may be insufficient) to prevent
  * the intermediate kernel page tables belonging to the specified address range
- * from being freed (e.g. memory hot-remove).
+ * from being freed (e.g. memory hot-remove, vmap huge page promotion).
  */
 int walk_kernel_page_table_range(unsigned long start, unsigned long end,
 		const struct mm_walk_ops *ops, pgd_t *pgd, void *private)
@@ -643,7 +643,7 @@ int walk_kernel_page_table_range(unsigned long start, unsigned long end,
  * Use this function to walk the kernel page tables locklessly. It should be
  * guaranteed that the caller has exclusive access over the range they are
  * operating on - that there should be no concurrent access, for example,
- * changing permissions for vmalloc objects.
+ * changing permissions for vmalloc objects, or vmap huge page promotion.
  */
 int walk_kernel_page_table_range_lockless(unsigned long start, unsigned long end,
 		const struct mm_walk_ops *ops, pgd_t *pgd, void *private)
@@ -692,9 +692,13 @@ int walk_page_range_debug(struct mm_struct *mm, unsigned long start,
 	};
 
 	/* For convenience, we allow traversal of kernel mappings. */
-	if (mm == &init_mm)
-		return walk_kernel_page_table_range(start, end, ops,
-						    pgd, private);
+	if (mm == &init_mm) {
+		RCU_LOCKDEP_WARN(!rcu_read_lock_held(),
+				 "RCU read lock must be held across kernel page table walk");
+		return walk_kernel_page_table_range(start, end, ops, pgd,
+							private);
+	}
+
 	if (start >= end || !walk.mm)
 		return -EINVAL;
 	if (!check_ops_safe(ops))
diff --git a/mm/pgtable-generic.c b/mm/pgtable-generic.c
index b91b1a98029c..7a32e4821957 100644
--- a/mm/pgtable-generic.c
+++ b/mm/pgtable-generic.c
@@ -410,6 +410,13 @@ pte_t *pte_offset_map_lock(struct mm_struct *mm, pmd_t *pmd,
 	goto again;
 }
 
+static void kernel_pgtable_free_rcu(struct rcu_head *head)
+{
+	struct ptdesc *pt = container_of(head, struct ptdesc, pt_rcu_head);
+
+	__pagetable_free(pt);
+}
+
 #ifdef CONFIG_ASYNC_KERNEL_PGTABLE_FREE
 static void kernel_pgtable_work_func(struct work_struct *work);
 
@@ -434,8 +441,15 @@ static void kernel_pgtable_work_func(struct work_struct *work)
 	spin_unlock(&kernel_pgtable_work.lock);
 
 	iommu_sva_invalidate_kva_range(PAGE_OFFSET, TLB_FLUSH_ALL);
+
+	/*
+	 * Debug walkers (ptdump) may walk ranges they do not own and race this
+	 * free, so they walk under rcu_read_lock(). Free after a grace period:
+	 * a walker either already saw the cleared PMD, or keeps the page alive
+	 * until it drops the RCU lock.
+	 */
 	list_for_each_entry_safe(pt, next, &page_list, pt_list)
-		__pagetable_free(pt);
+		call_rcu(&pt->pt_rcu_head, kernel_pgtable_free_rcu);
 }
 
 void pagetable_free_kernel(struct ptdesc *pt)
@@ -446,4 +460,10 @@ void pagetable_free_kernel(struct ptdesc *pt)
 
 	schedule_work(&kernel_pgtable_work.work);
 }
+#else
+void pagetable_free_kernel(struct ptdesc *pt)
+{
+	/* Defer the free by a grace period; see kernel_pgtable_work_func(). */
+	call_rcu(&pt->pt_rcu_head, kernel_pgtable_free_rcu);
+}
 #endif
diff --git a/mm/ptdump.c b/mm/ptdump.c
index 973020000096..50cd96a33dfd 100644
--- a/mm/ptdump.c
+++ b/mm/ptdump.c
@@ -178,11 +178,13 @@ void ptdump_walk_pgd(struct ptdump_state *st, struct mm_struct *mm, pgd_t *pgd)
 
 	get_online_mems();
 	mmap_write_lock(mm);
+	rcu_read_lock();
 	while (range->start != range->end) {
 		walk_page_range_debug(mm, range->start, range->end,
 				      &ptdump_ops, pgd, st);
 		range++;
 	}
+	rcu_read_unlock();
 	mmap_write_unlock(mm);
 	put_online_mems();
 
-- 
2.53.0



From brauner at kernel.org  Wed Jun 17 05:41:54 2026
From: brauner at kernel.org (Christian Brauner)
Date: Wed, 17 Jun 2026 14:41:54 +0200
Subject: [PATCH 00/19] init: discoverable root partitions, a.k.a. an
 omittable "root=" cmdline option
In-Reply-To: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>
References: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>
Message-ID: <20260617-irritation-rollen-wirst-7d636cbfec92@brauner>

On Mon, Jun 15, 2026 at 06:08:56PM +0200, Vincent Mailhol wrote:
> DPS [1] defines GPT partition type UUIDs for OS partitions and
> attributes that control whether such partitions should be
> automatically discovered. The specification states that:
> 
>   The OS can discover and mount the necessary file systems with a
>   non-existent or incomplete /etc/fstab file and without the root=
>   kernel command line option.
> 
> DPS is already implemented in systemd-gpt-auto-generator [2], which,
> when embedded in an initrd, indeed allows automatic detection of the
> root filesystem through its partition type UUID.
> 
> This series adds this discovery feature directly into the kernel so
> that people who are not using systemd or not using an initrd can still
> benefit from it. The implementation follows the same model as
> systemd-gpt-auto-generator:

I happen to co-maintain the DPS. It is userspace policy and complex
userspace policy at that and does not belong into the kernel.

This also implements a really tiny portion of the spec. It deals with a
lot more complex concepts such as automatic partitioning during
installation, verity, LUKS, containers. This is really not intended for
the kernel at all. I mean, it's great that this spec is being used but I
do not want this in the kernel just for the sake of auto-discovery.

The DPS is completely generic and can be implemented by tooling other
than systemd (util-linux implements it and so does refind iirc). I think
not wanting to use or build alternative userspace tooling for this is a
really weak argument for pushing this into the kernel.


From asrinivasan at oss.tenstorrent.com  Wed Jun 17 07:21:57 2026
From: asrinivasan at oss.tenstorrent.com (Anirudh Srinivasan)
Date: Wed, 17 Jun 2026 09:21:57 -0500
Subject: [PATCH 0/2] riscv: unaligned: stop using kthread for vector speed probe
In-Reply-To: <cover.1781666867.git.namcao@linutronix.de>
References: <cover.1781666867.git.namcao@linutronix.de>
Message-ID: <CAEev2e_nUHUvjfnn9fOe9b3t-tb3F9AYETh-LWfqx=ovf8TLPQ@mail.gmail.com>

Hi,

On Tue, Jun 16, 2026 at 10:38?PM Nam Cao <namcao at linutronix.de> wrote:
>
> Hi,
>
> This series is follow-up to the discussion at:
> https://lore.kernel.org/linux-riscv/20260612-vec_unaligned_drop_init-v1-1-df969210ae34 at oss.tenstorrent.com/
>
> It removes the kthread usage for unaligned vector access speed probe, avoiding
> a bug that the kthread may still be excuting a __init function that have
> already been freed.
>
> It also allows removing some vdso synchronization, simplify the code.
>
> This kthread has been bothering me for a while now, and the recent bug report
> pushed me to post this series.
>
> Nam Cao (2):
>   riscv: unaligned: stop using kthread for
>     check_vector_unaligned_access()
>   Revert "riscv: hwprobe: Fix stale vDSO data for late-initialized keys
>     at boot"
>
>  arch/riscv/include/asm/hwprobe.h           |  7 ---
>  arch/riscv/include/asm/vdso/arch_data.h    |  6 --
>  arch/riscv/kernel/sys_hwprobe.c            | 70 ++++------------------
>  arch/riscv/kernel/unaligned_access_speed.c | 19 +-----
>  arch/riscv/kernel/vdso/hwprobe.c           |  2 +-
>  5 files changed, 15 insertions(+), 89 deletions(-)

Tested on Tenstorrent Blackhole with Sifive x280 cores. Slowing down
the unaligned vector access speed probe doesn't cause boot to fail
now.

Tested-by: Anirudh Srinivasan <asrinivasan at oss.tenstorrent.com>

> --
> 2.47.3
>


From gsh517025 at gmail.com  Wed Jun 17 07:49:10 2026
From: gsh517025 at gmail.com (Gong Shuai)
Date: Wed, 17 Jun 2026 22:49:10 +0800
Subject: [PATCH v1] iommu/riscv: Add page request queue and IOPF support
In-Reply-To: <20260617090116.3254505-1-shanbeeyoo@gmail.com>
References: <20260617090116.3254505-1-shanbeeyoo@gmail.com>
Message-ID: <0c596ea4-8c29-4e5f-8238-cb8f8c5015fc@gmail.com>

On 6/17/2026 5:01 PM, bingyu.xian wrote:
> The RISC-V IOMMU Architecture Specification, Version 1.0, Chapter 3.3
> defines a Page-request Queue (PQ) for handling PCIe Page Request
> Interface (PRI) messages. The current driver implements only the
> Command Queue (CQ) and Fault Queue (FQ); the PQ is left
> unimplemented, which is the biggest functional gap compared with the
> ARM SMMUv3 driver.
> 
> Add PQ and IOPF support:
> 
> - Initialize and enable the PQ when the hardware advertises ATS
>    capability (RISCV_IOMMU_CAPABILITIES_ATS), and add an IOMMU_IOPF
>    Kconfig dependency.
> - Implement the PQ interrupt handler riscv_iommu_priq_process(),
>    which consumes PQ records from the hardware ring buffer.
> - Translate PQ records into the kernel's generic iopf_fault format
>    and pass them to the IOPF framework via
>    iommu_report_device_fault().
> - Implement the .page_response callback, which builds an ATS.PRGR
>    (Page Request Group Response) command and sends it through the
>    command queue to notify the requesting device.
> 


Hi, bingyu

Thanks for your work.

Tomasz already has a complete ATS/PRI/SVA support series on GitHub [1],
which hasn't been posted to the mailing list yet.

[1] https://github.com/tjeznach/linux/commits/riscv_iommu.next


> Tested on QEMU 10.0 with '-M virt,iommu-sys=on' and
> CONFIG_IOMMU_IOPF=y; the PQ comes up cleanly:
> 
>    riscv,iommu 3010000.iommu: page request queue enabled
>    
> Test patch
> ==========


It would be better to separate the test helper into its own patch rather
than mixing it with the core implementation, which makes it hard to
apply directly.

Regards,
Shuai


> 
> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> index b1c2d3e4f5a6..3af3f19de94f 100644
> --- a/drivers/iommu/riscv/iommu.c
> +++ b/drivers/iommu/riscv/iommu.c
> @@ -16,6 +16,7 @@
>   #include <linux/acpi_rimt.h>
>   #include <linux/compiler.h>
>   #include <linux/crash_dump.h>
> +#include <linux/debugfs.h>
>   #include <linux/init.h>
>   #include <linux/iommu.h>
>   #include <linux/iopoll.h>
> @@ -1608,9 +1609,62 @@ static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
>   	return 0;
>   }
> 
> +#ifdef CONFIG_DEBUG_FS
> +/*
> + * debugfs interface to inject a fake PQ record without real PRI hardware.
> + *
> + * Writing a PCI BDF-encoded device id to the 'inject_pq' file constructs a
> + * synthetic riscv_iommu_pq_record and feeds it directly to
> + * riscv_iommu_handle_pq(), exercising the IOPF report path and, via the
> + * IOPF framework, the .page_response -> ATS.PRGR command path.
> + *
> + * The IRQ-driven priq_process() consumer loop is not exercised here, but it
> + * reuses the same queue infrastructure as the existing fltq_process().
> + */
> +static struct dentry *riscv_iommu_debugfs_dir;
> +
> +static int riscv_iommu_inject_pq_set(void *data, u64 val)
> +{
> +	struct riscv_iommu_device *iommu = data;
> +	struct riscv_iommu_pq_record fake_req;
> +	unsigned int devid = (unsigned int)val;
> +
> +	if (!(iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)) {
> +		dev_err(iommu->dev, "inject_pq: ATS not supported\n");
> +		return -ENODEV;
> +	}
> +
> +	memset(&fake_req, 0, sizeof(fake_req));
> +	fake_req.hdr = FIELD_PREP(RISCV_IOMMU_PQ_HDR_DID, devid);
> +	fake_req.payload = FIELD_PREP(RISCV_IOMMU_PQ_PAYLOAD_ADDR, 0xdead0) |
> +			   FIELD_PREP(RISCV_IOMMU_PQ_PAYLOAD_PRGI, 1) |
> +			   RISCV_IOMMU_PQ_PAYLOAD_L |
> +			   RISCV_IOMMU_PQ_PAYLOAD_R;
> +
> +	dev_info(iommu->dev,
> +		 "inject_pq: injecting fake PQ record for devid 0x%x\n", devid);
> +	riscv_iommu_handle_pq(iommu, &fake_req);
> +	return 0;
> +}
> +
> +DEFINE_DEBUGFS_ATTRIBUTE(riscv_iommu_inject_pq_fops, NULL,
> +			 riscv_iommu_inject_pq_set, "%llu\n");
> +
> +static void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu)
> +{
> +	riscv_iommu_debugfs_dir = debugfs_create_dir("riscv-iommu", NULL);
> +	debugfs_create_file("inject_pq", 0200, riscv_iommu_debugfs_dir,
> +			    iommu, &riscv_iommu_inject_pq_fops);
> +}
> +
> +static void riscv_iommu_debugfs_remove(void)
> +{
> +	debugfs_remove_recursive(riscv_iommu_debugfs_dir);
> +	riscv_iommu_debugfs_dir = NULL;
> +}
> +#else
> +static inline void riscv_iommu_debugfs_init(struct riscv_iommu_device *iommu) { }
> +static inline void riscv_iommu_debugfs_remove(void) { }
> +#endif /* CONFIG_DEBUG_FS */
> +
>   void riscv_iommu_remove(struct riscv_iommu_device *iommu)
>   {
> +	riscv_iommu_debugfs_remove();
>   	iommu_device_unregister(&iommu->iommu);
>   	iommu_device_sysfs_remove(&iommu->iommu);
>   	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
> @@ -1754,6 +1808,8 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
>   		goto err_remove_sysfs;
>   	}
> 
> +	riscv_iommu_debugfs_init(iommu);
> +
>   	return 0;
> 
>   err_remove_sysfs:
> ---
> 
> Test logs:
>    root at Ubuntu-riscv64:~# dmesg | grep "iommu"
>    [    0.590293] iommu: Default domain type: Translated
>    [    0.590379] iommu: DMA domain TLB invalidation policy: lazy mode
>    [    1.374106] riscv,iommu 3010000.iommu: failed to find an MSI domain
>    [    1.374429] riscv,iommu 3010000.iommu: using wire-signaled interrupts
>    [    1.384786] riscv,iommu 3010000.iommu: page request queue enabled
>    [    1.391279] pci 0000:00:00.0: Adding to iommu group 0
>    [    1.391798] pci 0000:00:01.0: Adding to iommu group 1
>    [    1.392023] pci 0000:00:02.0: Adding to iommu group 2
>    [    1.392252] pci 0000:00:03.0: Adding to iommu group 3
> 
>    root at Ubuntu-riscv64:~# echo 8 > /sys/kernel/debug/riscv-iommu/inject_pq
> 
>    root at Ubuntu-riscv64:~# dmesg | grep "iommu"
>    [    0.590293] iommu: Default domain type: Translated
>    [    0.590379] iommu: DMA domain TLB invalidation policy: lazy mode
>    [    1.374106] riscv,iommu 3010000.iommu: failed to find an MSI domain
>    [    1.374429] riscv,iommu 3010000.iommu: using wire-signaled interrupts
>    [    1.384786] riscv,iommu 3010000.iommu: page request queue enabled
>    [    1.391279] pci 0000:00:00.0: Adding to iommu group 0
>    [    1.391798] pci 0000:00:01.0: Adding to iommu group 1
>    [    1.392023] pci 0000:00:02.0: Adding to iommu group 2
>    [    1.392252] pci 0000:00:03.0: Adding to iommu group 3
>    [ 1308.301611] riscv,iommu 3010000.iommu: inject_pq: injecting fake PQ record for devid 0x8
>    [ 1308.303467] riscv,iommu 3010000.iommu: page request fault report failed: -22
> 
> Assisted-by: YuanSheng: deepseek-v4-pro
> Co-developed-by: Quan Zhou <zhouquan at iscas.ac.cn>
> Signed-off-by: Quan Zhou <zhouquan at iscas.ac.cn>
> Signed-off-by: bingyu.xian <shanbeeyoo at gmail.com>
> ---
>   drivers/iommu/riscv/Kconfig |   1 +
>   drivers/iommu/riscv/iommu.c | 178 +++++++++++++++++++++++++++++++++++-
>   drivers/iommu/riscv/iommu.h |   3 +
>   3 files changed, 181 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/iommu/riscv/Kconfig b/drivers/iommu/riscv/Kconfig
> index b86e5ab94183..c5abb7b4ba8f 100644
> --- a/drivers/iommu/riscv/Kconfig
> +++ b/drivers/iommu/riscv/Kconfig
> @@ -7,6 +7,7 @@ config RISCV_IOMMU
>   	depends on GENERIC_MSI_IRQ
>   	depends on (RISCV || COMPILE_TEST) && 64BIT
>   	select IOMMU_API
> +	select IOMMU_IOPF
>   	select GENERIC_PT
>   	select IOMMU_PT
>   	select IOMMU_PT_RISCV64
> diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
> index a31f50bbad35..b1c2d3e4f5a6 100644
> --- a/drivers/iommu/riscv/iommu.c
> +++ b/drivers/iommu/riscv/iommu.c
> @@ -33,9 +33,10 @@
>   #define RISCV_IOMMU_DDTP_TIMEOUT	10000000
>   #define RISCV_IOMMU_IOTINVAL_TIMEOUT	90000000
> 
> -/* Number of entries per CMD/FLT queue, should be <= INT_MAX */
> +/* Number of entries per CMD/FLT/PRI queue, should be <= INT_MAX */
>   #define RISCV_IOMMU_DEF_CQ_COUNT	8192
>   #define RISCV_IOMMU_DEF_FQ_COUNT	4096
> +#define RISCV_IOMMU_DEF_PQ_COUNT	4096
> 
>   /* RISC-V IOMMU PPN <> PHYS address conversions, PHYS <=> PPN[53:10] */
>   #define phys_to_ppn(pa)  (((pa) >> 2) & (((1ULL << 44) - 1) << 10))
> @@ -565,6 +566,151 @@ static irqreturn_t riscv_iommu_fltq_process(int irq, void *data)
>   	return IRQ_HANDLED;
>   }
> 
> 
> +static struct device *riscv_iommu_find_dev(struct riscv_iommu_device *iommu,
> +					   unsigned int devid)
> +{
> +	struct pci_bus *bus;
> +	struct pci_dev *pdev;
> +
> +	bus = pci_find_bus(0, devid >> 8);
> +	if (!bus)
> +		return NULL;
> +
> +	pdev = pci_get_slot(bus, devid & 0xff);
> +	if (!pdev)
> +		return NULL;
> +
> +	return &pdev->dev;
> +}
> +
> +static void riscv_iommu_handle_pq(struct riscv_iommu_device *iommu,
> +				  struct riscv_iommu_pq_record *req)
> +{
> +	struct iopf_fault fault;
> +	struct device *dev;
> +	unsigned int devid;
> +	int ret;
> +
> +	devid = FIELD_GET(RISCV_IOMMU_PQ_HDR_DID, req->hdr);
> +	dev = riscv_iommu_find_dev(iommu, devid);
> +	if (!dev) {
> +		dev_warn_ratelimited(iommu->dev,
> +				     "page request for unknown devid 0x%x\n", devid);
> +		return;
> +	}
> +
> +	memset(&fault, 0, sizeof(fault));
> +	fault.fault.type = IOMMU_FAULT_PAGE_REQ;
> +	fault.fault.prm.addr = FIELD_GET(RISCV_IOMMU_PQ_PAYLOAD_ADDR, req->payload) << 12;
> +	fault.fault.prm.grpid = FIELD_GET(RISCV_IOMMU_PQ_PAYLOAD_PRGI, req->payload);
> +
> +	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_R)
> +		fault.fault.prm.perm |= IOMMU_FAULT_PERM_READ;
> +	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_W)
> +		fault.fault.prm.perm |= IOMMU_FAULT_PERM_WRITE;
> +	if (req->hdr & RISCV_IOMMU_PQ_HDR_EXEC)
> +		fault.fault.prm.perm |= IOMMU_FAULT_PERM_EXEC;
> +	if (req->hdr & RISCV_IOMMU_PQ_HDR_PRIV)
> +		fault.fault.prm.perm |= IOMMU_FAULT_PERM_PRIV;
> +
> +	if (req->hdr & RISCV_IOMMU_PQ_HDR_PV) {
> +		fault.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_PASID_VALID |
> +					 IOMMU_FAULT_PAGE_RESPONSE_NEEDS_PASID;
> +		fault.fault.prm.pasid = FIELD_GET(RISCV_IOMMU_PQ_HDR_PID, req->hdr);
> +	}
> +
> +	if (req->payload & RISCV_IOMMU_PQ_PAYLOAD_L)
> +		fault.fault.prm.flags |= IOMMU_FAULT_PAGE_REQUEST_LAST_PAGE;
> +
> +	/* Store DID in private_data for page_response to send ATS.PRGR */
> +	fault.fault.prm.private_data[0] = devid;
> +
> +	ret = iommu_report_device_fault(dev, &fault);
> +	if (ret) {
> +		dev_warn_ratelimited(iommu->dev,
> +				     "page request fault report failed: %d\n", ret);
> +	}
> +}
> +
> +/* Page request queue interrupt handler thread function */
> +static irqreturn_t riscv_iommu_priq_process(int irq, void *data)
> +{
> +	struct riscv_iommu_queue *queue = (struct riscv_iommu_queue *)data;
> +	struct riscv_iommu_device *iommu = queue->iommu;
> +	struct riscv_iommu_pq_record *requests;
> +	unsigned int ctrl, idx;
> +	int cnt, len;
> +
> +	requests = (struct riscv_iommu_pq_record *)queue->base;
> +
> +	/* Clear page request interrupt pending and process all records. */
> +	riscv_iommu_writel(iommu, RISCV_IOMMU_REG_IPSR, Q_IPSR(queue));
> +
> +	do {
> +		cnt = riscv_iommu_queue_consume(queue, &idx);
> +		for (len = 0; len < cnt; idx++, len++)
> +			riscv_iommu_handle_pq(iommu, &requests[Q_ITEM(queue, idx)]);
> +		riscv_iommu_queue_release(queue, cnt);
> +	} while (cnt > 0);
> +
> +	/* Clear MF/OF errors */
> +	ctrl = riscv_iommu_readl(iommu, queue->qcr);
> +	if (ctrl & (RISCV_IOMMU_PQCSR_PQMF | RISCV_IOMMU_PQCSR_PQOF)) {
> +		riscv_iommu_writel(iommu, queue->qcr, ctrl);
> +		dev_warn(iommu->dev,
> +			 "Queue #%u error; memory fault:%d overflow:%d\n",
> +			 queue->qid,
> +			 !!(ctrl & RISCV_IOMMU_PQCSR_PQMF),
> +			 !!(ctrl & RISCV_IOMMU_PQCSR_PQOF));
> +	}
> +
> +	return IRQ_HANDLED;
> +}
> +
> +/* Send ATS.PRGR page response through the command queue */
> +static void riscv_iommu_page_response(struct device *dev,
> +				      struct iopf_fault *evt,
> +				      struct iommu_page_response *msg)
> +{
> +	struct riscv_iommu_device *iommu = dev_to_iommu(dev);
> +	struct riscv_iommu_command cmd;
> +	unsigned int devid;
> +	u8 resp_code;
> +
> +	/* Recover DID from private_data stored during PQ processing */
> +	devid = evt->fault.prm.private_data[0];
> +
> +	switch (msg->code) {
> +	case IOMMU_PAGE_RESP_SUCCESS:
> +		resp_code = 0; /* Success */
> +		break;
> +	case IOMMU_PAGE_RESP_INVALID:
> +		resp_code = 1; /* Invalid Request */
> +		break;
> +	case IOMMU_PAGE_RESP_FAILURE:
> +	default:
> +		resp_code = 0xF; /* Response Failure */
> +		break;
> +	}
> +
> +	/* Build ATS.PRGR command */
> +	cmd.dword0 = FIELD_PREP(RISCV_IOMMU_CMD_OPCODE, RISCV_IOMMU_CMD_ATS_OPCODE) |
> +		     FIELD_PREP(RISCV_IOMMU_CMD_FUNC, RISCV_IOMMU_CMD_ATS_FUNC_PRGR) |
> +		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_RID, devid);
> +
> +	if (evt->fault.prm.flags & IOMMU_FAULT_PAGE_REQUEST_PASID_VALID)
> +		cmd.dword0 |= FIELD_PREP(RISCV_IOMMU_CMD_ATS_PID, evt->fault.prm.pasid) |
> +			      RISCV_IOMMU_CMD_ATS_PV;
> +
> +	cmd.dword1 = FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_PRG_INDEX, msg->grpid) |
> +		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_RESP_CODE, resp_code) |
> +		     FIELD_PREP(RISCV_IOMMU_CMD_ATS_PRGR_DST_ID, devid);
> +
> +	riscv_iommu_cmd_send(iommu, &cmd);
> +}
> +
>   /* Lookup and initialize device context info structure. */
>   static struct riscv_iommu_dc *riscv_iommu_get_dc(struct riscv_iommu_device *iommu,
>   						 unsigned int devid)
> @@ -1404,6 +1550,7 @@ static const struct iommu_ops riscv_iommu_ops = {
>   	.device_group = riscv_iommu_device_group,
>   	.probe_device = riscv_iommu_probe_device,
>   	.release_device	= riscv_iommu_release_device,
> +	.page_response = riscv_iommu_page_response,
>   };
> 
>   static int riscv_iommu_init_check(struct riscv_iommu_device *iommu)
> @@ -1466,6 +1613,8 @@ void riscv_iommu_remove(struct riscv_iommu_device *iommu)
>   	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
>   	riscv_iommu_queue_disable(&iommu->cmdq);
>   	riscv_iommu_queue_disable(&iommu->fltq);
> +	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)
> +		riscv_iommu_queue_disable(&iommu->priq);
>   }
> 
>   int riscv_iommu_init(struct riscv_iommu_device *iommu)
> @@ -1494,6 +1643,15 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
>   	if (rc)
>   		return rc;
> 
> +	/* Allocate page request queue if ATS is supported */
> +	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) {
> +		RISCV_IOMMU_QUEUE_INIT(&iommu->priq, PQ);
> +		rc = riscv_iommu_queue_alloc(iommu, &iommu->priq,
> +					     sizeof(struct riscv_iommu_pq_record));
> +		if (rc)
> +			return rc;
> +	}
> +
>   	rc = riscv_iommu_queue_enable(iommu, &iommu->cmdq, riscv_iommu_cmdq_process);
>   	if (rc)
>   		return rc;
> @@ -1502,6 +1660,15 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
>   	if (rc)
>   		goto err_queue_disable;
> 
> +	/* Enable page request queue if ATS is supported */
> +	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS) {
> +		rc = riscv_iommu_queue_enable(iommu, &iommu->priq,
> +					      riscv_iommu_priq_process);
> +		if (rc)
> +			goto err_queue_disable;
> +		dev_info(iommu->dev, "page request queue enabled\n");
> +	}
> +
>   	rc = riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_MAX);
>   	if (rc)
>   		goto err_queue_disable;
> @@ -1534,6 +1701,8 @@ int riscv_iommu_init(struct riscv_iommu_device *iommu)
>   err_iodir_off:
>   	riscv_iommu_iodir_set_mode(iommu, RISCV_IOMMU_DDTP_IOMMU_MODE_OFF);
>   err_queue_disable:
> +	if (iommu->caps & RISCV_IOMMU_CAPABILITIES_ATS)
> +		riscv_iommu_queue_disable(&iommu->priq);
>   	riscv_iommu_queue_disable(&iommu->fltq);
>   	riscv_iommu_queue_disable(&iommu->cmdq);
>   	return rc;
> diff --git a/drivers/iommu/riscv/iommu.h b/drivers/iommu/riscv/iommu.h
> index 46df79dd5495..5c5ab24539f2 100644
> --- a/drivers/iommu/riscv/iommu.h
> +++ b/drivers/iommu/riscv/iommu.h
> @@ -14,6 +14,8 @@
>   #include <linux/iommu.h>
>   #include <linux/types.h>
>   #include <linux/iopoll.h>
> +#include <linux/pci.h>
> +#include <linux/pci-ats.h>
> 
>   #include "iommu-bits.h"
> 
> @@ -55,6 +57,7 @@ struct riscv_iommu_device {
>   	/* hardware queues */
>   	struct riscv_iommu_queue cmdq;
>   	struct riscv_iommu_queue fltq;
> +	struct riscv_iommu_queue priq;
> 
>   	/* device directory */
>   	unsigned int ddt_mode;
> --
> 2.53.0
> 
> 
> _______________________________________________
> linux-riscv mailing list
> linux-riscv at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-riscv



From julianbraha at gmail.com  Wed Jun 17 09:17:36 2026
From: julianbraha at gmail.com (Julian Braha)
Date: Wed, 17 Jun 2026 17:17:36 +0100
Subject: [PATCH v9 3/3] riscv: clocksource: Add p8700-gcru driver
In-Reply-To: <20260616-riscv-time-mmio-v9-3-03af7bc8f2d8@htecgroup.com>
References: <20260616-riscv-time-mmio-v9-0-03af7bc8f2d8@htecgroup.com>
 <20260616-riscv-time-mmio-v9-3-03af7bc8f2d8@htecgroup.com>
Message-ID: <d515b780-84ff-4854-bd77-e98247d62172@gmail.com>

Hi Aleksa,

On 6/16/26 17:03, Aleksa Paunovic via B4 Relay wrote:

> +config P8700_TIMER
> +	bool "MIPS P8700 timer driver"
> +	depends on GENERIC_SCHED_CLOCK && RISCV && RISCV_SBI && 64BIT
> +	select CLKSRC_MMIO
> +	select TIMER_PROBE
> +	select TIMER_OF

You don't need to select TIMER_OF here, it's already enabled by
TIMER_PROBE. You could consider using a comment there, if you'd like.

- Julian Braha


From guoren at kernel.org  Wed Jun 17 09:24:12 2026
From: guoren at kernel.org (Guo Ren)
Date: Thu, 18 Jun 2026 00:24:12 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260616205147.6aa7df98@pumpkin>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org> <20260616113651.1048a19a@pumpkin>
 <CAJF2gTTh1zyAZkKt7AQNZptG_H=-8xSum6PVTyxEmw23pN6-9g@mail.gmail.com> <20260616205147.6aa7df98@pumpkin>
Message-ID: <CAJF2gTTCLKCnTcY=K9hsepRgKwDRXqg5eqJBPxBPqTp98zqFKw@mail.gmail.com>

On Wed, Jun 17, 2026 at 3:51?AM David Laight
<david.laight.linux at gmail.com> wrote:
>
> On Tue, 16 Jun 2026 23:47:05 +0800
> Guo Ren <guoren at kernel.org> wrote:
>
> > On Tue, Jun 16, 2026 at 6:36?PM David Laight
> > <david.laight.linux at gmail.com> wrote:
> > >
> > > On Mon, 15 Jun 2026 12:38:17 +0000
> > > Guo Ren <guoren at kernel.org> wrote:
> > >
> > > > Hi Zhanpeng Zhang,
> > > ..
> > > > 3. Only performance-monitoring counters require 64-bit IO access or the
> > > > high-low-high do-while retry strategy. For ordinary status and control
> > > > MMIO registers, a single read is sufficient.
> > >
> > > Actually this sequence should be enough for a counter:
> > >         hi = read_hi();
> > >         lo = read_lo();
> > >         if (hi != read_hi()) {
> > >                 // Pick a value that happened while doing the reads.
> > >                 hi++;
> > >                 lo = 0;
> > >         }
> > This is not a free optimization ? it does not preserve the same
> > semantics as an atomic 64-bit read. There are at least two correctness
> > issues:
> >
> > 1. Loss of precision: If hi changed during the read, setting lo = 0
> > discards the actual lo value. The correct approach is to re-read lo
> > after detecting the change, not fabricate a value.
> >
> > 2. Multiple overflows: This assumes at most one overflow occurs
> > between reads. If two overflows happen (e.g., due to interrupt
> > injection), hi++ will produce an incorrect result, silently corrupting
> > the counter value.
> >
> > Negligible benefit: hi changing between reads is an extremely rare
> > event. Optimizing away the retry loop for such a rare case provides no
> > meaningful performance gain. And if hi never stabilizes, that
> > indicates a hardware failure ? in which case hanging in the retry loop
> > is actually the more appropriate behavior, as it makes the failure
> > visible rather than silently producing garbage values.
> >
> > The high-low-high do-while retry strategy exists precisely to handle
> > these cases correctly. I don't think this proposed sequence is a valid
> > replacement.
> >
>
> The point is that if the value is an incrementing counter (of some form)
> then the value is stale by the time the reading sequence completes.
> So all the code can be assumed to do is return a value the counter had
> sometime between when the code started and when it finished.
> If hi changes then hi+1:0 must have happened while the code was running
> so it is a safe return value.
You're right ? (hi + 1):0 is enough for hi-lo-hi. Thank you for
sticking to your point; it helped me think more carefully and
understand the subtlety.

>
> It is likely that the reads are also much slower than memory reads.
> If hi changes relatively infrequently (compared to the number of reads)
> it may be worth saving the previously read value and avoiding the second
> read of hi if it is the same as the previous read hi and lo has got larger.


--
Best Regards
 Guo Ren


From rppt at kernel.org  Wed Jun 17 11:48:07 2026
From: rppt at kernel.org (Mike Rapoport)
Date: Wed, 17 Jun 2026 21:48:07 +0300
Subject: [PATCH v16 00/10] arm64/riscv: Add support for crashkernel CMA
 reservation
In-Reply-To: <20260608073459.3119290-1-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
Message-ID: <ajLr53EK6mJbng-7@kernel.org>

Hi Jinjie,

On Mon, Jun 08, 2026 at 03:34:49PM +0800, Jinjie Ruan wrote:
> The crash memory allocation, and the exclude of crashk_res, crashk_low_res
> and crashk_cma memory are almost identical across different architectures,
> This patch set handle them in crash core in a general way, which eliminate
> a lot of duplication code.
> 
> And add support for crashkernel CMA reservation for arm64 and riscv.
> 
> This patch set is rebased on v7.1-rc1.

Please rebase this set on v7.2-rc1 once that's out.

I'm going to queue it in the liveupdate tree then to expose to the wider
testing.

Meanwhile it would be great to chase riscv and x86 maintainers for acks :)

-- 
Sincerely yours,
Mike.


From mailhol at kernel.org  Wed Jun 17 13:56:00 2026
From: mailhol at kernel.org (Vincent Mailhol)
Date: Wed, 17 Jun 2026 22:56:00 +0200
Subject: [PATCH 00/19] init: discoverable root partitions, a.k.a. an
 omittable "root=" cmdline option
In-Reply-To: <20260617-irritation-rollen-wirst-7d636cbfec92@brauner>
References: <20260615-discoverable-root_partitions-v1-0-39c78fac42e2@kernel.org>
 <20260617-irritation-rollen-wirst-7d636cbfec92@brauner>
Message-ID: <01cc3ac9-c89e-491c-86ed-4c4c90809075@kernel.org>

On 17/06/2026 at 14:41, Christian Brauner wrote:
> On Mon, Jun 15, 2026 at 06:08:56PM +0200, Vincent Mailhol wrote:
>> DPS [1] defines GPT partition type UUIDs for OS partitions and
>> attributes that control whether such partitions should be
>> automatically discovered. The specification states that:
>>
>>   The OS can discover and mount the necessary file systems with a
>>   non-existent or incomplete /etc/fstab file and without the root=
>>   kernel command line option.
>>
>> DPS is already implemented in systemd-gpt-auto-generator [2], which,
>> when embedded in an initrd, indeed allows automatic detection of the
>> root filesystem through its partition type UUID.
>>
>> This series adds this discovery feature directly into the kernel so
>> that people who are not using systemd or not using an initrd can still
>> benefit from it. The implementation follows the same model as
>> systemd-gpt-auto-generator:
> 
> I happen to co-maintain the DPS. It is userspace policy and complex
> userspace policy at that and does not belong into the kernel.
> 
> This also implements a really tiny portion of the spec. It deals with a
> lot more complex concepts such as automatic partitioning during
> installation, verity, LUKS, containers. This is really not intended for
> the kernel at all. I mean, it's great that this spec is being used but I
> do not want this in the kernel just for the sake of auto-discovery.

The implementation of a tiny portion is voluntary. If I can draw a
parallel, it would be the same as saying that the root= cmdline option
is a tiny portion of what an fstab can do.

Yes it does not manage the LUKS, containers and so on, the same way it
is not possible to directly boot those things directly from the kernel.

So, I don't think this conflicts with the actual userland
implementations, the same way you can add root= to your command line and
still have an initrd next to it.

I did not intend to write this as a replacement but just as a complement
to fill the gap of kernel with no initrd.

> The DPS is completely generic and can be implemented by tooling other
> than systemd (util-linux implements it and so does refind iirc). I think
> not wanting to use or build alternative userspace tooling for this is a
> really weak argument for pushing this into the kernel.

Well, I might explain to you where I come from. Time to time, I mess up
my configuration. When this issue is in a userland config file (e.g. bad
fstab), the recovery is always easy.

But when I mess up the bootloader firmware configuration (e.g. grub,
u-boot, edk2), the fix is always painful. I have to fight with a shell
with which I am not familiar with to figure out what the correct
configuration is.

And an initrd would help but:

 - it is still one more file to look for pass as a parameter
 - on some machine I do not have one anyway

I think it would have been very neet to have a method to boot a kernel
with zero config (understand here: no cmdline, no initrd) and I find out
that DPS could achieve that if just a tiny part of it were implemented
in the kernel.

For example, in edk2, I would be able to just browse the disk from the
"Boot from file" menu and select a kernel. Currently it panics because
no configuration is attached. With DPS, we could have it boot linux from
that menu. All in a graphical interface, with just up/down arrows and
one enter keypress.

And this is my motivation. This non LUKS root read-only part of the DPS
is the only piece which makes sense for me in the kernel. Not that I
don't *want* to implement it in userland, but just that it doesn't
achieve what would be helpful to me (and I guess others).

I thought I wouldn't be the only one in the world to see value in that
this is why I posted it.


Yours sincerely,
Vincent Mailhol



From david.laight.linux at gmail.com  Wed Jun 17 14:54:16 2026
From: david.laight.linux at gmail.com (David Laight)
Date: Wed, 17 Jun 2026 22:54:16 +0100
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <CAJF2gTTCLKCnTcY=K9hsepRgKwDRXqg5eqJBPxBPqTp98zqFKw@mail.gmail.com>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
	<20260615123821.373248-1-guoren@kernel.org>
	<20260616113651.1048a19a@pumpkin>
	<CAJF2gTTh1zyAZkKt7AQNZptG_H=-8xSum6PVTyxEmw23pN6-9g@mail.gmail.com>
	<20260616205147.6aa7df98@pumpkin>
	<CAJF2gTTCLKCnTcY=K9hsepRgKwDRXqg5eqJBPxBPqTp98zqFKw@mail.gmail.com>
Message-ID: <20260617225416.0c5a79b0@pumpkin>

On Thu, 18 Jun 2026 00:24:12 +0800
Guo Ren <guoren at kernel.org> wrote:

> On Wed, Jun 17, 2026 at 3:51?AM David Laight
> <david.laight.linux at gmail.com> wrote:
> >
> > On Tue, 16 Jun 2026 23:47:05 +0800
> > Guo Ren <guoren at kernel.org> wrote:
> >  
> > > On Tue, Jun 16, 2026 at 6:36?PM David Laight
> > > <david.laight.linux at gmail.com> wrote:  
> > > >
> > > > On Mon, 15 Jun 2026 12:38:17 +0000
> > > > Guo Ren <guoren at kernel.org> wrote:
> > > >  
> > > > > Hi Zhanpeng Zhang,  
> > > > ..  
> > > > > 3. Only performance-monitoring counters require 64-bit IO access or the
> > > > > high-low-high do-while retry strategy. For ordinary status and control
> > > > > MMIO registers, a single read is sufficient.  
> > > >
> > > > Actually this sequence should be enough for a counter:
> > > >         hi = read_hi();
> > > >         lo = read_lo();
> > > >         if (hi != read_hi()) {
> > > >                 // Pick a value that happened while doing the reads.
> > > >                 hi++;
> > > >                 lo = 0;
> > > >         }  
> > > This is not a free optimization ? it does not preserve the same
> > > semantics as an atomic 64-bit read. There are at least two correctness
> > > issues:
> > >
> > > 1. Loss of precision: If hi changed during the read, setting lo = 0
> > > discards the actual lo value. The correct approach is to re-read lo
> > > after detecting the change, not fabricate a value.
> > >
> > > 2. Multiple overflows: This assumes at most one overflow occurs
> > > between reads. If two overflows happen (e.g., due to interrupt
> > > injection), hi++ will produce an incorrect result, silently corrupting
> > > the counter value.
> > >
> > > Negligible benefit: hi changing between reads is an extremely rare
> > > event. Optimizing away the retry loop for such a rare case provides no
> > > meaningful performance gain. And if hi never stabilizes, that
> > > indicates a hardware failure ? in which case hanging in the retry loop
> > > is actually the more appropriate behavior, as it makes the failure
> > > visible rather than silently producing garbage values.
> > >
> > > The high-low-high do-while retry strategy exists precisely to handle
> > > these cases correctly. I don't think this proposed sequence is a valid
> > > replacement.
> > >  
> >
> > The point is that if the value is an incrementing counter (of some form)
> > then the value is stale by the time the reading sequence completes.
> > So all the code can be assumed to do is return a value the counter had
> > sometime between when the code started and when it finished.
> > If hi changes then hi+1:0 must have happened while the code was running
> > so it is a safe return value.  
> You're right ? (hi + 1):0 is enough for hi-lo-hi. Thank you for
> sticking to your point; it helped me think more carefully and
> understand the subtlety.

Don't worry, I'll have written the loop in the past.
Probably best is read old_hi-lo-hi then if (hi != old_hi) lo = 0

	David

> 
> >
> > It is likely that the reads are also much slower than memory reads.
> > If hi changes relatively infrequently (compared to the number of reads)
> > it may be worth saving the previously read value and avoiding the second
> > read of hi if it is the same as the previous read hi and lo has got larger.  
> 
> 
> --
> Best Regards
>  Guo Ren



From pjw at kernel.org  Wed Jun 17 15:51:04 2026
From: pjw at kernel.org (Paul Walmsley)
Date: Wed, 17 Jun 2026 16:51:04 -0600 (MDT)
Subject: [GIT PULL] RISC-V updates for v7.2
Message-ID: <2ca9fd52-d4a1-5e7b-b9d9-9d759b92f8c1@kernel.org>

Linus,

Please pull the following RISC-V changes for v7.2-rc1.  These are
mostly fixes and cleanups.  Seems primarily due to more people using
RISC-V systems, rather than increased LLM usage; but, hard to be
certain.  In any case, I hope we'll be able to focus more on features
for the next merge window.

thanks,

- Paul


The following changes since commit 15b4155138505669d3d43d7692459ee8ea2a86e7:

  riscv: cfi: reject unknown flags in PR_SET_CFI (2026-06-06 20:17:05 -0600)

are available in the Git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/riscv/linux tags/riscv-for-linus-7.2-mw1

for you to fetch changes up to 319fafd9a3743b617b8547d81c41c99fb67857b1:

  riscv: traps_misaligned: Avoid redundant unaligned access speed probe (2026-06-08 10:47:22 -0600)

----------------------------------------------------------------
RISC-V updates for v7.2

- Prevent get_free_mem_region() from returning regions that are
  unmappable in certain circumstances by defining
  DIRECT_MAP_PHYSMEM_END for RISC-V

- Fix an early boot problem with kexec_file when the amount of
  installed physical memory installed on the system exceeds the direct
  map size, which is possible in certain RISC-V virtual memory modes

- Unconditionally sfence.vma in the new vmalloc area handling code in
  the page fault handler, since even the presence of Svvptc doesn't
  guarantee that the CPU won't immediately fault again after the
  exception handler completes and subsequently crash

- Fix ftrace_graph_ret_addr() to use the correct task pointer
  (aligning with what other architectures do)

- Fix the misaligned access performance checking code in cases when
  performance is specified on the kernel command line and when CPUs
  have been brought offline and back online

- Get rid of a bogus address offset in the non-frame-pointer version
  of walk_stackframe(), aligning it with the frame pointer-based code

- Fix a RISC-V kfence issue causing bogus use-after-free warnings

- Add ARCH_HAS_CC_CAN_LINK for RISC-V, which needs different compiler
  command line flags than other architectures

- Implement _THIS_IP_ using RISC-V-specific assembly, which seems to
  be less brittle (from a compiler point of view) than taking the
  address of a label

- Reduce kernel startup overhead by defining
  HAVE_BUILDTIME_MCOUNT_SORT, since arch/riscv meets all the
  requirements

- Patch the CFI vDSO during alternatives processing, not only the
  standard vDSO

- Fix a potential memory leak in the cacheinfo code

- Clean up kernel/setup.c:add_resource() to pass along the return
  value from insert_resource() and to improve the display of
  resource ranges

- Clean up our purgatory.[ch] by aligning our purgatory() prototype
  to what's in arch/x86, and by cleaning up verify_sha256_digest()

- Clean up cpu_is_stopped() to align its function a little more
  closely to its name

- Replace some unbounded string function usage in get_early_cmdline()
  and the ptdump code with strscpy()

- Replace sprintf() with sysfs_emit() in cpu_show_ghostwrite() for
  safer bounds checking

- Standardize how compiler output flags are specified in the RISC-V
  kselftests, aligning them with what other architectures do

- Use the Linux-generic cmp_int() macro in place of an open-coded
  "cmp_3way()" macro in kernel/module-sections.c

- Panic early in boot if IRQ handler stacks can't be allocated rather
  than pretending to continue normally

- Add support for Eswin SoCs in the RISC-V defconfig

- Remove some unnecessary conditionals in sbi_hsm_hart_{start,stop}()

- Clean up some Kconfig infelicities found by Kconfirm

- Replace an open-coded version of min() in the kexec_elf code with
  the standard min() function

----------------------------------------------------------------
Anirudh Srinivasan (1):
      riscv: defconfig: Enable Eswin SoCs

Chen Pei (1):
      riscv: ftrace: select HAVE_BUILDTIME_MCOUNT_SORT

Florian Schmaus (1):
      riscv: module: Use generic cmp_int() instead of custom cmp_3way()

Han Gao (2):
      riscv: kexec_file: Constrain segment placement to direct map
      riscv: also select ARCH_KEEP_MEMBLOCK if kexec is selected

Hui Wang (3):
      riscv: kexec_elf: Remove unused pr_fmt definition
      riscv: cpu_ops: Change return value type of cpu_is_stopped() to bool
      riscv: cpu_ops_sbi: No need to be bothered to check ret.error

Julian Braha (2):
      riscv: replace select with dependency for visible RELOCATABLE
      riscv: dead code cleanup in kconfig for RISCV_PROBE_VECTOR_UNALIGNED_ACCESS

Marco Elver (1):
      riscv: Implement _THIS_IP_ using inline asm

Nam Cao (2):
      riscv: misaligned: Fix fast_unaligned_access_speed_key init
      riscv: traps_misaligned: Avoid redundant unaligned access speed probe

Osama Abdelkader (1):
      riscv: panic if IRQ handler stacks cannot be allocated

Rui Qi (2):
      riscv: Fix ftrace_graph_ret_addr() to use the correct task pointer
      riscv: stacktrace: Remove bogus -0x4 offset in non-FP walk_stackframe

Thomas Wei?schuh (5):
      riscv: Implement ARCH_HAS_CC_CAN_LINK
      riscv: vdso: Always declare vdso_start symbols
      riscv: alternative: Use IS_ENABLED() over ifdeffery for apply_vdso_alternatives()
      riscv: alternative: Pass vDSO start as parameter to apply_vdso_alternatives()
      riscv: alternative: Also patch the CFI vDSO

Thorsten Blum (7):
      riscv/purgatory: return bool from verify_sha256_digest
      riscv/purgatory: add asm/purgatory.h
      riscv: ptdump: Replace unbounded sprintf() in dump_prot()
      riscv: pi: replace strlcat with strscpy in get_early_cmdline
      riscv: use sysfs_emit in cpu_show_ghostwrite
      riscv: propagate insert_resource result from add_resource
      riscv: kexec: use min to simplify riscv_kexec_elf_load

Vivian Wang (6):
      riscv: mm: Define DIRECT_MAP_PHYSMEM_END
      riscv: mm: Extract helper mark_new_valid_map()
      riscv: kfence: Call mark_new_valid_map() for kfence_unprotect()
      riscv: mm: Rename new_vmalloc into new_valid_map_cpus
      riscv: mm: Use the bitmap API for new_valid_map_cpus
      riscv: mm: Unconditionally sfence.vma for spurious fault

Zishun Yi (1):
      riscv: cacheinfo: Fix node reference leak in populate_cache_leaves

Zong Li (1):
      selftests/riscv: fix compiler output flag spacing in all Makefiles

 arch/riscv/Kconfig                               | 21 ++++++--
 arch/riscv/configs/defconfig                     |  1 +
 arch/riscv/include/asm/cacheflush.h              | 25 ++++-----
 arch/riscv/include/asm/cpu_ops.h                 |  2 +-
 arch/riscv/include/asm/kfence.h                  |  7 ++-
 arch/riscv/include/asm/linkage.h                 |  2 +
 arch/riscv/include/asm/pgtable.h                 | 10 ++++
 arch/riscv/include/asm/purgatory.h               | 11 ++++
 arch/riscv/include/asm/vdso.h                    | 10 ++--
 arch/riscv/kernel/alternative.c                  | 14 ++---
 arch/riscv/kernel/bugs.c                         | 12 ++---
 arch/riscv/kernel/cacheinfo.c                    |  2 +-
 arch/riscv/kernel/cpu-hotplug.c                  |  4 +-
 arch/riscv/kernel/cpu_ops_sbi.c                  | 22 ++++----
 arch/riscv/kernel/entry.S                        | 51 ++++++++++--------
 arch/riscv/kernel/irq.c                          | 22 +++++---
 arch/riscv/kernel/kexec_elf.c                    | 10 +---
 arch/riscv/kernel/machine_kexec_file.c           |  3 +-
 arch/riscv/kernel/module-sections.c              |  6 +--
 arch/riscv/kernel/pi/cmdline_early.c             | 16 +++---
 arch/riscv/kernel/setup.c                        | 11 ++--
 arch/riscv/kernel/stacktrace.c                   |  4 +-
 arch/riscv/kernel/traps_misaligned.c             |  4 +-
 arch/riscv/kernel/unaligned_access_speed.c       | 69 ++++++++----------------
 arch/riscv/mm/init.c                             |  2 +-
 arch/riscv/mm/ptdump.c                           | 13 ++---
 arch/riscv/purgatory/purgatory.c                 | 16 +++---
 tools/testing/selftests/riscv/abi/Makefile       |  2 +-
 tools/testing/selftests/riscv/cfi/Makefile       |  2 +-
 tools/testing/selftests/riscv/hwprobe/Makefile   |  6 +--
 tools/testing/selftests/riscv/mm/Makefile        |  2 +-
 tools/testing/selftests/riscv/sigreturn/Makefile |  2 +-
 tools/testing/selftests/riscv/vector/Makefile    | 12 ++---
 33 files changed, 205 insertions(+), 191 deletions(-)
create mode 100644 arch/riscv/include/asm/purgatory.h

vmlinux size differences in bytes (from 15b415513850):
  text    data    bss     dec     hex  filename                             
 +3913  +48816    -64  +52665   +cdb9  vmlinux.defconfig.gcc-15             
 -2056    +192     -8   -1872    -750  vmlinux.nosmp_defconfig.gcc-15       
 +4225  +30056    -64  +34217   +85a9  vmlinux.rv32_defconfig.gcc-15        
 -2340    +128     -8   -2220    -8ac  vmlinux.rv32_nosmp_defconfig.gcc-15  
   +19       .   -120    -101     -65  vmlinux.nommu_virt_defconfig.gcc-15  
 +4357  +47344    -64  +51637   +c9b5  vmlinux.defconfig.clang-20           
 +3856   -3252      .    +604    +25c  vmlinux.nosmp_defconfig.clang-20     
 +7613  +29256    -64  +36805   +8fc5  vmlinux.rv32_defconfig.clang-20      
 +7344   -4656    -64   +2624    +a40  vmlinux.rv32_nosmp_defconfig.clang-20
   -97   +4096    -64   +3935    +f5f  vmlinux.nommu_virt_defconfig.clang-20
 +3873  +52784    -64  +56593   +dd11  vmlinux.defconfig.gcc-14             
 -2472    +180     -8   -2300    -8fc  vmlinux.nosmp_defconfig.gcc-14       
 +4217  +29992    -64  +34145   +8561  vmlinux.rv32_defconfig.gcc-14        
 -2728    +116     -8   -2620    -a3c  vmlinux.rv32_nosmp_defconfig.gcc-14  
   +31       .   -120     -89     -59  vmlinux.nommu_virt_defconfig.gcc-14  
 +4437  +47408    -64  +51781   +ca45  vmlinux.defconfig.clang-19           
 +3908   -3308     -8    +592    +250  vmlinux.nosmp_defconfig.clang-19     
 +7677  +28680    -64  +36293   +8dc5  vmlinux.rv32_defconfig.clang-19      
 +7392   -4756    -16   +2620    +a3c  vmlinux.rv32_nosmp_defconfig.clang-19
  -113     -64    -56    -233     -e9  vmlinux.nommu_virt_defconfig.clang-19
 +3829  +48784    -64  +52549   +cd45  vmlinux.defconfig.gcc-13             
 -2836    +128     -8   -2716    -a9c  vmlinux.nosmp_defconfig.gcc-13       
 +4045  +30024    -64  +34005   +84d5  vmlinux.rv32_defconfig.gcc-13        
 -2952     +96     -8   -2864    -b30  vmlinux.rv32_nosmp_defconfig.gcc-13  
    -1       .   -120    -121     -79  vmlinux.nommu_virt_defconfig.gcc-13  
 +4481  +47408    -64  +51825   +ca71  vmlinux.defconfig.clang-18           
 +3812   -3564     -8    +240     +f0  vmlinux.nosmp_defconfig.clang-18     
 +7589  +28744    -64  +36269   +8dad  vmlinux.rv32_defconfig.clang-18      
 +7456   -4756    -16   +2684    +a7c  vmlinux.rv32_nosmp_defconfig.clang-18
  -133       .    -56    -189     -bd  vmlinux.nommu_virt_defconfig.clang-18
 +4453  +48848    -64  +53237   +cff5  vmlinux.defconfig.gcc-12             
 -2572    +256     -8   -2324    -914  vmlinux.nosmp_defconfig.gcc-12       
 +3533  +29992    -64  +33461   +82b5  vmlinux.rv32_defconfig.gcc-12        
 -3272    +128     -8   -3152    -c50  vmlinux.rv32_nosmp_defconfig.gcc-12  
   -13       .   -120    -133     -85  vmlinux.nommu_virt_defconfig.gcc-12  
 +4545  +47536    -64  +52017   +cb31  vmlinux.defconfig.clang-17           
 +3964   -3564     -8    +392    +188  vmlinux.nosmp_defconfig.clang-17     
 +7489  +28584    -64  +36009   +8ca9  vmlinux.rv32_defconfig.clang-17      
 +7528   -4748    -16   +2764    +acc  vmlinux.rv32_nosmp_defconfig.clang-17
  -101       .    -56    -157     -9d  vmlinux.nommu_virt_defconfig.clang-17
 +4205  +48704    -64  +52845   +ce6d  vmlinux.defconfig.gcc-11             
 -2660    +160     -8   -2508    -9cc  vmlinux.nosmp_defconfig.gcc-11       
 +3469  +29944    -64  +33349   +8245  vmlinux.rv32_defconfig.gcc-11        
 -2724     +72     -8   -2660    -a64  vmlinux.rv32_nosmp_defconfig.gcc-11  
    -9       .   -120    -129     -81  vmlinux.nommu_virt_defconfig.gcc-11  
   -76       .     -8     -84     -54  vmlinux.allnoconfig.gcc-14           
-78761    +608  +1800  -76353  -12a41  vmlinux.allmodconfig.gcc-14          
   -48    -160     -8    -216     -d8  vmlinux.allnoconfig.clang-19         
 +4179  -19204   -256  -15281   -3bb1  vmlinux.allmodconfig.clang-19        

From bp at alien8.de  Wed Jun 17 17:41:06 2026
From: bp at alien8.de (Borislav Petkov)
Date: Wed, 17 Jun 2026 17:41:06 -0700
Subject: [PATCH v16 05/10] x86: kexec_file: Use crash_prepare_headers()
 helper to simplify code
In-Reply-To: <20260608073459.3119290-6-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608073459.3119290-6-ruanjinjie@huawei.com>
Message-ID: <20260618004106.GCajM-oofpxU2jDsy0@fat_crate.local>

On Mon, Jun 08, 2026 at 03:34:54PM +0800, Jinjie Ruan wrote:

> Subject: Re: [PATCH v16 05/10] x86: kexec_file: Use crash_prepare_headers() helper to simplify code

Use proper subject prefix: "x86/crash: ..."

> Use the newly introduced crash_prepare_headers() function to replace
> the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
> memory in the crash core, which reduce code duplication.
> 
> Only the following three architecture functions need to be implemented:
> - arch_get_system_nr_ranges(). Call get_nr_ram_ranges_callback()
>   to pre-count the max number of memory ranges.
> 
> - arch_crash_populate_cmem(). Use prepare_elf64_ram_headers_callback()
>   to collect the memory ranges and fills them into cmem.
> 
> - arch_crash_exclude_ranges(). Exclude the low 1M for x86.
> 
> By the way, remove the unused "nr_mem_ranges" in

s/By the way/While at it/

> arch_crash_handle_hotplug_event().
> 
> Cc: Thomas Gleixner <tglx at kernel.org>
> Cc: Ingo Molnar <mingo at redhat.com>
> Cc: Borislav Petkov <bp at alien8.de>
> Cc: Dave Hansen <dave.hansen at linux.intel.com>
> Cc: Andrew Morton <akpm at linux-foundation.org>
> Cc: Vivek Goyal <vgoyal at redhat.com>
> Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
> Acked-by: Baoquan He <bhe at redhat.com>
> Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/x86/kernel/crash.c | 89 +++++------------------------------------
>  1 file changed, 11 insertions(+), 78 deletions(-)

With those nitpicks above addressed:

Acked-by: Borislav Petkov (AMD) <bp at alien8.de>

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette


From ruanjinjie at huawei.com  Wed Jun 17 18:45:17 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 18 Jun 2026 09:45:17 +0800
Subject: [PATCH v16 00/10] arm64/riscv: Add support for crashkernel CMA
 reservation
In-Reply-To: <ajLr53EK6mJbng-7@kernel.org>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <ajLr53EK6mJbng-7@kernel.org>
Message-ID: <6437c0e3-d5c5-44b1-9157-b30bae2a6335@huawei.com>



On 6/18/2026 2:48 AM, Mike Rapoport wrote:
> Hi Jinjie,
> 
> On Mon, Jun 08, 2026 at 03:34:49PM +0800, Jinjie Ruan wrote:
>> The crash memory allocation, and the exclude of crashk_res, crashk_low_res
>> and crashk_cma memory are almost identical across different architectures,
>> This patch set handle them in crash core in a general way, which eliminate
>> a lot of duplication code.
>>
>> And add support for crashkernel CMA reservation for arm64 and riscv.
>>
>> This patch set is rebased on v7.1-rc1.
> 
> Please rebase this set on v7.2-rc1 once that's out.
> 
> I'm going to queue it in the liveupdate tree then to expose to the wider
> testing.
> 
> Meanwhile it would be great to chase riscv and x86 maintainers for acks :)

Thanks! That sounds great.

I will rebase this patch set on v7.2-rc1 as soon as it is out and send v17.

In the meantime, I will CC and reach out to the RISC-V and x86
maintainers to request their reviews and Acks.

Best regards,
Jinjie

> 



From ruanjinjie at huawei.com  Wed Jun 17 18:54:52 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 18 Jun 2026 09:54:52 +0800
Subject: [PATCH v16 06/10] riscv: kexec_file: Use crash_prepare_headers()
 helper to simplify code
In-Reply-To: <20260608073459.3119290-7-ruanjinjie@huawei.com>
References: <20260608073459.3119290-1-ruanjinjie@huawei.com>
 <20260608073459.3119290-7-ruanjinjie@huawei.com>
Message-ID: <7d8492c5-fc17-4c94-bc88-e77d6c1a849d@huawei.com>



On 6/8/2026 3:34 PM, Jinjie Ruan wrote:
> Use the newly introduced crash_prepare_headers() function to replace
> the existing prepare_elf_headers(), allocate cmem and exclude crash kernel
> memory in the crash core, which reduce code duplication.
> 
> Only the following two architecture functions need to be implemented:
> - arch_get_system_nr_ranges(). Call get_nr_ram_ranges_callback()
>   to pre-counts the max number of memory ranges.
> 
> - arch_crash_populate_cmem(). Use prepare_elf64_ram_headers_callback()
>   to collects the memory ranges and fills them into cmem.

Hi Paul, Palmer, Albert, Alexandre and RISC-V maintainers,

Sorry for the interruption.

This patch set aims to clean up and refactor the crash memory allocation
and the exclusion logic of crashk_res, crashk_low_res, and crashk_cma.
Currently, these  routines are almost identical across different
architectures, leading to a lot of duplicated code.

This series consolidates the logic into the generic crash core, removing
redundant implementations from architecture-specific directories,
including arch/riscv.

There are no functional changes intended for RISC-V.

The patches will be queued in the liveupdate tree for wider testing.
Could you please take a look at the RISC-V side and consider providing
an Acked-by?

The patch series can be reviewed here:

https://lore.kernel.org/all/20260608073459.3119290-1-ruanjinjie at huawei.com/

Thank you very much for your time and review!

Best regards,
Jinjie

> 
> Cc: Paul Walmsley <pjw at kernel.org>
> Cc: Palmer Dabbelt <palmer at dabbelt.com>
> Cc: Albert Ou <aou at eecs.berkeley.edu>
> Cc: Alexandre Ghiti <alex at ghiti.fr>
> Cc: Guo Ren <guoren at kernel.org>
> Reviewed-by: Sourabh Jain <sourabhjain at linux.ibm.com>
> Acked-by: Baoquan He <bhe at redhat.com>
> Acked-by: Mike Rapoport (Microsoft) <rppt at kernel.org>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/riscv/kernel/machine_kexec_file.c | 47 +++++++-------------------
>  1 file changed, 12 insertions(+), 35 deletions(-)
> 
> diff --git a/arch/riscv/kernel/machine_kexec_file.c b/arch/riscv/kernel/machine_kexec_file.c
> index 3f7766057cac..439cbc50dfa6 100644
> --- a/arch/riscv/kernel/machine_kexec_file.c
> +++ b/arch/riscv/kernel/machine_kexec_file.c
> @@ -44,6 +44,15 @@ static int get_nr_ram_ranges_callback(struct resource *res, void *arg)
>  	return 0;
>  }
>  
> +unsigned int arch_get_system_nr_ranges(void)
> +{
> +	unsigned int nr_ranges = 2; /* For exclusion of crashkernel region */
> +
> +	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
> +
> +	return nr_ranges;
> +}
> +
>  static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
>  {
>  	struct crash_mem *cmem = arg;
> @@ -55,41 +64,9 @@ static int prepare_elf64_ram_headers_callback(struct resource *res, void *arg)
>  	return 0;
>  }
>  
> -static int prepare_elf_headers(void **addr, unsigned long *sz)
> +int arch_crash_populate_cmem(struct crash_mem *cmem)
>  {
> -	struct crash_mem *cmem;
> -	unsigned int nr_ranges;
> -	int ret;
> -
> -	nr_ranges = 2; /* For exclusion of crashkernel region */
> -	walk_system_ram_res(0, -1, &nr_ranges, get_nr_ram_ranges_callback);
> -
> -	cmem = kmalloc_flex(*cmem, ranges, nr_ranges);
> -	if (!cmem)
> -		return -ENOMEM;
> -
> -	cmem->max_nr_ranges = nr_ranges;
> -	cmem->nr_ranges = 0;
> -	ret = walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
> -	if (ret)
> -		goto out;
> -
> -	/* Exclude crashkernel region */
> -	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
> -	if (ret)
> -		goto out;
> -
> -	if (crashk_low_res.end) {
> -		ret = crash_exclude_mem_range(cmem, crashk_low_res.start, crashk_low_res.end);
> -		if (ret)
> -			goto out;
> -	}
> -
> -	ret = crash_prepare_elf64_headers(cmem, true, addr, sz);
> -
> -out:
> -	kfree(cmem);
> -	return ret;
> +	return walk_system_ram_res(0, -1, cmem, prepare_elf64_ram_headers_callback);
>  }
>  
>  static char *setup_kdump_cmdline(struct kimage *image, char *cmdline,
> @@ -281,7 +258,7 @@ int load_extra_segments(struct kimage *image, unsigned long kernel_start,
>  	if (image->type == KEXEC_TYPE_CRASH) {
>  		void *headers;
>  		unsigned long headers_sz;
> -		ret = prepare_elf_headers(&headers, &headers_sz);
> +		ret = crash_prepare_headers(true, &headers, &headers_sz, NULL);
>  		if (ret) {
>  			pr_err("Preparing elf core header failed\n");
>  			goto out;



From wangruikang at iscas.ac.cn  Wed Jun 17 20:20:07 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Thu, 18 Jun 2026 11:20:07 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260615123821.373248-1-guoren@kernel.org>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org>
Message-ID: <7c490aeb-a3d9-4fe9-81de-f9662577851d@iscas.ac.cn>

On 6/15/26 20:38, Guo Ren wrote:
> Hi Zhanpeng Zhang,
>
> I noticed you posted a similar fix recently. However, I had already
> submitted a similar solution back in September 2025 [1]. It would be
> great if you could review it. A few concerns with the current patch:
>
> 1. Using spin_lock_irqsave in such a small semantic structure is
> unnecessary. IRQ protection should be provided by the higher-level
> IOMMU driver interfaces. Many existing call sites already handle IRQ
> disabling, so adding it here feels redundant and adds avoidable
> overhead.
>
> 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
> problematic. According to the RISC-V IOMMU specification (Software
> Guidelines, ?Reading and writing IOMMU registers?):
>
>> Registers that are 64-bit wide may be accessed using either a 32-bit
>> or a 64-bit access.
> This clearly requires that any hardware supporting 64-bit MMIO access
> must also support 32-bit MMIO access. Therefore, the IOMMU driver should
> be built on a 32-bit access base for maximum hardware compatibility.

I agree that the driver should be build with 32-bit accesses to support
these hardware. However there's one minor thing that I want to propose
regarding this, for the sake of clarity:

RISC-V IOMMU implementations that do not support 64-bit accesses are not
fully compliant with the RISC-V IOMMU specification and should not use
the standard RISC-V identifiers, namely:

- Devicetree compatible riscv,iommu
- ACPI HID RSCV0004

This, in my opinion, is not only the right thing to do (not claiming to
be standard hardware without actually being standard hardware), but also
saves a lot of trouble for operating system developers (yes, there are
RISC-V operating systems other than Linux out there), since invalid IO
accesses usually manifest as mysterious access faults (that would
usually suggest an incorrect IOMMU address), or worse, system hangs.

I would appreciate if the hardware vendors shipping 32-bit-access-only
IOMMUs would consider this.

Vivian "dramforever" Wang



From guoren at kernel.org  Wed Jun 17 20:36:33 2026
From: guoren at kernel.org (Guo Ren)
Date: Thu, 18 Jun 2026 11:36:33 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260617225416.0c5a79b0@pumpkin>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org> <20260616113651.1048a19a@pumpkin>
 <CAJF2gTTh1zyAZkKt7AQNZptG_H=-8xSum6PVTyxEmw23pN6-9g@mail.gmail.com>
 <20260616205147.6aa7df98@pumpkin> <CAJF2gTTCLKCnTcY=K9hsepRgKwDRXqg5eqJBPxBPqTp98zqFKw@mail.gmail.com>
 <20260617225416.0c5a79b0@pumpkin>
Message-ID: <CAJF2gTTwjtAs997XC1A9FEH68pGMqiwoOd9wcBMs5j_E0gSvQQ@mail.gmail.com>

On Thu, Jun 18, 2026 at 5:54?AM David Laight
<david.laight.linux at gmail.com> wrote:
>
> On Thu, 18 Jun 2026 00:24:12 +0800
> Guo Ren <guoren at kernel.org> wrote:
>
> > On Wed, Jun 17, 2026 at 3:51?AM David Laight
> > <david.laight.linux at gmail.com> wrote:
> > >
> > > On Tue, 16 Jun 2026 23:47:05 +0800
> > > Guo Ren <guoren at kernel.org> wrote:
> > >
> > > > On Tue, Jun 16, 2026 at 6:36?PM David Laight
> > > > <david.laight.linux at gmail.com> wrote:
> > > > >
> > > > > On Mon, 15 Jun 2026 12:38:17 +0000
> > > > > Guo Ren <guoren at kernel.org> wrote:
> > > > >
> > > > > > Hi Zhanpeng Zhang,
> > > > > ..
> > > > > > 3. Only performance-monitoring counters require 64-bit IO access or the
> > > > > > high-low-high do-while retry strategy. For ordinary status and control
> > > > > > MMIO registers, a single read is sufficient.
> > > > >
> > > > > Actually this sequence should be enough for a counter:
> > > > >         hi = read_hi();
> > > > >         lo = read_lo();
> > > > >         if (hi != read_hi()) {
> > > > >                 // Pick a value that happened while doing the reads.
> > > > >                 hi++;
> > > > >                 lo = 0;
> > > > >         }
> > > > This is not a free optimization ? it does not preserve the same
> > > > semantics as an atomic 64-bit read. There are at least two correctness
> > > > issues:
> > > >
> > > > 1. Loss of precision: If hi changed during the read, setting lo = 0
> > > > discards the actual lo value. The correct approach is to re-read lo
> > > > after detecting the change, not fabricate a value.
> > > >
> > > > 2. Multiple overflows: This assumes at most one overflow occurs
> > > > between reads. If two overflows happen (e.g., due to interrupt
> > > > injection), hi++ will produce an incorrect result, silently corrupting
> > > > the counter value.
> > > >
> > > > Negligible benefit: hi changing between reads is an extremely rare
> > > > event. Optimizing away the retry loop for such a rare case provides no
> > > > meaningful performance gain. And if hi never stabilizes, that
> > > > indicates a hardware failure ? in which case hanging in the retry loop
> > > > is actually the more appropriate behavior, as it makes the failure
> > > > visible rather than silently producing garbage values.
> > > >
> > > > The high-low-high do-while retry strategy exists precisely to handle
> > > > these cases correctly. I don't think this proposed sequence is a valid
> > > > replacement.
> > > >
> > >
> > > The point is that if the value is an incrementing counter (of some form)
> > > then the value is stale by the time the reading sequence completes.
> > > So all the code can be assumed to do is return a value the counter had
> > > sometime between when the code started and when it finished.
> > > If hi changes then hi+1:0 must have happened while the code was running
> > > so it is a safe return value.
> > You're right ? (hi + 1):0 is enough for hi-lo-hi. Thank you for
> > sticking to your point; it helped me think more carefully and
> > understand the subtlety.
>
> Don't worry, I'll have written the loop in the past.
> Probably best is read old_hi-lo-hi then if (hi != old_hi) lo = 0
This is more conservative than (hi + 1):0.

-- 
Best Regards
 Guo Ren


From guoren at kernel.org  Wed Jun 17 20:45:14 2026
From: guoren at kernel.org (Guo Ren)
Date: Thu, 18 Jun 2026 11:45:14 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <7c490aeb-a3d9-4fe9-81de-f9662577851d@iscas.ac.cn>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org> <7c490aeb-a3d9-4fe9-81de-f9662577851d@iscas.ac.cn>
Message-ID: <CAJF2gTQ+-gpvUDtOh99aKP2-iDJy3MYOWti9k2Ntd0-J0MXqxQ@mail.gmail.com>

On Thu, Jun 18, 2026 at 11:20?AM Vivian Wang <wangruikang at iscas.ac.cn> wrote:
>
> On 6/15/26 20:38, Guo Ren wrote:
> > Hi Zhanpeng Zhang,
> >
> > I noticed you posted a similar fix recently. However, I had already
> > submitted a similar solution back in September 2025 [1]. It would be
> > great if you could review it. A few concerns with the current patch:
> >
> > 1. Using spin_lock_irqsave in such a small semantic structure is
> > unnecessary. IRQ protection should be provided by the higher-level
> > IOMMU driver interfaces. Many existing call sites already handle IRQ
> > disabling, so adding it here feels redundant and adds avoidable
> > overhead.
> >
> > 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
> > problematic. According to the RISC-V IOMMU specification (Software
> > Guidelines, ?Reading and writing IOMMU registers?):
> >
> >> Registers that are 64-bit wide may be accessed using either a 32-bit
> >> or a 64-bit access.
> > This clearly requires that any hardware supporting 64-bit MMIO access
> > must also support 32-bit MMIO access. Therefore, the IOMMU driver should
> > be built on a 32-bit access base for maximum hardware compatibility.
>
> I agree that the driver should be build with 32-bit accesses to support
> these hardware. However there's one minor thing that I want to propose
> regarding this, for the sake of clarity:
>
> RISC-V IOMMU implementations that do not support 64-bit accesses are not
> fully compliant with the RISC-V IOMMU specification and should not use
> the standard RISC-V identifiers, namely:
>
> - Devicetree compatible riscv,iommu
> - ACPI HID RSCV0004
>
> This, in my opinion, is not only the right thing to do (not claiming to
> be standard hardware without actually being standard hardware), but also
> saves a lot of trouble for operating system developers (yes, there are
> RISC-V operating systems other than Linux out there), since invalid IO
> accesses usually manifest as mysterious access faults (that would
> usually suggest an incorrect IOMMU address), or worse, system hangs.
>
> I would appreciate if the hardware vendors shipping 32-bit-access-only
> IOMMUs would consider this.
>
> Vivian "dramforever" Wang
>

32-bit MMIO access is explicitly supported by the RISC-V IOMMU
specification and is a valid choice (64-bit MMIO access is optional).
64-bit MMIO access is not "free" ? it consumes additional interconnect
hardware resources.

Could you elaborate on the concrete benefit of using 64-bit MMIO
access in this driver, for these non-PMU registers? A clear
justification would help evaluate whether the trade-off is worthwhile.


-- 
Best Regards
 Guo Ren


From daniel.almeida at collabora.com  Wed Jun 17 20:46:34 2026
From: daniel.almeida at collabora.com (Daniel Almeida)
Date: Thu, 18 Jun 2026 00:46:34 -0300
Subject: [PATCH v4 0/3] Clk improvements
Message-ID: <20260618-clk-type-state-v4-0-8be082786080@collabora.com>

This series contains a few improvements that simplifies clock handling for
drivers.

Patch 1 implements the same typestate pattern that has been used
successfully for Regulators. This is needed because otherwise drivers
will be responsible for unpreparing and disabling clocks themselves and
ultimately handling the reference counts on their own. This is
undesirable. The patch automatically encodes this information using the
type system so that no misuse can occur.

Patch 2 makes things more convenient by offering devres-managed APIs. This
lets drivers set clock parameters once and forget about lifetime
management.

Patch 3 converts clk.rs to the newer kernel-vertical style in order to make
future changes easier.

Alice Ryhl's "rust: clk: implement Send and Sync" series, which this used to
depend on, has since been merged, so this series now applies directly on
clk-next.

---
Changes in v4:
- Rebased onto clk-next. Alice Ryhl's "rust: clk: implement Send and Sync"
  series is now merged upstream, so it is no longer carried as a dependency.
- Fixed the build with CONFIG_CPUFREQ_DT_RUST=y. The generic DT cpufreq
  driver only has the (unbound) per-CPU device, so it cannot hand a
  &Device<Bound> to Policy::set_clk(). Added a pub(crate) Clk::get_unbound()
  for the few in-tree abstractions that operate on a device outside a bind
  scope; set_clk() now takes &Device and uses it. Clk::get()/get_optional()
  and the devm_* helpers still require &Device<Bound>.
- Added impl From<Error<State>> for kernel::error::Error, so the fallible
  state transitions can be used with `?` (and chained) instead of
  .map_err(|e| e.error).
- Added Clk::<Prepared>::with_enabled(), which runs a closure with the clock
  temporarily enabled, scoping the Enabled state without giving up the
  prepared clock.
- Documented how to change a clock's state at runtime via an enum, for
  drivers that enable/disable across resume/suspend.
- Link to v3: https://lore.kernel.org/r/20260107-clk-type-state-v3-0-77d3e3ee59c2 at collabora.com

Changes in v3:
- Rebased on top of 6.19-rc4
- Dropped patch 1 (from Alice), added her series as a dependency instead
- Fixed Tyr, PWM_TH1520 drivers
- Changed clk.rs imports to kernel-vertical style
- Added support get_optional shortcut for Prepared and Enabled (i.e.:
  Clk::<Enabled>::get_optional())
- Fixed misplaced #[inline] tag

Thanks, Danilo {
  - Moved the devres changes into its own patch
  - Require &Device<Bound> for all functions where a &Device is used
  - Account for con_in in SAFETY comments where applicable
  - Added backticks
}

- Link to v2: https://lore.kernel.org/r/20250910-clk-type-state-v2-0-1b97c11bb631 at collabora.com

Changes in v2:
- Added Alice's patch as patch 1, since it is a dependency.
- Added devm helpers (like we did for Regulator<T>)
- Fixed missing clk_put() call in Drop (Danilo)
- Fixed missing parenthesis and wrong docs (Viresh)
- Removed extra "dev" parameter from "shutdown" example (Danilo)
- Removed useless type annotation from example (Danilo)
- Link to v1: https://lore.kernel.org/rust-for-linux/20250729-clk-type-state-v1-1-896b53816f7b at collabora.com/#r

To: "Rafael J. Wysocki" <rafael at kernel.org>
To: Viresh Kumar <viresh.kumar at linaro.org>
To: Danilo Krummrich <dakr at kernel.org>
To: Alice Ryhl <aliceryhl at google.com>
To: Daniel Almeida <daniel.almeida at collabora.com>
To: David Airlie <airlied at gmail.com>
To: Simona Vetter <simona at ffwll.ch>
To: Drew Fustini <fustini at kernel.org>
To: Guo Ren <guoren at kernel.org>
To: Fu Wei <wefu at redhat.com>
To: Michal Wilczynski <m.wilczynski at samsung.com>
To: Uwe Kleine-K?nig <ukleinek at kernel.org>
To: Michael Turquette <mturquette at baylibre.com>
To: Stephen Boyd <sboyd at kernel.org>
To: Brian Masney <bmasney at redhat.com>
To: Miguel Ojeda <ojeda at kernel.org>
To: Boqun Feng <boqun at kernel.org>
To: Gary Guo <gary at garyguo.net>
To: Bj?rn Roy Baron <bjorn3_gh at protonmail.com>
To: Benno Lossin <lossin at kernel.org>
To: Andreas Hindborg <a.hindborg at kernel.org>
To: Trevor Gross <tmgross at umich.edu>
Cc: linux-pm at vger.kernel.org
Cc: linux-kernel at vger.kernel.org
Cc: dri-devel at lists.freedesktop.org
Cc: linux-riscv at lists.infradead.org
Cc: linux-pwm at vger.kernel.org
Cc: linux-clk at vger.kernel.org
Cc: rust-for-linux at vger.kernel.org
Cc: Boris Brezillon <boris.brezillon at collabora.com>

---
Daniel Almeida (3):
      rust: clk: use the type-state pattern
      rust: clk: add devres-managed clks
      rust: clk: use 'kernel vertical style' for imports

 drivers/cpufreq/rcpufreq_dt.rs |   2 +-
 drivers/gpu/drm/tyr/driver.rs  |  31 +--
 drivers/pwm/pwm_th1520.rs      |  17 +-
 rust/kernel/clk.rs             | 595 +++++++++++++++++++++++++++++++----------
 rust/kernel/cpufreq.rs         |   8 +-
 5 files changed, 477 insertions(+), 176 deletions(-)
---
base-commit: 8d03cc42a42b1a3f1535757f65bfb74a9753953f
change-id: 20250909-clk-type-state-c01aa7dd551d

Best regards,
--  
Daniel Almeida <daniel.almeida at collabora.com>



From daniel.almeida at collabora.com  Wed Jun 17 20:46:35 2026
From: daniel.almeida at collabora.com (Daniel Almeida)
Date: Thu, 18 Jun 2026 00:46:35 -0300
Subject: [PATCH v4 1/3] rust: clk: use the type-state pattern
In-Reply-To: <20260618-clk-type-state-v4-0-8be082786080@collabora.com>
References: <20260618-clk-type-state-v4-0-8be082786080@collabora.com>
Message-ID: <20260618-clk-type-state-v4-1-8be082786080@collabora.com>

The current Clk abstraction can still be improved on the following issues:

a) It only keeps track of a count to clk_get(), which means that users have
to manually call disable() and unprepare(), or a variation of those, like
disable_unprepare().

b) It allows repeated calls to prepare() or enable(), but it keeps no track
of how often these were called, i.e., it's currently legal to write the
following:

clk.prepare();
clk.prepare();
clk.enable();
clk.enable();

And nothing gets undone on drop().

c) It adds a OptionalClk type that is probably not needed. There is no
"struct optional_clk" in C and we should probably not add one.

d) It does not let a user express the state of the clk through the
type system. For example, there is currently no way to encode that a Clk is
enabled via the type system alone.

In light of the Regulator abstraction that was recently merged, switch this
abstraction to use the type-state pattern instead. It solves both a) and b)
by establishing a number of states and the valid ways to transition between
them. It also automatically undoes any call to clk_get(), clk_prepare() and
clk_enable() as applicable on drop(), so users do not have to do anything
special before Clk goes out of scope.

It solves c) by removing the OptionalClk type, which is now simply encoded
as a Clk whose inner pointer is NULL.

It solves d) by directly encoding the state of the Clk into the type, e.g.:
Clk<Enabled> is now known to be a Clk that is enabled.

The INVARIANTS section for Clk is expanded to highlight the relationship
between the states and the respective reference counts that are owned by
each of them.

The examples are expanded to highlight how a user can transition between
states, as well as highlight some of the shortcuts built into the API.

The current implementation is also more flexible, in the sense that it
allows for more states to be added in the future. This lets us implement
different strategies for handling clocks, including one that mimics the
current API, allowing for multiple calls to prepare() and enable().

The users (cpufreq.rs/ rcpufreq_dt.rs) were updated by this patch (and not
a separate one) to reflect the new changes. This is needed, because
otherwise this patch would break the build.

Link: https://crates.io/crates/sealed [1]
Signed-off-by: Daniel Almeida <daniel.almeida at collabora.com>
---
 drivers/cpufreq/rcpufreq_dt.rs |   2 +-
 drivers/gpu/drm/tyr/driver.rs  |  31 +--
 drivers/pwm/pwm_th1520.rs      |  17 +-
 rust/kernel/clk.rs             | 512 ++++++++++++++++++++++++++++++-----------
 rust/kernel/cpufreq.rs         |   8 +-
 5 files changed, 396 insertions(+), 174 deletions(-)

diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs
index f17bf64c22e2..9d2ec7df4bac 100644
--- a/drivers/cpufreq/rcpufreq_dt.rs
+++ b/drivers/cpufreq/rcpufreq_dt.rs
@@ -40,7 +40,7 @@ struct CPUFreqDTDevice {
     freq_table: opp::FreqTable,
     _mask: CpumaskVar,
     _token: Option<opp::ConfigToken>,
-    _clk: Clk,
+    _clk: Clk<kernel::clk::Unprepared>,
 }
 
 #[derive(Default)]
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index 279710b36a10..a2230aebfea2 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -3,7 +3,7 @@
 use kernel::{
     clk::{
         Clk,
-        OptionalClk, //
+        Enabled, //
     },
     device::{
         Bound,
@@ -49,7 +49,7 @@ pub(crate) struct TyrPlatformDriverData {
     _device: ARef<TyrDrmDevice>,
 }
 
-#[pin_data(PinnedDrop)]
+#[pin_data]
 pub(crate) struct TyrDrmDeviceData {
     pub(crate) pdev: ARef<platform::Device>,
 
@@ -97,13 +97,9 @@ fn probe(
         pdev: &platform::Device<Core>,
         _info: Option<&Self::IdInfo>,
     ) -> impl PinInit<Self, Error> {
-        let core_clk = Clk::get(pdev.as_ref(), Some(c"core"))?;
-        let stacks_clk = OptionalClk::get(pdev.as_ref(), Some(c"stacks"))?;
-        let coregroup_clk = OptionalClk::get(pdev.as_ref(), Some(c"coregroup"))?;
-
-        core_clk.prepare_enable()?;
-        stacks_clk.prepare_enable()?;
-        coregroup_clk.prepare_enable()?;
+        let core_clk = Clk::<Enabled>::get(pdev.as_ref(), Some(c"core"))?;
+        let stacks_clk = Clk::<Enabled>::get_optional(pdev.as_ref(), Some(c"stacks"))?;
+        let coregroup_clk = Clk::<Enabled>::get_optional(pdev.as_ref(), Some(c"coregroup"))?;
 
         let mali_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"mali")?;
         let sram_regulator = Regulator::<regulator::Enabled>::get(pdev.as_ref(), c"sram")?;
@@ -150,17 +146,6 @@ impl PinnedDrop for TyrPlatformDriverData {
     fn drop(self: Pin<&mut Self>) {}
 }
 
-#[pinned_drop]
-impl PinnedDrop for TyrDrmDeviceData {
-    fn drop(self: Pin<&mut Self>) {
-        // TODO: the type-state pattern for Clks will fix this.
-        let clks = self.clks.lock();
-        clks.core.disable_unprepare();
-        clks.stacks.disable_unprepare();
-        clks.coregroup.disable_unprepare();
-    }
-}
-
 // We need to retain the name "panthor" to achieve drop-in compatibility with
 // the C driver in the userspace stack.
 const INFO: drm::DriverInfo = drm::DriverInfo {
@@ -186,9 +171,9 @@ impl drm::Driver for TyrDrmDriver {
 
 #[pin_data]
 struct Clocks {
-    core: Clk,
-    stacks: OptionalClk,
-    coregroup: OptionalClk,
+    core: Clk<Enabled>,
+    stacks: Clk<Enabled>,
+    coregroup: Clk<Enabled>,
 }
 
 #[pin_data]
diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
index ddd44a5ce497..343a1178c5e7 100644
--- a/drivers/pwm/pwm_th1520.rs
+++ b/drivers/pwm/pwm_th1520.rs
@@ -22,7 +22,7 @@
 
 use core::ops::Deref;
 use kernel::{
-    clk::Clk,
+    clk::{Clk, Enabled},
     device::{Bound, Core, Device},
     devres,
     io::{
@@ -89,11 +89,11 @@ struct Th1520WfHw {
 }
 
 /// The driver's private data struct. It holds all necessary devres managed resources.
-#[pin_data(PinnedDrop)]
+#[pin_data]
 struct Th1520PwmDriverData {
     #[pin]
     iomem: devres::Devres<IoMem<TH1520_PWM_REG_SIZE>>,
-    clk: Clk,
+    clk: Clk<Enabled>,
 }
 
 impl pwm::PwmOps for Th1520PwmDriverData {
@@ -298,13 +298,6 @@ fn write_waveform(
     }
 }
 
-#[pinned_drop]
-impl PinnedDrop for Th1520PwmDriverData {
-    fn drop(self: Pin<&mut Self>) {
-        self.clk.disable_unprepare();
-    }
-}
-
 struct Th1520PwmPlatformDriver;
 
 kernel::of_device_table!(
@@ -325,9 +318,7 @@ fn probe(
         let dev = pdev.as_ref();
         let request = pdev.io_request_by_index(0).ok_or(ENODEV)?;
 
-        let clk = Clk::get(dev, None)?;
-
-        clk.prepare_enable()?;
+        let clk = Clk::<Enabled>::get(dev, None)?;
 
         // TODO: Get exclusive ownership of the clock to prevent rate changes.
         // The Rust equivalent of `clk_rate_exclusive_get()` is not yet available.
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index 7abbd0767d8c..a62e4c7e252e 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -80,17 +80,103 @@ fn from(freq: Hertz) -> Self {
 mod common_clk {
     use super::Hertz;
     use crate::{
-        device::Device,
+        device::{Bound, Device},
         error::{from_err_ptr, to_result, Result},
         prelude::*,
     };
 
-    use core::{ops::Deref, ptr};
+    use core::{marker::PhantomData, mem::ManuallyDrop, ptr};
+
+    mod private {
+        pub trait Sealed {}
+
+        impl Sealed for super::Unprepared {}
+        impl Sealed for super::Prepared {}
+        impl Sealed for super::Enabled {}
+    }
+
+    /// A trait representing the different states that a [`Clk`] can be in.
+    pub trait ClkState: private::Sealed {
+        /// Whether the clock should be disabled when dropped.
+        const DISABLE_ON_DROP: bool;
+
+        /// Whether the clock should be unprepared when dropped.
+        const UNPREPARE_ON_DROP: bool;
+    }
+
+    /// A state where the [`Clk`] is not prepared and not enabled.
+    pub struct Unprepared;
+
+    /// A state where the [`Clk`] is prepared but not enabled.
+    pub struct Prepared;
+
+    /// A state where the [`Clk`] is both prepared and enabled.
+    pub struct Enabled;
+
+    impl ClkState for Unprepared {
+        const DISABLE_ON_DROP: bool = false;
+        const UNPREPARE_ON_DROP: bool = false;
+    }
+
+    impl ClkState for Prepared {
+        const DISABLE_ON_DROP: bool = false;
+        const UNPREPARE_ON_DROP: bool = true;
+    }
+
+    impl ClkState for Enabled {
+        const DISABLE_ON_DROP: bool = true;
+        const UNPREPARE_ON_DROP: bool = true;
+    }
+
+    /// An error that can occur when trying to convert a [`Clk`] between states.
+    pub struct Error<State: ClkState> {
+        /// The error that occurred.
+        pub error: kernel::error::Error,
+
+        /// The [`Clk`] that caused the error, so that the operation may be
+        /// retried.
+        pub clk: Clk<State>,
+    }
+
+    impl<State: ClkState> From<Error<State>> for kernel::error::Error {
+        /// Discards the [`Clk`] and keeps only the error code.
+        ///
+        /// This makes the fallible state transitions usable with the `?`
+        /// operator when the caller does not need to retry the operation on the
+        /// original [`Clk`], e.g.:
+        ///
+        /// ```
+        /// use kernel::clk::{Clk, Enabled, Unprepared};
+        /// use kernel::device::{Bound, Device};
+        /// use kernel::error::Result;
+        ///
+        /// fn get_enabled(dev: &Device<Bound>) -> Result<Clk<Enabled>> {
+        ///     let clk = Clk::<Unprepared>::get(dev, Some(c"apb_clk"))?
+        ///         .prepare()?
+        ///         .enable()?;
+        ///     Ok(clk)
+        /// }
+        /// ```
+        #[inline]
+        fn from(err: Error<State>) -> Self {
+            err.error
+        }
+    }
 
     /// A reference-counted clock.
     ///
     /// Rust abstraction for the C [`struct clk`].
     ///
+    /// A [`Clk`] instance represents a clock that can be in one of several
+    /// states: [`Unprepared`], [`Prepared`], or [`Enabled`].
+    ///
+    /// No action needs to be taken when a [`Clk`] is dropped. The calls to
+    /// `clk_unprepare()` and `clk_disable()` will be placed as applicable.
+    ///
+    /// An optional [`Clk`] is treated just like a regular [`Clk`], but its
+    /// inner `struct clk` pointer is `NULL`. This interfaces correctly with the
+    /// C API and also exposes all the methods of a regular [`Clk`] to users.
+    ///
     /// # Invariants
     ///
     /// A [`Clk`] instance holds either a pointer to a valid [`struct clk`] created by the C
@@ -99,19 +185,37 @@ mod common_clk {
     /// Instances of this type are reference-counted. Calling [`Clk::get`] ensures that the
     /// allocation remains valid for the lifetime of the [`Clk`].
     ///
+    /// The [`Prepared`] state is associated with a single count of
+    /// `clk_prepare()`, and the [`Enabled`] state is associated with a single
+    /// count of `clk_enable()`, and the [`Prepared`] state is associated with a
+    /// single count of `clk_prepare()` and `clk_enable()`.
+    ///
+    /// All states are associated with a single count of `clk_get()`.
+    ///
     /// # Examples
     ///
     /// The following example demonstrates how to obtain and configure a clock for a device.
     ///
     /// ```
-    /// use kernel::clk::{Clk, Hertz};
-    /// use kernel::device::Device;
+    /// use kernel::clk::{Clk, Enabled, Hertz, Unprepared, Prepared};
+    /// use kernel::device::{Bound, Device};
     /// use kernel::error::Result;
     ///
-    /// fn configure_clk(dev: &Device) -> Result {
-    ///     let clk = Clk::get(dev, Some(c"apb_clk"))?;
+    /// fn configure_clk(dev: &Device<Bound>) -> Result {
+    ///     // The fastest way is to use a version of `Clk::get` for the desired
+    ///     // state, i.e.:
+    ///     let clk: Clk<Enabled> = Clk::<Enabled>::get(dev, Some(c"apb_clk"))?;
+    ///
+    ///     // Any other state is also possible, e.g.:
+    ///     let clk: Clk<Prepared> = Clk::<Prepared>::get(dev, Some(c"apb_clk"))?;
     ///
-    ///     clk.prepare_enable()?;
+    ///     // Later:
+    ///     //
+    ///     // `?` works directly thanks to `From<Error<State>>`; the failed
+    ///     // `Clk` is dropped on error. Match on the returned `Error<State>`
+    ///     // instead (its `clk` field is the original `Clk`) if you want to
+    ///     // retry the operation.
+    ///     let clk: Clk<Enabled> = clk.enable()?;
     ///
     ///     let expected_rate = Hertz::from_ghz(1);
     ///
@@ -119,111 +223,300 @@ mod common_clk {
     ///         clk.set_rate(expected_rate)?;
     ///     }
     ///
-    ///     clk.disable_unprepare();
+    ///     // Nothing is needed here. The drop implementation will undo any
+    ///     // operations as appropriate.
+    ///     Ok(())
+    /// }
+    ///
+    /// fn shutdown(clk: Clk<Enabled>) -> Result {
+    ///     // The states can be traversed "in the reverse order" as well:
+    ///     let clk: Clk<Prepared> = clk.disable()?;
+    ///
+    ///     // This is of type `Clk<Unprepared>`.
+    ///     let clk = clk.unprepare();
+    ///
     ///     Ok(())
     /// }
     /// ```
     ///
+    /// Drivers that need to change a clock's state at runtime (for example to
+    /// enable it on resume and disable it on suspend) can keep it in an enum
+    /// and move between the variants:
+    ///
+    /// ```
+    /// use kernel::clk::{Clk, Enabled, Prepared};
+    /// use kernel::error::Result;
+    ///
+    /// enum DeviceClk {
+    ///     Suspended(Clk<Prepared>),
+    ///     Resumed(Clk<Enabled>),
+    /// }
+    ///
+    /// impl DeviceClk {
+    ///     fn resume(self) -> Result<Self> {
+    ///         Ok(match self {
+    ///             DeviceClk::Suspended(clk) => DeviceClk::Resumed(clk.enable()?),
+    ///             resumed => resumed,
+    ///         })
+    ///     }
+    ///
+    ///     fn suspend(self) -> Result<Self> {
+    ///         Ok(match self {
+    ///             DeviceClk::Resumed(clk) => DeviceClk::Suspended(clk.disable()?),
+    ///             suspended => suspended,
+    ///         })
+    ///     }
+    /// }
+    /// ```
+    ///
     /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html
     #[repr(transparent)]
-    pub struct Clk(*mut bindings::clk);
+    pub struct Clk<T: ClkState> {
+        inner: *mut bindings::clk,
+        _phantom: core::marker::PhantomData<T>,
+    }
 
     // SAFETY: It is safe to call `clk_put` on another thread than where `clk_get` was called.
-    unsafe impl Send for Clk {}
+    unsafe impl<T: ClkState> Send for Clk<T> {}
 
     // SAFETY: It is safe to call any combination of the `&self` methods in parallel, as the
     // methods are synchronized internally.
-    unsafe impl Sync for Clk {}
+    unsafe impl<T: ClkState> Sync for Clk<T> {}
 
-    impl Clk {
-        /// Gets [`Clk`] corresponding to a [`Device`] and a connection id.
+    impl Clk<Unprepared> {
+        /// Gets [`Clk`] corresponding to a bound [`Device`] and a connection
+        /// id.
         ///
         /// Equivalent to the kernel's [`clk_get`] API.
         ///
         /// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get
-        pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {
+        #[inline]
+        pub fn get(dev: &Device<Bound>, name: Option<&CStr>) -> Result<Clk<Unprepared>> {
+            Self::get_unbound(dev, name)
+        }
+
+        /// Gets [`Clk`] corresponding to a [`Device`] and a connection id,
+        /// without requiring the device to be bound.
+        ///
+        /// This is sound because [`clk_get`] and [`clk_put`] do not depend on the
+        /// device being bound to a driver. It is `pub(crate)` because a driver
+        /// should obtain its clocks through a bound device (see [`Clk::get`]); it
+        /// is meant for the few in-tree abstractions that operate on a device
+        /// outside a bind scope, such as the generic DT cpufreq driver.
+        ///
+        /// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get
+        #[inline]
+        pub(crate) fn get_unbound(dev: &Device, name: Option<&CStr>) -> Result<Clk<Unprepared>> {
             let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
 
-            // SAFETY: It is safe to call [`clk_get`] for a valid device pointer.
-            //
+            // SAFETY: It is safe to call [`clk_get`] for a valid device pointer
+            // and any `con_id`, including NULL.
+            let inner = from_err_ptr(unsafe { bindings::clk_get(dev.as_raw(), con_id) })?;
+
             // INVARIANT: The reference-count is decremented when [`Clk`] goes out of scope.
-            Ok(Self(from_err_ptr(unsafe {
-                bindings::clk_get(dev.as_raw(), con_id)
-            })?))
+            Ok(Self {
+                inner,
+                _phantom: PhantomData,
+            })
         }
 
-        /// Obtain the raw [`struct clk`] pointer.
+        /// Behaves the same as [`Self::get`], except when there is no clock
+        /// producer. In this case, instead of returning [`ENOENT`], it returns
+        /// a dummy [`Clk`].
         #[inline]
-        pub fn as_raw(&self) -> *mut bindings::clk {
-            self.0
+        pub fn get_optional(dev: &Device<Bound>, name: Option<&CStr>) -> Result<Clk<Unprepared>> {
+            let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
+
+            // SAFETY: It is safe to call [`clk_get`] for a valid device pointer
+            // and any `con_id`, including NULL.
+            let inner = from_err_ptr(unsafe { bindings::clk_get_optional(dev.as_raw(), con_id) })?;
+
+            // INVARIANT: The reference-count is decremented when [`Clk`] goes out of scope.
+            Ok(Self {
+                inner,
+                _phantom: PhantomData,
+            })
         }
 
-        /// Enable the clock.
+        /// Attempts to convert the [`Clk`] to a [`Prepared`] state.
         ///
-        /// Equivalent to the kernel's [`clk_enable`] API.
+        /// Equivalent to the kernel's [`clk_prepare`] API.
         ///
-        /// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_enable
+        /// [`clk_prepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_prepare
         #[inline]
-        pub fn enable(&self) -> Result {
-            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
-            // [`clk_enable`].
-            to_result(unsafe { bindings::clk_enable(self.as_raw()) })
+        pub fn prepare(self) -> Result<Clk<Prepared>, Error<Unprepared>> {
+            // We will be transferring the ownership of our `clk_get()` count to
+            // `Clk<Prepared>`.
+            let clk = ManuallyDrop::new(self);
+
+            // SAFETY: By the type invariants, `self.0` is a valid argument for
+            // [`clk_prepare`].
+            to_result(unsafe { bindings::clk_prepare(clk.as_raw()) })
+                .map(|()| Clk {
+                    inner: clk.inner,
+                    _phantom: PhantomData,
+                })
+                .map_err(|error| Error {
+                    error,
+                    clk: ManuallyDrop::into_inner(clk),
+                })
         }
+    }
 
-        /// Disable the clock.
+    impl Clk<Prepared> {
+        /// Obtains a [`Clk`] from a bound [`Device`] and a connection id and
+        /// prepares it.
         ///
-        /// Equivalent to the kernel's [`clk_disable`] API.
+        /// Equivalent to calling [`Clk::get`], followed by [`Clk::prepare`],
+        #[inline]
+        pub fn get(dev: &Device<Bound>, name: Option<&CStr>) -> Result<Clk<Prepared>> {
+            Clk::<Unprepared>::get(dev, name)?
+                .prepare()
+                .map_err(|error| error.error)
+        }
+
+        /// Behaves the same as [`Self::get`], except when there is no clock
+        /// producer. In this case, instead of returning [`ENOENT`], it returns
+        /// a dummy [`Clk`].
+        #[inline]
+        pub fn get_optional(dev: &Device<Bound>, name: Option<&CStr>) -> Result<Clk<Prepared>> {
+            Clk::<Unprepared>::get_optional(dev, name)?
+                .prepare()
+                .map_err(|error| error.error)
+        }
+
+        /// Attempts to convert the [`Clk`] to an [`Unprepared`] state.
         ///
-        /// [`clk_disable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_disable
+        /// Equivalent to the kernel's [`clk_unprepare`] API.
         #[inline]
-        pub fn disable(&self) {
-            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
-            // [`clk_disable`].
-            unsafe { bindings::clk_disable(self.as_raw()) };
+        pub fn unprepare(self) -> Clk<Unprepared> {
+            // We will be transferring the ownership of our `clk_get()` count to
+            // `Clk<Unprepared>`.
+            let clk = ManuallyDrop::new(self);
+
+            // SAFETY: By the type invariants, `self.0` is a valid argument for
+            // [`clk_unprepare`].
+            unsafe { bindings::clk_unprepare(clk.as_raw()) }
+
+            Clk {
+                inner: clk.inner,
+                _phantom: PhantomData,
+            }
         }
 
-        /// Prepare the clock.
+        /// Attempts to convert the [`Clk`] to an [`Enabled`] state.
         ///
-        /// Equivalent to the kernel's [`clk_prepare`] API.
+        /// Equivalent to the kernel's [`clk_enable`] API.
         ///
-        /// [`clk_prepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_prepare
+        /// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_enable
         #[inline]
-        pub fn prepare(&self) -> Result {
-            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
-            // [`clk_prepare`].
-            to_result(unsafe { bindings::clk_prepare(self.as_raw()) })
+        pub fn enable(self) -> Result<Clk<Enabled>, Error<Prepared>> {
+            // We will be transferring the ownership of our `clk_get()` and
+            // `clk_prepare()` counts to `Clk<Enabled>`.
+            let clk = ManuallyDrop::new(self);
+
+            // SAFETY: By the type invariants, `self.0` is a valid argument for
+            // [`clk_enable`].
+            to_result(unsafe { bindings::clk_enable(clk.as_raw()) })
+                .map(|()| Clk {
+                    inner: clk.inner,
+                    _phantom: PhantomData,
+                })
+                .map_err(|error| Error {
+                    error,
+                    clk: ManuallyDrop::into_inner(clk),
+                })
         }
 
-        /// Unprepare the clock.
+        /// Runs `cb` with the clock temporarily enabled.
         ///
-        /// Equivalent to the kernel's [`clk_unprepare`] API.
+        /// The clock is enabled before `cb` runs and disabled again afterwards,
+        /// so the [`Enabled`] state is scoped to the closure and the [`Clk`]
+        /// remains [`Prepared`]. This is convenient for drivers that only need
+        /// the clock running for a short, well-defined section (e.g. while
+        /// touching registers) without giving up ownership of the prepared
+        /// clock or threading it through an intermediate state, e.g.:
+        ///
+        /// ```
+        /// use kernel::clk::{Clk, Enabled, Hertz, Prepared};
+        /// use kernel::error::Result;
         ///
-        /// [`clk_unprepare`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_unprepare
+        /// fn read_rate(clk: &Clk<Prepared>) -> Result<Hertz> {
+        ///     clk.with_enabled(|clk: &Clk<Enabled>| clk.rate())
+        /// }
+        /// ```
+        ///
+        /// Equivalent to a balanced [`clk_enable`]/[`clk_disable`] pair around
+        /// `cb`.
+        ///
+        /// [`clk_enable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_enable
+        /// [`clk_disable`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_disable
         #[inline]
-        pub fn unprepare(&self) {
-            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
-            // [`clk_unprepare`].
-            unsafe { bindings::clk_unprepare(self.as_raw()) };
+        pub fn with_enabled<R>(&self, cb: impl FnOnce(&Clk<Enabled>) -> R) -> Result<R> {
+            // SAFETY: By the type invariants, `self.as_raw()` is a valid argument for
+            // [`clk_enable`].
+            to_result(unsafe { bindings::clk_enable(self.as_raw()) })?;
+
+            // Borrow the same clock as `Clk<Enabled>` for the duration of `cb`.
+            // It must not be dropped, as that would run `clk_disable`/`clk_put`
+            // against counts owned by `self`; the matching `clk_disable` below
+            // balances the `clk_enable` above instead.
+            //
+            // INVARIANT: The clock is enabled for the lifetime of `enabled`.
+            let enabled = ManuallyDrop::new(Clk::<Enabled> {
+                inner: self.inner,
+                _phantom: PhantomData,
+            });
+
+            let ret = cb(&enabled);
+
+            // SAFETY: The `clk_enable` above succeeded, so this balances it.
+            // `cb` only had a shared reference, so the enable count is unchanged.
+            unsafe { bindings::clk_disable(self.as_raw()) };
+
+            Ok(ret)
         }
+    }
 
-        /// Prepare and enable the clock.
+    impl Clk<Enabled> {
+        /// Gets [`Clk`] corresponding to a bound [`Device`] and a connection id
+        /// and then prepares and enables it.
         ///
-        /// Equivalent to calling [`Clk::prepare`] followed by [`Clk::enable`].
+        /// Equivalent to calling [`Clk::get`], followed by [`Clk::prepare`],
+        /// followed by [`Clk::enable`].
         #[inline]
-        pub fn prepare_enable(&self) -> Result {
-            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
-            // [`clk_prepare_enable`].
-            to_result(unsafe { bindings::clk_prepare_enable(self.as_raw()) })
+        pub fn get(dev: &Device<Bound>, name: Option<&CStr>) -> Result<Clk<Enabled>> {
+            Clk::<Prepared>::get(dev, name)?
+                .enable()
+                .map_err(|error| error.error)
         }
 
-        /// Disable and unprepare the clock.
-        ///
-        /// Equivalent to calling [`Clk::disable`] followed by [`Clk::unprepare`].
+        /// Behaves the same as [`Self::get`], except when there is no clock
+        /// producer. In this case, instead of returning [`ENOENT`], it returns
+        /// a dummy [`Clk`].
         #[inline]
-        pub fn disable_unprepare(&self) {
-            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
-            // [`clk_disable_unprepare`].
-            unsafe { bindings::clk_disable_unprepare(self.as_raw()) };
+        pub fn get_optional(dev: &Device<Bound>, name: Option<&CStr>) -> Result<Clk<Enabled>> {
+            Clk::<Prepared>::get_optional(dev, name)?
+                .enable()
+                .map_err(|error| error.error)
+        }
+
+        /// Attempts to disable the [`Clk`] and convert it to the [`Prepared`]
+        /// state.
+        #[inline]
+        pub fn disable(self) -> Result<Clk<Prepared>, Error<Enabled>> {
+            // We will be transferring the ownership of our `clk_get()` and
+            // `clk_enable()` counts to `Clk<Prepared>`.
+            let clk = ManuallyDrop::new(self);
+
+            // SAFETY: By the type invariants, `self.0` is a valid argument for
+            // [`clk_disable`].
+            unsafe { bindings::clk_disable(clk.as_raw()) };
+
+            Ok(Clk {
+                inner: clk.inner,
+                _phantom: PhantomData,
+            })
         }
 
         /// Get clock's rate.
@@ -251,82 +544,31 @@ pub fn set_rate(&self, rate: Hertz) -> Result {
         }
     }
 
-    impl Drop for Clk {
-        fn drop(&mut self) {
-            // SAFETY: By the type invariants, self.as_raw() is a valid argument for [`clk_put`].
-            unsafe { bindings::clk_put(self.as_raw()) };
-        }
-    }
-
-    /// A reference-counted optional clock.
-    ///
-    /// A lightweight wrapper around an optional [`Clk`]. An [`OptionalClk`] represents a [`Clk`]
-    /// that a driver can function without but may improve performance or enable additional
-    /// features when available.
-    ///
-    /// # Invariants
-    ///
-    /// An [`OptionalClk`] instance encapsulates a [`Clk`] with either a valid [`struct clk`] or
-    /// `NULL` pointer.
-    ///
-    /// Instances of this type are reference-counted. Calling [`OptionalClk::get`] ensures that the
-    /// allocation remains valid for the lifetime of the [`OptionalClk`].
-    ///
-    /// # Examples
-    ///
-    /// The following example demonstrates how to obtain and configure an optional clock for a
-    /// device. The code functions correctly whether or not the clock is available.
-    ///
-    /// ```
-    /// use kernel::clk::{OptionalClk, Hertz};
-    /// use kernel::device::Device;
-    /// use kernel::error::Result;
-    ///
-    /// fn configure_clk(dev: &Device) -> Result {
-    ///     let clk = OptionalClk::get(dev, Some(c"apb_clk"))?;
-    ///
-    ///     clk.prepare_enable()?;
-    ///
-    ///     let expected_rate = Hertz::from_ghz(1);
-    ///
-    ///     if clk.rate() != expected_rate {
-    ///         clk.set_rate(expected_rate)?;
-    ///     }
-    ///
-    ///     clk.disable_unprepare();
-    ///     Ok(())
-    /// }
-    /// ```
-    ///
-    /// [`struct clk`]: https://docs.kernel.org/driver-api/clk.html
-    pub struct OptionalClk(Clk);
-
-    impl OptionalClk {
-        /// Gets [`OptionalClk`] corresponding to a [`Device`] and a connection id.
-        ///
-        /// Equivalent to the kernel's [`clk_get_optional`] API.
-        ///
-        /// [`clk_get_optional`]:
-        /// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional
-        pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {
-            let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
-
-            // SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer.
-            //
-            // INVARIANT: The reference-count is decremented when [`OptionalClk`] goes out of
-            // scope.
-            Ok(Self(Clk(from_err_ptr(unsafe {
-                bindings::clk_get_optional(dev.as_raw(), con_id)
-            })?)))
+    impl<T: ClkState> Clk<T> {
+        /// Obtain the raw [`struct clk`] pointer.
+        #[inline]
+        pub fn as_raw(&self) -> *mut bindings::clk {
+            self.inner
         }
     }
 
-    // Make [`OptionalClk`] behave like [`Clk`].
-    impl Deref for OptionalClk {
-        type Target = Clk;
+    impl<T: ClkState> Drop for Clk<T> {
+        fn drop(&mut self) {
+            if T::DISABLE_ON_DROP {
+                // SAFETY: By the type invariants, self.as_raw() is a valid argument for
+                // [`clk_disable`].
+                unsafe { bindings::clk_disable(self.as_raw()) };
+            }
+
+            if T::UNPREPARE_ON_DROP {
+                // SAFETY: By the type invariants, self.as_raw() is a valid argument for
+                // [`clk_unprepare`].
+                unsafe { bindings::clk_unprepare(self.as_raw()) };
+            }
 
-        fn deref(&self) -> &Clk {
-            &self.0
+            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
+            // [`clk_put`].
+            unsafe { bindings::clk_put(self.as_raw()) };
         }
     }
 }
diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
index d8d26870bea2..e837bb1010e0 100644
--- a/rust/kernel/cpufreq.rs
+++ b/rust/kernel/cpufreq.rs
@@ -553,8 +553,12 @@ pub fn cpus(&mut self) -> &mut cpumask::Cpumask {
     /// The caller must guarantee that the returned [`Clk`] is not dropped while it is getting used
     /// by the C code.
     #[cfg(CONFIG_COMMON_CLK)]
-    pub unsafe fn set_clk(&mut self, dev: &Device, name: Option<&CStr>) -> Result<Clk> {
-        let clk = Clk::get(dev, name)?;
+    pub unsafe fn set_clk(
+        &mut self,
+        dev: &Device,
+        name: Option<&CStr>,
+    ) -> Result<Clk<crate::clk::Unprepared>> {
+        let clk = Clk::<crate::clk::Unprepared>::get_unbound(dev, name)?;
         self.as_mut_ref().clk = clk.as_raw();
         Ok(clk)
     }

-- 
2.54.0



From daniel.almeida at collabora.com  Wed Jun 17 20:46:36 2026
From: daniel.almeida at collabora.com (Daniel Almeida)
Date: Thu, 18 Jun 2026 00:46:36 -0300
Subject: [PATCH v4 2/3] rust: clk: add devres-managed clks
In-Reply-To: <20260618-clk-type-state-v4-0-8be082786080@collabora.com>
References: <20260618-clk-type-state-v4-0-8be082786080@collabora.com>
Message-ID: <20260618-clk-type-state-v4-2-8be082786080@collabora.com>

The clk API allows fine-grained control, but some drivers might be
more interested in a "set and forget" API.

Expand the current API to support this. The clock will automatically be
disabled, unprepared and freed when the device is unbound from the bus
without further intervention by the driver.

Signed-off-by: Daniel Almeida <daniel.almeida at collabora.com>
---
 rust/kernel/clk.rs | 43 +++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 43 insertions(+)

diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index a62e4c7e252e..692ee88ca772 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -95,6 +95,49 @@ impl Sealed for super::Prepared {}
         impl Sealed for super::Enabled {}
     }
 
+    /// Obtains and enables a [`devres`]-managed [`Clk`] for a bound device.
+    ///
+    /// [`devres`]: crate::devres::Devres
+    pub fn devm_enable(dev: &Device<Bound>, name: Option<&CStr>) -> Result {
+        let name = name.map_or(ptr::null(), |n| n.as_char_ptr());
+
+        // SAFETY: It is safe to call [`devm_clk_get_enabled`] with a valid
+        // device pointer.
+        from_err_ptr(unsafe { bindings::devm_clk_get_enabled(dev.as_raw(), name) })?;
+        Ok(())
+    }
+
+    /// Obtains and enables a [`devres`]-managed [`Clk`] for a bound device.
+    ///
+    /// This does not print any error messages if the clock is not found.
+    ///
+    /// [`devres`]: crate::devres::Devres
+    pub fn devm_enable_optional(dev: &Device<Bound>, name: Option<&CStr>) -> Result {
+        let name = name.map_or(ptr::null(), |n| n.as_char_ptr());
+
+        // SAFETY: It is safe to call [`devm_clk_get_optional_enabled`] with a
+        // valid device pointer.
+        from_err_ptr(unsafe { bindings::devm_clk_get_optional_enabled(dev.as_raw(), name) })?;
+        Ok(())
+    }
+
+    /// Same as [`devm_enable_optional`], but also sets the rate.
+    pub fn devm_enable_optional_with_rate(
+        dev: &Device<Bound>,
+        name: Option<&CStr>,
+        rate: Hertz,
+    ) -> Result {
+        let name = name.map_or(ptr::null(), |n| n.as_char_ptr());
+
+        // SAFETY: It is safe to call
+        // [`devm_clk_get_optional_enabled_with_rate`] with a valid device
+        // pointer.
+        from_err_ptr(unsafe {
+            bindings::devm_clk_get_optional_enabled_with_rate(dev.as_raw(), name, rate.as_hz())
+        })?;
+        Ok(())
+    }
+
     /// A trait representing the different states that a [`Clk`] can be in.
     pub trait ClkState: private::Sealed {
         /// Whether the clock should be disabled when dropped.

-- 
2.54.0



From daniel.almeida at collabora.com  Wed Jun 17 20:46:37 2026
From: daniel.almeida at collabora.com (Daniel Almeida)
Date: Thu, 18 Jun 2026 00:46:37 -0300
Subject: [PATCH v4 3/3] rust: clk: use 'kernel vertical style' for imports
In-Reply-To: <20260618-clk-type-state-v4-0-8be082786080@collabora.com>
References: <20260618-clk-type-state-v4-0-8be082786080@collabora.com>
Message-ID: <20260618-clk-type-state-v4-3-8be082786080@collabora.com>

Convert all imports to use the new import style. This will make it easier
to land new changes in the future.

No change of functionality implied.

Link: https://docs.kernel.org/rust/coding-guidelines.html#imports
Signed-off-by: Daniel Almeida <daniel.almeida at collabora.com>
---
 rust/kernel/clk.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 46 insertions(+), 10 deletions(-)

diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index 692ee88ca772..1412a2f0aedf 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -80,12 +80,23 @@ fn from(freq: Hertz) -> Self {
 mod common_clk {
     use super::Hertz;
     use crate::{
-        device::{Bound, Device},
-        error::{from_err_ptr, to_result, Result},
-        prelude::*,
+        device::{
+            Bound,
+            Device, //
+        },
+        error::{
+            from_err_ptr,
+            to_result,
+            Result, //
+        },
+        prelude::*, //
     };
 
-    use core::{marker::PhantomData, mem::ManuallyDrop, ptr};
+    use core::{
+        marker::PhantomData,
+        mem::ManuallyDrop,
+        ptr, //
+    };
 
     mod private {
         pub trait Sealed {}
@@ -189,8 +200,15 @@ impl<State: ClkState> From<Error<State>> for kernel::error::Error {
         /// original [`Clk`], e.g.:
         ///
         /// ```
-        /// use kernel::clk::{Clk, Enabled, Unprepared};
-        /// use kernel::device::{Bound, Device};
+        /// use kernel::clk::{
+        ///     Clk,
+        ///     Enabled,
+        ///     Unprepared, //
+        /// };
+        /// use kernel::device::{
+        ///     Bound,
+        ///     Device, //
+        /// };
         /// use kernel::error::Result;
         ///
         /// fn get_enabled(dev: &Device<Bound>) -> Result<Clk<Enabled>> {
@@ -240,8 +258,17 @@ fn from(err: Error<State>) -> Self {
     /// The following example demonstrates how to obtain and configure a clock for a device.
     ///
     /// ```
-    /// use kernel::clk::{Clk, Enabled, Hertz, Unprepared, Prepared};
-    /// use kernel::device::{Bound, Device};
+    /// use kernel::clk::{
+    ///     Clk,
+    ///     Enabled,
+    ///     Hertz,
+    ///     Prepared,
+    ///     Unprepared, //
+    /// };
+    /// use kernel::device::{
+    ///     Bound,
+    ///     Device, //
+    /// };
     /// use kernel::error::Result;
     ///
     /// fn configure_clk(dev: &Device<Bound>) -> Result {
@@ -287,7 +314,11 @@ fn from(err: Error<State>) -> Self {
     /// and move between the variants:
     ///
     /// ```
-    /// use kernel::clk::{Clk, Enabled, Prepared};
+    /// use kernel::clk::{
+    ///     Clk,
+    ///     Enabled,
+    ///     Prepared, //
+    /// };
     /// use kernel::error::Result;
     ///
     /// enum DeviceClk {
@@ -481,7 +512,12 @@ pub fn enable(self) -> Result<Clk<Enabled>, Error<Prepared>> {
         /// clock or threading it through an intermediate state, e.g.:
         ///
         /// ```
-        /// use kernel::clk::{Clk, Enabled, Hertz, Prepared};
+        /// use kernel::clk::{
+        ///     Clk,
+        ///     Enabled,
+        ///     Hertz,
+        ///     Prepared, //
+        /// };
         /// use kernel::error::Result;
         ///
         /// fn read_rate(clk: &Clk<Prepared>) -> Result<Hertz> {

-- 
2.54.0



From inochiama at gmail.com  Wed Jun 17 23:41:43 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Thu, 18 Jun 2026 14:41:43 +0800
Subject: [PATCH net] net: stmmac: dwmac-spacemit: Fix wrong ctrl register definition
Message-ID: <20260618064143.1102179-1-inochiama@gmail.com>

There register layout of the phy ctrl register has something wrong,
fix it to match the right layout

Fixes: 30f0ba420ed3 ("net: stmmac: Add glue layer for Spacemit K3 SoC")
Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
---
 .../net/ethernet/stmicro/stmmac/dwmac-spacemit.c    | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
index 223754cc5c79..6feffaa3ef3a 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
@@ -18,10 +18,12 @@
 #include "stmmac_platform.h"
 
 /* ctrl register bits */
-#define CTRL_PHY_INTF_RGMII		BIT(3)
-#define CTRL_PHY_INTF_MII		BIT(4)
-#define CTRL_WAKE_IRQ_EN		BIT(9)
-#define CTRL_PHY_IRQ_EN			BIT(12)
+#define CTRL_PHY_INTF_MODE		GENMASK(4, 3)
+#define CTRL_PHY_INTF_RMII		FIELD_PREP(CTRL_PHY_INTF_MODE, 0)
+#define CTRL_PHY_INTF_RGMII		FIELD_PREP(CTRL_PHY_INTF_MODE, 1)
+#define CTRL_PHY_INTF_MII		FIELD_PREP(CTRL_PHY_INTF_MODE, 3)
+#define CTRL_PHY_IRQ_EN			BIT(9)
+#define CTRL_WAKE_IRQ_EN		BIT(12)
 
 /* dline register bits */
 #define RGMII_RX_DLINE_EN		BIT(0)
@@ -118,7 +120,7 @@ static void spacemit_get_interfaces(struct stmmac_priv *priv, void *bsp_priv,
 
 static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel)
 {
-	unsigned int mask = CTRL_PHY_INTF_MII | CTRL_PHY_INTF_RGMII;
+	unsigned int mask = CTRL_PHY_INTF_MODE;
 	struct spacmit_dwmac *dwmac = bsp_priv;
 	unsigned int val = 0;
 
@@ -128,6 +130,7 @@ static int spacemit_set_phy_intf_sel(void *bsp_priv, u8 phy_intf_sel)
 		break;
 
 	case PHY_INTF_SEL_RMII:
+		val = CTRL_PHY_INTF_RMII;
 		break;
 
 	case PHY_INTF_SEL_RGMII:
-- 
2.54.0



From cuiyunhui at bytedance.com  Wed Jun 17 23:44:03 2026
From: cuiyunhui at bytedance.com (Yunhui Cui)
Date: Thu, 18 Jun 2026 14:44:03 +0800
Subject: [PATCH v4 0/3] riscv: support effective hardware PTE A/D updates
Message-ID: <20260618064406.14508-1-cuiyunhui@bytedance.com>

This series makes RISC-V track hardware PTE A/D updating by the
effective runtime state instead of treating Svadu discovery alone as
enough.

When both Svade and Svadu are present, Svadu is disabled at boot and
must be enabled through SBI FWFT.  The series enables FWFT PTE A/D
hardware updating on all currently online CPUs before enabling the
global static key, and enables it for later hotplug CPUs early in
smp_callin(), before they are marked online.  If FWFT setup fails, the
kernel falls back to software-managed A/D updates.

It also makes live PTE access/permission updates use cmpxchg-based
merges so that software updates do not lose concurrently
hardware-updated accessed, dirty, or soft-dirty state.

Changes since v3:
- Keep the only-Svadu binding contract as always enabled, and only
  describe the Svade+Svadu boot state as disabled instead of turned-off.
- Detect the need for FWFT from per-CPU Svade state instead of the global
  ISA intersection, so asymmetric Svade/Svadu systems do not skip FWFT.
- Document the secondary-hart FWFT bringup state flow in the commit log.

Yunhui Cui (3):
  dt-bindings: riscv: describe Svadu as disabled at boot
  riscv: track effective hardware PTE A/D updating
  riscv: preserve A/D and soft-dirty state across PTE updates

 .../devicetree/bindings/riscv/extensions.yaml |   2 +-
 arch/riscv/include/asm/cpufeature.h           |   8 ++
 arch/riscv/include/asm/pgtable.h              |  27 +++--
 arch/riscv/kernel/cpufeature.c                | 101 ++++++++++++++++--
 arch/riscv/kernel/smpboot.c                   |   4 +
 arch/riscv/mm/pgtable.c                       |  68 ++++++++++--
 6 files changed, 185 insertions(+), 25 deletions(-)

-- 
2.39.5


From cuiyunhui at bytedance.com  Wed Jun 17 23:44:04 2026
From: cuiyunhui at bytedance.com (Yunhui Cui)
Date: Thu, 18 Jun 2026 14:44:04 +0800
Subject: [PATCH v4 1/3] dt-bindings: riscv: describe Svadu as disabled at boot
In-Reply-To: <20260618064406.14508-1-cuiyunhui@bytedance.com>
References: <20260618064406.14508-1-cuiyunhui@bytedance.com>
Message-ID: <20260618064406.14508-2-cuiyunhui@bytedance.com>

When both Svade and Svadu are advertised, Svadu is not active at boot and
must be enabled through SBI FWFT before supervisor software can rely on
hardware PTE A/D updates.

Use "disabled" instead of "turned-off" to describe that boot-time state.
This matches the FWFT terminology more closely and avoids the informal
"turned-off" wording without changing the binding semantics.

Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
---
 Documentation/devicetree/bindings/riscv/extensions.yaml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/Documentation/devicetree/bindings/riscv/extensions.yaml b/Documentation/devicetree/bindings/riscv/extensions.yaml
index 2b0a8a93bb214..f1e6b0d79486b 100644
--- a/Documentation/devicetree/bindings/riscv/extensions.yaml
+++ b/Documentation/devicetree/bindings/riscv/extensions.yaml
@@ -297,7 +297,7 @@ properties:
             3) Only Svadu present in DT => Supervisor must assume Svadu to be
                always enabled.
             4) Both Svade and Svadu present in DT => Supervisor must assume
-               Svadu turned-off at boot time. To use Svadu, supervisor must
+               Svadu is disabled at boot time. To use Svadu, supervisor must
                explicitly enable it using the SBI FWFT extension.
 
         - const: svadu
-- 
2.39.5



From cuiyunhui at bytedance.com  Wed Jun 17 23:44:05 2026
From: cuiyunhui at bytedance.com (Yunhui Cui)
Date: Thu, 18 Jun 2026 14:44:05 +0800
Subject: [PATCH v4 2/3] riscv: track effective hardware PTE A/D updating
In-Reply-To: <20260618064406.14508-1-cuiyunhui@bytedance.com>
References: <20260618064406.14508-1-cuiyunhui@bytedance.com>
Message-ID: <20260618064406.14508-3-cuiyunhui@bytedance.com>

Svadu being present in the ISA does not always mean that hardware PTE A/D
updating is active. When Svade and Svadu are both advertised, Svadu starts
disabled and must be enabled through SBI FWFT before the kernel can rely on
hardware A/D updates.

Track that effective runtime state with a static key. During init, enable
FWFT for all online harts before setting the key; if that fails, leave the
system in software-managed A/D mode. Secondary harts must match the global
A/D update mode before they are marked online.

The full state flow is:

                boot init
                    |
                    v
          do all CPUs have Svadu?
                    |
             +------+------+
             |             |
            no            yes
             |             |
             v             v
      hw_ad key = false   does any CPU have Svade?
      requires_fwft = false       |
             |              +-----+-----+
             |              |           |
             |             no          yes
             |              |           |
             |              v           v
             |       hw_ad key = true   requires_fwft = true
             |       requires_fwft = false       |
             |                                v
             |                         FWFT on online CPUs
             |                                |
             |                         +------+------+
             |                         |             |
             |                      success       failure
             |                         |             |
             |                         v             v
             |                hw_ad key = true   requires_fwft = false
             |                requires_fwft = true hw_ad key = false
             |                                  fallback to software A/D
             |
             +--------------+-----------+
                            |
                            v
                       hotplug CPU
                            |
                            v
          if (!hw_ad_key || !requires_fwft)
                    |
             +------+------+
             |             |
           true          false
             |             |
             v             v
          return 0    enable local FWFT
             |             |
             |       +-----+-----+
             |       |           |
             |    success     failure
             |       |           |
             v       v           v
          continue  continue  return error
             |       |           |
             v       v           v
       set_cpu_online()     do not set CPU online
             |                   |
             v                   v
          CPU online        CPU bringup fails

Thus, an online CPU never runs with an A/D update mode different from the
global kernel state.

Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
---
 arch/riscv/include/asm/cpufeature.h |   8 +++
 arch/riscv/kernel/cpufeature.c      | 101 ++++++++++++++++++++++++++--
 arch/riscv/kernel/smpboot.c         |   4 ++
 3 files changed, 107 insertions(+), 6 deletions(-)

diff --git a/arch/riscv/include/asm/cpufeature.h b/arch/riscv/include/asm/cpufeature.h
index 739fcc84bf7b2..ba3d74f6006a6 100644
--- a/arch/riscv/include/asm/cpufeature.h
+++ b/arch/riscv/include/asm/cpufeature.h
@@ -128,6 +128,14 @@ struct riscv_isa_ext_data {
 extern const struct riscv_isa_ext_data riscv_isa_ext[];
 extern const size_t riscv_isa_ext_count;
 extern bool riscv_isa_fallback;
+DECLARE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
+
+static __always_inline bool riscv_has_hw_pte_ad_updating(void)
+{
+	return static_branch_unlikely(&riscv_hw_pte_ad_updating);
+}
+
+int riscv_enable_hw_pte_ad_updating(void);
 
 unsigned long riscv_isa_extension_base(const unsigned long *isa_bitmap);
 static __always_inline bool riscv_cpu_has_extension_likely(int cpu, const unsigned long ext)
diff --git a/arch/riscv/kernel/cpufeature.c b/arch/riscv/kernel/cpufeature.c
index f46aa5602d74d..c0ac7ab39d4e0 100644
--- a/arch/riscv/kernel/cpufeature.c
+++ b/arch/riscv/kernel/cpufeature.c
@@ -15,6 +15,7 @@
 #include <linux/memory.h>
 #include <linux/module.h>
 #include <linux/of.h>
+#include <linux/smp.h>
 #include <asm/acpi.h>
 #include <asm/alternative.h>
 #include <asm/bugs.h>
@@ -35,6 +36,9 @@
 static bool any_cpu_has_zicboz;
 static bool any_cpu_has_zicbop;
 static bool any_cpu_has_zicbom;
+DEFINE_STATIC_KEY_FALSE(riscv_hw_pte_ad_updating);
+EXPORT_SYMBOL_GPL(riscv_hw_pte_ad_updating);
+static bool riscv_hw_pte_ad_updating_requires_fwft __read_mostly;
 
 unsigned long elf_hwcap __read_mostly;
 
@@ -287,15 +291,100 @@ static int riscv_ext_zvfbfwma_validate(const struct riscv_isa_ext_data *data,
 	return -EPROBE_DEFER;
 }
 
-static int riscv_ext_svadu_validate(const struct riscv_isa_ext_data *data,
-				    const unsigned long *isa_bitmap)
+static void riscv_set_hw_pte_ad_updating(void)
+{
+	static_branch_enable(&riscv_hw_pte_ad_updating);
+}
+
+static int riscv_enable_local_hw_pte_ad_updating(void)
 {
-	/* SVADE has already been detected, use SVADE only */
-	if (__riscv_isa_extension_available(isa_bitmap, RISCV_ISA_EXT_SVADE))
-		return -EOPNOTSUPP;
+	return sbi_fwft_set(SBI_FWFT_PTE_AD_HW_UPDATING, 1, 0);
+}
+
+static int riscv_set_online_hw_pte_ad_updating(bool enable)
+{
+	return sbi_fwft_set_online_cpus(SBI_FWFT_PTE_AD_HW_UPDATING,
+					   enable, 0);
+}
+
+static bool __init riscv_any_cpu_has_svade(void)
+{
+	unsigned int cpu;
 
+	for_each_possible_cpu(cpu) {
+		if (riscv_cpu_has_extension_unlikely(cpu, RISCV_ISA_EXT_SVADE))
+			return true;
+	}
+
+	return false;
+}
+
+int riscv_enable_hw_pte_ad_updating(void)
+{
+	unsigned int cpu;
+	int ret;
+
+	if (!riscv_has_hw_pte_ad_updating() ||
+	    !riscv_hw_pte_ad_updating_requires_fwft)
+		return 0;
+
+	cpu = smp_processor_id();
+	ret = riscv_enable_local_hw_pte_ad_updating();
+	if (ret)
+		pr_err("CPU%u failed to enable hardware PTE A/D updating: %d\n",
+		       cpu, ret);
+
+	return ret;
+}
+
+static void __init riscv_disable_hw_pte_ad_updating(int error)
+{
+	int ret;
+
+	riscv_hw_pte_ad_updating_requires_fwft = false;
+	if (error != -EOPNOTSUPP)
+		pr_err("Failed to enable hardware PTE A/D updating: %d\n",
+		       error);
+
+	ret = riscv_set_online_hw_pte_ad_updating(false);
+	if (ret && ret != -EOPNOTSUPP)
+		pr_err("Failed to rollback hardware PTE A/D updating: %d\n",
+		       ret);
+
+	pr_info("riscv: leave PTE A/D updates software-managed (%d)\n",
+		error);
+}
+
+static int __init riscv_hw_pte_ad_updating_init(void)
+{
+	bool requires_fwft, has_svadu;
+	int ret;
+
+	has_svadu = riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
+	requires_fwft = riscv_any_cpu_has_svade();
+
+	if (!has_svadu)
+		return 0;
+
+	if (requires_fwft) {
+		riscv_hw_pte_ad_updating_requires_fwft = true;
+		ret = riscv_set_online_hw_pte_ad_updating(true);
+		if (ret) {
+			riscv_disable_hw_pte_ad_updating(ret);
+			return 0;
+		}
+	}
+
+	/*
+	 * At this point hardware PTE A/D updating is active for all online
+	 * harts, either from boot or from the FWFT setup above. Later harts
+	 * must do the same in secondary startup before they are marked online.
+	 */
+	riscv_set_hw_pte_ad_updating();
+	pr_debug("riscv: hardware PTE A/D updating enabled\n");
 	return 0;
 }
+arch_initcall(riscv_hw_pte_ad_updating_init);
 
 static int riscv_cfilp_validate(const struct riscv_isa_ext_data *data,
 				const unsigned long *isa_bitmap)
@@ -584,7 +673,7 @@ const struct riscv_isa_ext_data riscv_isa_ext[] = {
 	__RISCV_ISA_EXT_SUPERSET(ssnpm, RISCV_ISA_EXT_SSNPM, riscv_xlinuxenvcfg_exts),
 	__RISCV_ISA_EXT_DATA(sstc, RISCV_ISA_EXT_SSTC),
 	__RISCV_ISA_EXT_DATA(svade, RISCV_ISA_EXT_SVADE),
-	__RISCV_ISA_EXT_DATA_VALIDATE(svadu, RISCV_ISA_EXT_SVADU, riscv_ext_svadu_validate),
+	__RISCV_ISA_EXT_DATA(svadu, RISCV_ISA_EXT_SVADU),
 	__RISCV_ISA_EXT_DATA(svinval, RISCV_ISA_EXT_SVINVAL),
 	__RISCV_ISA_EXT_DATA(svnapot, RISCV_ISA_EXT_SVNAPOT),
 	__RISCV_ISA_EXT_DATA(svpbmt, RISCV_ISA_EXT_SVPBMT),
diff --git a/arch/riscv/kernel/smpboot.c b/arch/riscv/kernel/smpboot.c
index 8b628580fe118..4fe62f96bcca2 100644
--- a/arch/riscv/kernel/smpboot.c
+++ b/arch/riscv/kernel/smpboot.c
@@ -27,6 +27,7 @@
 #include <linux/sched/mm.h>
 
 #include <asm/cacheflush.h>
+#include <asm/cpufeature.h>
 #include <asm/cpu_ops.h>
 #include <asm/irq.h>
 #include <asm/mmu_context.h>
@@ -221,6 +222,9 @@ asmlinkage __visible void smp_callin(void)
 	struct mm_struct *mm = &init_mm;
 	unsigned int curr_cpuid = smp_processor_id();
 
+	if (riscv_enable_hw_pte_ad_updating())
+		return;
+
 	if (has_vector()) {
 		/*
 		 * Return as early as possible so the hart with a mismatching
-- 
2.39.5



From cuiyunhui at bytedance.com  Wed Jun 17 23:44:06 2026
From: cuiyunhui at bytedance.com (Yunhui Cui)
Date: Thu, 18 Jun 2026 14:44:06 +0800
Subject: [PATCH v4 3/3] riscv: preserve A/D and soft-dirty state across PTE updates
In-Reply-To: <20260618064406.14508-1-cuiyunhui@bytedance.com>
References: <20260618064406.14508-1-cuiyunhui@bytedance.com>
Message-ID: <20260618064406.14508-4-cuiyunhui@bytedance.com>

Use cmpxchg-based PTE updates so software permission changes do not lose
concurrent A/D updates from hardware. Preserve soft-dirty state as well,
since RISC-V marks PTEs dirty and soft-dirty together.

Signed-off-by: Yunhui Cui <cuiyunhui at bytedance.com>
Reviewed-by: Qingwei Hu <qingwei.hu at bytedance.com>
---
 arch/riscv/include/asm/pgtable.h | 27 +++++++++----
 arch/riscv/mm/pgtable.c          | 68 ++++++++++++++++++++++++++------
 2 files changed, 77 insertions(+), 18 deletions(-)

diff --git a/arch/riscv/include/asm/pgtable.h b/arch/riscv/include/asm/pgtable.h
index 5d5756bda82e3..02286b48dc471 100644
--- a/arch/riscv/include/asm/pgtable.h
+++ b/arch/riscv/include/asm/pgtable.h
@@ -678,15 +678,21 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
 static inline void ptep_set_wrprotect(struct mm_struct *mm,
 				      unsigned long address, pte_t *ptep)
 {
-	pte_t read_pte = READ_ONCE(*ptep);
+	pte_t old_pte;
+	pte_t pte;
 	/*
 	 * ptep_set_wrprotect can be called for shadow stack ranges too.
 	 * shadow stack memory is XWR = 010 and thus clearing _PAGE_WRITE will lead to
 	 * encoding 000b which is wrong encoding with V = 1. This should lead to page fault
 	 * but we dont want this wrong configuration to be set in page tables.
 	 */
-	atomic_long_set((atomic_long_t *)ptep,
-			((pte_val(read_pte) & ~(unsigned long)_PAGE_WRITE) | _PAGE_READ));
+	pte = READ_ONCE(*ptep);
+	do {
+		old_pte = pte;
+		pte = pte_wrprotect(pte);
+		pte_val(pte) = cmpxchg_relaxed(&pte_val(*ptep), pte_val(old_pte),
+					       pte_val(pte));
+	} while (pte_val(pte) != pte_val(old_pte));
 }
 
 #define __HAVE_ARCH_PTEP_CLEAR_YOUNG_FLUSH
@@ -742,14 +748,14 @@ static inline pgprot_t pgprot_writecombine(pgprot_t _prot)
 #define pgprot_dmacoherent pgprot_writecombine
 
 /*
- * Both Svade and Svadu control the hardware behavior when the PTE A/D bits need to be set. By
- * default the M-mode firmware enables the hardware updating scheme when only Svadu is present in
- * DT.
+ * Both Svade and Svadu control the hardware behavior when the PTE A/D bits
+ * need to be set. The core MM code only cares whether hardware updating of
+ * the accessed/dirty state is currently active.
  */
 #define arch_has_hw_pte_young arch_has_hw_pte_young
 static inline bool arch_has_hw_pte_young(void)
 {
-	return riscv_has_extension_unlikely(RISCV_ISA_EXT_SVADU);
+	return riscv_has_hw_pte_ad_updating();
 }
 
 /*
@@ -1040,6 +1046,13 @@ static inline void pmdp_set_wrprotect(struct mm_struct *mm,
 	ptep_set_wrprotect(mm, address, (pte_t *)pmdp);
 }
 
+#define __HAVE_ARCH_PUDP_SET_WRPROTECT
+static inline void pudp_set_wrprotect(struct mm_struct *mm,
+				      unsigned long address, pud_t *pudp)
+{
+	ptep_set_wrprotect(mm, address, (pte_t *)pudp);
+}
+
 #define pmdp_establish pmdp_establish
 static inline pmd_t pmdp_establish(struct vm_area_struct *vma,
 				unsigned long address, pmd_t *pmdp, pmd_t pmd)
diff --git a/arch/riscv/mm/pgtable.c b/arch/riscv/mm/pgtable.c
index 9c4427d0b1874..98eed19ea70de 100644
--- a/arch/riscv/mm/pgtable.c
+++ b/arch/riscv/mm/pgtable.c
@@ -5,23 +5,55 @@
 #include <linux/kernel.h>
 #include <linux/pgtable.h>
 
+#define RISCV_PTE_ACCESS_FLAG_MASK	(_PAGE_READ | _PAGE_WRITE | _PAGE_EXEC | \
+					 _PAGE_ACCESSED | _PAGE_DIRTY | \
+					 _PAGE_SOFT_DIRTY)
+
+static inline unsigned long riscv_pte_access_flags(unsigned long cur,
+						   unsigned long entry)
+{
+	unsigned long pteval;
+	unsigned long preserved_flags;
+
+	preserved_flags = _PAGE_ACCESSED | _PAGE_DIRTY | _PAGE_SOFT_DIRTY;
+	pteval = cur & ~RISCV_PTE_ACCESS_FLAG_MASK;
+	pteval |= entry & (RISCV_PTE_ACCESS_FLAG_MASK & ~preserved_flags);
+	pteval |= (cur | entry) & preserved_flags;
+
+	return pteval;
+}
+
 int ptep_set_access_flags(struct vm_area_struct *vma,
 			  unsigned long address, pte_t *ptep,
 			  pte_t entry, int dirty)
 {
+	unsigned long old_pteval;
+	unsigned long new_pteval;
+	unsigned long prev_pteval;
+	bool changed;
+
+	old_pteval = pte_val(ptep_get(ptep));
+	do {
+		new_pteval = riscv_pte_access_flags(old_pteval, pte_val(entry));
+		if (new_pteval == old_pteval)
+			break;
+
+		prev_pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval,
+					      new_pteval);
+		if (prev_pteval == old_pteval)
+			break;
+
+		old_pteval = prev_pteval;
+	} while (1);
+
+	changed = old_pteval != new_pteval;
 	if (riscv_has_extension_unlikely(RISCV_ISA_EXT_SVVPTC)) {
-		if (!pte_same(ptep_get(ptep), entry)) {
-			__set_pte_at(vma->vm_mm, ptep, entry);
-			/* Here only not svadu is impacted */
+		if (changed)
 			flush_tlb_page(vma, address);
-			return true;
-		}
 
-		return false;
+		return changed;
 	}
 
-	if (!pte_same(ptep_get(ptep), entry))
-		__set_pte_at(vma->vm_mm, ptep, entry);
 	/*
 	 * update_mmu_cache will unconditionally execute, handling both
 	 * the case that the PTE changed and the spurious fault case.
@@ -32,9 +64,23 @@ int ptep_set_access_flags(struct vm_area_struct *vma,
 bool ptep_test_and_clear_young(struct vm_area_struct *vma,
 		unsigned long address, pte_t *ptep)
 {
-	if (!pte_young(ptep_get(ptep)))
-		return false;
-	return test_and_clear_bit(_PAGE_ACCESSED_OFFSET, &pte_val(*ptep));
+	unsigned long old_pteval;
+	unsigned long new_pteval;
+	unsigned long prev_pteval;
+
+	old_pteval = pte_val(ptep_get(ptep));
+	do {
+		if (!(old_pteval & _PAGE_ACCESSED))
+			return false;
+
+		new_pteval = pte_val(pte_mkold(__pte(old_pteval)));
+		prev_pteval = cmpxchg_relaxed(&pte_val(*ptep), old_pteval,
+					      new_pteval);
+		if (prev_pteval == old_pteval)
+			return true;
+
+		old_pteval = prev_pteval;
+	} while (1);
 }
 EXPORT_SYMBOL_GPL(ptep_test_and_clear_young);
 
-- 
2.39.5



From maxime.chevallier at bootlin.com  Thu Jun 18 00:03:21 2026
From: maxime.chevallier at bootlin.com (Maxime Chevallier)
Date: Thu, 18 Jun 2026 09:03:21 +0200
Subject: [PATCH net] net: stmmac: dwmac-spacemit: Fix wrong ctrl register
 definition
In-Reply-To: <20260618064143.1102179-1-inochiama@gmail.com>
References: <20260618064143.1102179-1-inochiama@gmail.com>
Message-ID: <9b39829d-92b4-4ffa-be0b-b2b0f857f58e@bootlin.com>

Hi Inochi,

On 6/18/26 08:41, Inochi Amaoto wrote:
> There register layout of the phy ctrl register has something wrong,
> fix it to match the right layout
> 
> Fixes: 30f0ba420ed3 ("net: stmmac: Add glue layer for Spacemit K3 SoC")
> Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> ---
>  .../net/ethernet/stmicro/stmmac/dwmac-spacemit.c    | 13 ++++++++-----
>  1 file changed, 8 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> index 223754cc5c79..6feffaa3ef3a 100644
> --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> @@ -18,10 +18,12 @@
>  #include "stmmac_platform.h"
>  
>  /* ctrl register bits */
> -#define CTRL_PHY_INTF_RGMII		BIT(3)
> -#define CTRL_PHY_INTF_MII		BIT(4)
> -#define CTRL_WAKE_IRQ_EN		BIT(9)
> -#define CTRL_PHY_IRQ_EN			BIT(12)
> +#define CTRL_PHY_INTF_MODE		GENMASK(4, 3)
> +#define CTRL_PHY_INTF_RMII		FIELD_PREP(CTRL_PHY_INTF_MODE, 0)
> +#define CTRL_PHY_INTF_RGMII		FIELD_PREP(CTRL_PHY_INTF_MODE, 1)
> +#define CTRL_PHY_INTF_MII		FIELD_PREP(CTRL_PHY_INTF_MODE, 3)
> +#define CTRL_PHY_IRQ_EN			BIT(9)
> +#define CTRL_WAKE_IRQ_EN		BIT(12)

Looks like you're fixing 2 things there :

 -> Wake on Lan probably didn't work before, as the wake irq was apparently wrong
 -> The MII mode selection apparently also changes, but maybe you don't have a
    MII board around to test this ?

Is it possible you address these issues independently (i.e. split this in 2 patches) ?
That way, if we ever revert one, we won't re-break the other thing that was broken.


Maxime



From inochiama at gmail.com  Thu Jun 18 00:12:58 2026
From: inochiama at gmail.com (Inochi Amaoto)
Date: Thu, 18 Jun 2026 15:12:58 +0800
Subject: [PATCH net] net: stmmac: dwmac-spacemit: Fix wrong ctrl register
 definition
In-Reply-To: <9b39829d-92b4-4ffa-be0b-b2b0f857f58e@bootlin.com>
References: <20260618064143.1102179-1-inochiama@gmail.com>
 <9b39829d-92b4-4ffa-be0b-b2b0f857f58e@bootlin.com>
Message-ID: <ajOZnO_dFg20VnEc@inochi.infowork>

On Thu, Jun 18, 2026 at 09:03:21AM +0200, Maxime Chevallier wrote:
> Hi Inochi,
> 
> On 6/18/26 08:41, Inochi Amaoto wrote:
> > There register layout of the phy ctrl register has something wrong,
> > fix it to match the right layout
> > 
> > Fixes: 30f0ba420ed3 ("net: stmmac: Add glue layer for Spacemit K3 SoC")
> > Signed-off-by: Inochi Amaoto <inochiama at gmail.com>
> > ---
> >  .../net/ethernet/stmicro/stmmac/dwmac-spacemit.c    | 13 ++++++++-----
> >  1 file changed, 8 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> > index 223754cc5c79..6feffaa3ef3a 100644
> > --- a/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> > +++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-spacemit.c
> > @@ -18,10 +18,12 @@
> >  #include "stmmac_platform.h"
> >  
> >  /* ctrl register bits */
> > -#define CTRL_PHY_INTF_RGMII		BIT(3)
> > -#define CTRL_PHY_INTF_MII		BIT(4)
> > -#define CTRL_WAKE_IRQ_EN		BIT(9)
> > -#define CTRL_PHY_IRQ_EN			BIT(12)
> > +#define CTRL_PHY_INTF_MODE		GENMASK(4, 3)
> > +#define CTRL_PHY_INTF_RMII		FIELD_PREP(CTRL_PHY_INTF_MODE, 0)
> > +#define CTRL_PHY_INTF_RGMII		FIELD_PREP(CTRL_PHY_INTF_MODE, 1)
> > +#define CTRL_PHY_INTF_MII		FIELD_PREP(CTRL_PHY_INTF_MODE, 3)
> > +#define CTRL_PHY_IRQ_EN			BIT(9)
> > +#define CTRL_WAKE_IRQ_EN		BIT(12)
> 
> Looks like you're fixing 2 things there :
> 
>  -> Wake on Lan probably didn't work before, as the wake irq was apparently wrong.

I guess the vendor firmware and uboot may do something for it, 
but the irq is wrong actually.

>  -> The MII mode selection apparently also changes, but maybe you don't have a
>     MII board around to test this ?
> 

Actually, the only board of the K3 is the pico-itx board, and it only has
a RGMII phy. I even doube the spacemit vendor has not tested the MII phy
well....

> Is it possible you address these issues independently (i.e. split this in 2 patches) ?
> That way, if we ever revert one, we won't re-break the other thing that was broken.
> 
> 

Yes, it is fine for me to split it. I will send it in a few days.

Regards,
Inochi


From thecharlesjenkins at gmail.com  Thu Jun 18 00:31:26 2026
From: thecharlesjenkins at gmail.com (Charlie Jenkins)
Date: Thu, 18 Jun 2026 00:31:26 -0700
Subject: [PATCH 04/16] riscv: kprobes: Use generated instruction headers
In-Reply-To: <87jys5egum.fsf@yellow.woof>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-4-54b4736a1e77@gmail.com>
 <87jys5egum.fsf@yellow.woof>
Message-ID: <ajOezhejx7PcOw_x@blinky>

On Thu, Jun 11, 2026 at 08:22:41AM +0200, Nam Cao wrote:
> Charlie Jenkins via B4 Relay
> <devnull+thecharlesjenkins.gmail.com at kernel.org> writes:
> > This was again verified by checking all 32-bit values for each of these
> > functions and checking that the two version have the same behavior.
> 
> Your checking is missing some cases. branch instructions and c.jr are
> broken.
> 
> Btw, any chance that check can be added as a new kunit test case? I
> wrote the CONFIG_RISCV_KPROBES_KUNIT, but that only tests some values.

Okay I looked back over my test cases and realized my mistakes. I was
iterating through all possible 32-bit values and passing them into the
new simulate_* functions and comparing the register state to the old
simulate_* instructions. I missed the _pc + addr bug because the _pc
value I was using was 0. I missed the simulate_c_jr ra bug because I was
not checking ra.


Since I was checking against the previous version it's not possible to
do a straight one-to-one conversion to the kunit. I think it might be
possible to do something similar but I will need to mess with that to
determine a good way of doing it.

- Charlie

> 
> Nam


From wangruikang at iscas.ac.cn  Thu Jun 18 00:33:29 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Thu, 18 Jun 2026 15:33:29 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <CAJF2gTQ+-gpvUDtOh99aKP2-iDJy3MYOWti9k2Ntd0-J0MXqxQ@mail.gmail.com>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org>
 <7c490aeb-a3d9-4fe9-81de-f9662577851d@iscas.ac.cn>
 <CAJF2gTQ+-gpvUDtOh99aKP2-iDJy3MYOWti9k2Ntd0-J0MXqxQ@mail.gmail.com>
Message-ID: <e051d822-d0be-4a88-ba86-ec9b5905fd1e@iscas.ac.cn>

On 6/18/26 11:45, Guo Ren wrote:
> On Thu, Jun 18, 2026 at 11:20?AM Vivian Wang <wangruikang at iscas.ac.cn> wrote:
>> On 6/15/26 20:38, Guo Ren wrote:
>>> Hi Zhanpeng Zhang,
>>>
>>> I noticed you posted a similar fix recently. However, I had already
>>> submitted a similar solution back in September 2025 [1]. It would be
>>> great if you could review it. A few concerns with the current patch:
>>>
>>> 1. Using spin_lock_irqsave in such a small semantic structure is
>>> unnecessary. IRQ protection should be provided by the higher-level
>>> IOMMU driver interfaces. Many existing call sites already handle IRQ
>>> disabling, so adding it here feels redundant and adds avoidable
>>> overhead.
>>>
>>> 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
>>> problematic. According to the RISC-V IOMMU specification (Software
>>> Guidelines, ?Reading and writing IOMMU registers?):
>>>
>>>> Registers that are 64-bit wide may be accessed using either a 32-bit
>>>> or a 64-bit access.
>>> This clearly requires that any hardware supporting 64-bit MMIO access
>>> must also support 32-bit MMIO access. Therefore, the IOMMU driver should
>>> be built on a 32-bit access base for maximum hardware compatibility.
>> I agree that the driver should be build with 32-bit accesses to support
>> these hardware. However there's one minor thing that I want to propose
>> regarding this, for the sake of clarity:
>>
>> RISC-V IOMMU implementations that do not support 64-bit accesses are not
>> fully compliant with the RISC-V IOMMU specification and should not use
>> the standard RISC-V identifiers, namely:
>>
>> - Devicetree compatible riscv,iommu
>> - ACPI HID RSCV0004
>>
>> This, in my opinion, is not only the right thing to do (not claiming to
>> be standard hardware without actually being standard hardware), but also
>> saves a lot of trouble for operating system developers (yes, there are
>> RISC-V operating systems other than Linux out there), since invalid IO
>> accesses usually manifest as mysterious access faults (that would
>> usually suggest an incorrect IOMMU address), or worse, system hangs.
>>
>> I would appreciate if the hardware vendors shipping 32-bit-access-only
>> IOMMUs would consider this.
>>
>> Vivian "dramforever" Wang
>>
> 32-bit MMIO access is explicitly supported by the RISC-V IOMMU
> specification and is a valid choice (64-bit MMIO access is optional).

Hmm... I think it's optional in software but not optional in hardware,
but the specs are not super clear on this. I've opened a GitHub issue to
ask:

    https://github.com/riscv-non-isa/riscv-iommu/issues/765

> 64-bit MMIO access is not "free" ? it consumes additional interconnect
> hardware resources.
>
> Could you elaborate on the concrete benefit of using 64-bit MMIO
> access in this driver, for these non-PMU registers? A clear
> justification would help evaluate whether the trade-off is worthwhile.
>
>



From work at onurozkan.dev  Thu Jun 18 00:58:47 2026
From: work at onurozkan.dev (=?UTF-8?q?Onur=20=C3=96zkan?=)
Date: Thu, 18 Jun 2026 10:58:47 +0300
Subject: [PATCH v4 3/3] rust: clk: use 'kernel vertical style' for imports
In-Reply-To: <20260618-clk-type-state-v4-3-8be082786080@collabora.com>
References: <20260618-clk-type-state-v4-0-8be082786080@collabora.com> <20260618-clk-type-state-v4-3-8be082786080@collabora.com>
Message-ID: <20260618075848.28017-1-work@onurozkan.dev>

On Thu, 18 Jun 2026 00:46:37 -0300
Daniel Almeida <daniel.almeida at collabora.com> wrote:

> Convert all imports to use the new import style. This will make it easier
> to land new changes in the future.
> 
> No change of functionality implied.
> 
> Link: https://docs.kernel.org/rust/coding-guidelines.html#imports
> Signed-off-by: Daniel Almeida <daniel.almeida at collabora.com>

Reviewed-by: Onur ?zkan <work at onurozkan.dev>

> ---
>  rust/kernel/clk.rs | 56 ++++++++++++++++++++++++++++++++++++++++++++----------
>  1 file changed, 46 insertions(+), 10 deletions(-)
> 
> diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
> index 692ee88ca772..1412a2f0aedf 100644
> --- a/rust/kernel/clk.rs
> +++ b/rust/kernel/clk.rs
> @@ -80,12 +80,23 @@ fn from(freq: Hertz) -> Self {
>  mod common_clk {
>      use super::Hertz;
>      use crate::{
> -        device::{Bound, Device},
> -        error::{from_err_ptr, to_result, Result},
> -        prelude::*,
> +        device::{
> +            Bound,
> +            Device, //
> +        },
> +        error::{
> +            from_err_ptr,
> +            to_result,
> +            Result, //
> +        },
> +        prelude::*, //
>      };
>  
> -    use core::{marker::PhantomData, mem::ManuallyDrop, ptr};
> +    use core::{
> +        marker::PhantomData,
> +        mem::ManuallyDrop,
> +        ptr, //
> +    };
>  
>      mod private {
>          pub trait Sealed {}
> @@ -189,8 +200,15 @@ impl<State: ClkState> From<Error<State>> for kernel::error::Error {
>          /// original [`Clk`], e.g.:
>          ///
>          /// ```
> -        /// use kernel::clk::{Clk, Enabled, Unprepared};
> -        /// use kernel::device::{Bound, Device};
> +        /// use kernel::clk::{
> +        ///     Clk,
> +        ///     Enabled,
> +        ///     Unprepared, //
> +        /// };
> +        /// use kernel::device::{
> +        ///     Bound,
> +        ///     Device, //
> +        /// };
>          /// use kernel::error::Result;
>          ///
>          /// fn get_enabled(dev: &Device<Bound>) -> Result<Clk<Enabled>> {
> @@ -240,8 +258,17 @@ fn from(err: Error<State>) -> Self {
>      /// The following example demonstrates how to obtain and configure a clock for a device.
>      ///
>      /// ```
> -    /// use kernel::clk::{Clk, Enabled, Hertz, Unprepared, Prepared};
> -    /// use kernel::device::{Bound, Device};
> +    /// use kernel::clk::{
> +    ///     Clk,
> +    ///     Enabled,
> +    ///     Hertz,
> +    ///     Prepared,
> +    ///     Unprepared, //
> +    /// };
> +    /// use kernel::device::{
> +    ///     Bound,
> +    ///     Device, //
> +    /// };
>      /// use kernel::error::Result;
>      ///
>      /// fn configure_clk(dev: &Device<Bound>) -> Result {
> @@ -287,7 +314,11 @@ fn from(err: Error<State>) -> Self {
>      /// and move between the variants:
>      ///
>      /// ```
> -    /// use kernel::clk::{Clk, Enabled, Prepared};
> +    /// use kernel::clk::{
> +    ///     Clk,
> +    ///     Enabled,
> +    ///     Prepared, //
> +    /// };
>      /// use kernel::error::Result;
>      ///
>      /// enum DeviceClk {
> @@ -481,7 +512,12 @@ pub fn enable(self) -> Result<Clk<Enabled>, Error<Prepared>> {
>          /// clock or threading it through an intermediate state, e.g.:
>          ///
>          /// ```
> -        /// use kernel::clk::{Clk, Enabled, Hertz, Prepared};
> +        /// use kernel::clk::{
> +        ///     Clk,
> +        ///     Enabled,
> +        ///     Hertz,
> +        ///     Prepared, //
> +        /// };
>          /// use kernel::error::Result;
>          ///
>          /// fn read_rate(clk: &Clk<Prepared>) -> Result<Hertz> {
> 
> -- 
> 2.54.0
> 


From work at onurozkan.dev  Thu Jun 18 01:10:34 2026
From: work at onurozkan.dev (=?UTF-8?q?Onur=20=C3=96zkan?=)
Date: Thu, 18 Jun 2026 11:10:34 +0300
Subject: [PATCH v4 1/3] rust: clk: use the type-state pattern
In-Reply-To: <20260618-clk-type-state-v4-1-8be082786080@collabora.com>
References: <20260618-clk-type-state-v4-0-8be082786080@collabora.com> <20260618-clk-type-state-v4-1-8be082786080@collabora.com>
Message-ID: <20260618081037.35784-1-work@onurozkan.dev>

On Thu, 18 Jun 2026 00:46:35 -0300
Daniel Almeida <daniel.almeida at collabora.com> wrote:

> The current Clk abstraction can still be improved on the following issues:
> 
> a) It only keeps track of a count to clk_get(), which means that users have
> to manually call disable() and unprepare(), or a variation of those, like
> disable_unprepare().
> 
> b) It allows repeated calls to prepare() or enable(), but it keeps no track
> of how often these were called, i.e., it's currently legal to write the
> following:
> 
> clk.prepare();
> clk.prepare();
> clk.enable();
> clk.enable();
> 
> And nothing gets undone on drop().
> 
> c) It adds a OptionalClk type that is probably not needed. There is no
> "struct optional_clk" in C and we should probably not add one.
> 
> d) It does not let a user express the state of the clk through the
> type system. For example, there is currently no way to encode that a Clk is
> enabled via the type system alone.
> 
> In light of the Regulator abstraction that was recently merged, switch this
> abstraction to use the type-state pattern instead. It solves both a) and b)
> by establishing a number of states and the valid ways to transition between
> them. It also automatically undoes any call to clk_get(), clk_prepare() and
> clk_enable() as applicable on drop(), so users do not have to do anything
> special before Clk goes out of scope.
> 
> It solves c) by removing the OptionalClk type, which is now simply encoded
> as a Clk whose inner pointer is NULL.
> 
> It solves d) by directly encoding the state of the Clk into the type, e.g.:
> Clk<Enabled> is now known to be a Clk that is enabled.
> 
> The INVARIANTS section for Clk is expanded to highlight the relationship
> between the states and the respective reference counts that are owned by
> each of them.
> 
> The examples are expanded to highlight how a user can transition between
> states, as well as highlight some of the shortcuts built into the API.
> 
> The current implementation is also more flexible, in the sense that it
> allows for more states to be added in the future. This lets us implement
> different strategies for handling clocks, including one that mimics the
> current API, allowing for multiple calls to prepare() and enable().
> 
> The users (cpufreq.rs/ rcpufreq_dt.rs) were updated by this patch (and not
> a separate one) to reflect the new changes. This is needed, because
> otherwise this patch would break the build.
> 
> Link: https://crates.io/crates/sealed [1]
> Signed-off-by: Daniel Almeida <daniel.almeida at collabora.com>
> ---
>  drivers/cpufreq/rcpufreq_dt.rs |   2 +-
>  drivers/gpu/drm/tyr/driver.rs  |  31 +--
>  drivers/pwm/pwm_th1520.rs      |  17 +-
>  rust/kernel/clk.rs             | 512 ++++++++++++++++++++++++++++++-----------
>  rust/kernel/cpufreq.rs         |   8 +-
>  5 files changed, 396 insertions(+), 174 deletions(-)
> 
> diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs
> index f17bf64c22e2..9d2ec7df4bac 100644
> --- a/drivers/cpufreq/rcpufreq_dt.rs
> +++ b/drivers/cpufreq/rcpufreq_dt.rs
> @@ -40,7 +40,7 @@ struct CPUFreqDTDevice {
>      freq_table: opp::FreqTable,
>      _mask: CpumaskVar,
>      _token: Option<opp::ConfigToken>,
> -    _clk: Clk,
> +    _clk: Clk<kernel::clk::Unprepared>,
>  }
>  
>  #[derive(Default)]
> diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
> index 279710b36a10..a2230aebfea2 100644
> --- a/drivers/gpu/drm/tyr/driver.rs
> +++ b/drivers/gpu/drm/tyr/driver.rs
> @@ -3,7 +3,7 @@
>  use kernel::{
>      clk::{
>          Clk,
> -        OptionalClk, //
> +        Enabled, //
>      },
>      device::{
>          Bound,
> @@ -49,7 +49,7 @@ pub(crate) struct TyrPlatformDriverData {

[...]

> -        /// Disable and unprepare the clock.
> -        ///
> -        /// Equivalent to calling [`Clk::disable`] followed by [`Clk::unprepare`].
> +        /// Behaves the same as [`Self::get`], except when there is no clock
> +        /// producer. In this case, instead of returning [`ENOENT`], it returns
> +        /// a dummy [`Clk`].
>          #[inline]
> -        pub fn disable_unprepare(&self) {
> -            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> -            // [`clk_disable_unprepare`].
> -            unsafe { bindings::clk_disable_unprepare(self.as_raw()) };
> +        pub fn get_optional(dev: &Device<Bound>, name: Option<&CStr>) -> Result<Clk<Enabled>> {
> +            Clk::<Prepared>::get_optional(dev, name)?
> +                .enable()
> +                .map_err(|error| error.error)
> +        }
> +
> +        /// Attempts to disable the [`Clk`] and convert it to the [`Prepared`]

nit: I wouldn't use the word "Attempts" for an infallible function.

> +        /// state.
> +        #[inline]
> +        pub fn disable(self) -> Result<Clk<Prepared>, Error<Enabled>> {

This is an infallible function, you can return Clk<Prepared> directly.

Thanks,
Onur

> +            // We will be transferring the ownership of our `clk_get()` and
> +            // `clk_enable()` counts to `Clk<Prepared>`.
> +            let clk = ManuallyDrop::new(self);
> +
> +            // SAFETY: By the type invariants, `self.0` is a valid argument for
> +            // [`clk_disable`].
> +            unsafe { bindings::clk_disable(clk.as_raw()) };
> +
> +            Ok(Clk {
> +                inner: clk.inner,
> +                _phantom: PhantomData,
> +            })
>          }
>  
>          /// Get clock's rate.
> @@ -251,82 +544,31 @@ pub fn set_rate(&self, rate: Hertz) -> Result {
> +                // [`clk_unprepare`].

[...]

> +                unsafe { bindings::clk_unprepare(self.as_raw()) };
> +            }
>  
> -        fn deref(&self) -> &Clk {
> -            &self.0
> +            // SAFETY: By the type invariants, self.as_raw() is a valid argument for
> +            // [`clk_put`].
> +            unsafe { bindings::clk_put(self.as_raw()) };
>          }
>      }
>  }
> diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs
> index d8d26870bea2..e837bb1010e0 100644
> --- a/rust/kernel/cpufreq.rs
> +++ b/rust/kernel/cpufreq.rs
> @@ -553,8 +553,12 @@ pub fn cpus(&mut self) -> &mut cpumask::Cpumask {
>      /// The caller must guarantee that the returned [`Clk`] is not dropped while it is getting used
>      /// by the C code.
>      #[cfg(CONFIG_COMMON_CLK)]
> -    pub unsafe fn set_clk(&mut self, dev: &Device, name: Option<&CStr>) -> Result<Clk> {
> -        let clk = Clk::get(dev, name)?;
> +    pub unsafe fn set_clk(
> +        &mut self,
> +        dev: &Device,
> +        name: Option<&CStr>,
> +    ) -> Result<Clk<crate::clk::Unprepared>> {
> +        let clk = Clk::<crate::clk::Unprepared>::get_unbound(dev, name)?;
>          self.as_mut_ref().clk = clk.as_raw();
>          Ok(clk)
>      }
> 
> -- 
> 2.54.0
> 


From kees at kernel.org  Thu Jun 18 01:12:57 2026
From: kees at kernel.org (Kees Cook)
Date: Thu, 18 Jun 2026 01:12:57 -0700
Subject: [PATCH] riscv: Add kCFI type prefix to unaligned copy routines
Message-ID: <20260618081252.work.711-kees@kernel.org>

__riscv_copy_words_unaligned() and __riscv_copy_bytes_unaligned() are
called indirectly through function pointers from measure_cycles() (via
compare_unaligned_access()) during the boot-time unaligned-access
probe. Under kCFI, an indirect call checks the type id stored in the
word immediately preceding the callee against the type id of the
function-pointer type at the call site. These two routines are defined
with SYM_FUNC_START(), which emits no __cfi_ prefix, so the check reads
the alignment padding ahead of the function (zero) instead of a type id
and traps:

  CFI failure at measure_cycles.constprop.0+0x34
    (target: __riscv_copy_words_unaligned+0x0; expected type: 0x00000000)
  Kernel panic - not syncing: Fatal exception in interrupt

The call site is correct: it loads the actual type id from [target-4]
and compares against the expected 0xf1200a56, which matches the
compiler-generated __kcfi_typeid___riscv_copy_words_unaligned. Only the
callee is missing its prefix word.

Switch both routines to SYM_TYPED_FUNC_START() so the assembler emits
the __cfi_ type-id prefix, matching the existing treatment of other
indirectly-called riscv assembly routines (e.g. ftrace_stub in
mcount.S and __cpu_resume_enter in suspend_entry.S), and add the
<linux/cfi_types.h> include that provides the macro.

Build and boot tested ARCH=riscv defconfig+CONFIG_CFI=y with GCC
17.0.0 20260615 (experimental kCFI tree) under qemu; the boot-time
unaligned-access probe no longer traps.

Fixes: 584ea6564bca ("RISC-V: Probe for unaligned access speed")
Assisted-by: Claude:claude-opus-4-8[1m]
Signed-off-by: Kees Cook <kees at kernel.org>
---
 arch/riscv/kernel/copy-unaligned.S | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/arch/riscv/kernel/copy-unaligned.S b/arch/riscv/kernel/copy-unaligned.S
index 2b3d9398c113..c649ad3d19e0 100644
--- a/arch/riscv/kernel/copy-unaligned.S
+++ b/arch/riscv/kernel/copy-unaligned.S
@@ -2,6 +2,7 @@
 /* Copyright (C) 2023 Rivos Inc. */
 
 #include <linux/linkage.h>
+#include <linux/cfi_types.h>
 #include <asm/asm.h>
 
 	.text
@@ -9,7 +10,7 @@
 /* void __riscv_copy_words_unaligned(void *, const void *, size_t) */
 /* Performs a memcpy without aligning buffers, using word loads and stores. */
 /* Note: The size is truncated to a multiple of 8 * SZREG */
-SYM_FUNC_START(__riscv_copy_words_unaligned)
+SYM_TYPED_FUNC_START(__riscv_copy_words_unaligned)
 	andi  a4, a2, ~((8*SZREG)-1)
 	beqz  a4, 2f
 	add   a3, a1, a4
@@ -41,7 +42,7 @@ SYM_FUNC_END(__riscv_copy_words_unaligned)
 /* void __riscv_copy_bytes_unaligned(void *, const void *, size_t) */
 /* Performs a memcpy without aligning buffers, using only byte accesses. */
 /* Note: The size is truncated to a multiple of 8 */
-SYM_FUNC_START(__riscv_copy_bytes_unaligned)
+SYM_TYPED_FUNC_START(__riscv_copy_bytes_unaligned)
 	andi a4, a2, ~(8-1)
 	beqz a4, 2f
 	add  a3, a1, a4
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Jun 18 02:24:41 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 18 Jun 2026 17:24:41 +0800
Subject: [PATCH v2 1/4] cpu/hotplug: Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST
In-Reply-To: <20260618092444.1316336-1-ruanjinjie@huawei.com>
References: <20260618092444.1316336-1-ruanjinjie@huawei.com>
Message-ID: <20260618092444.1316336-2-ruanjinjie@huawei.com>

During parallel CPU bringup, x86 requires primary SMT threads to boot
first to avoid siblings stopping during microcode updates. This constraint
is architecture-specific and unnecessary for other platforms
like arm64.

Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST to decouple this constraint.
Platforms requiring this temporal order (e.g., x86) can select it
in Kconfig. Other architectures (e.g., arm64) can leave it unselected
to entirely bypass the SMT branch via the preprocessor.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/Kconfig       | 4 ++++
 arch/mips/Kconfig  | 1 +
 arch/riscv/Kconfig | 1 +
 arch/x86/Kconfig   | 1 +
 kernel/cpu.c       | 6 +++++-
 5 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/Kconfig b/arch/Kconfig
index e86880045158..0365d2df2659 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -102,6 +102,10 @@ config HOTPLUG_PARALLEL
 	bool
 	select HOTPLUG_SPLIT_STARTUP
 
+config PARALLEL_SMT_PRIMARY_FIRST
+	bool
+	depends on HOTPLUG_PARALLEL
+
 config GENERIC_IRQ_ENTRY
 	bool
 
diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 4364f3dba688..84e11ac0cf71 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -642,6 +642,7 @@ config EYEQ
 	select MIPS_CPU_SCACHE
 	select MIPS_GIC
 	select MIPS_L1_CACHE_SHIFT_7
+	select PARALLEL_SMT_PRIMARY_FIRST if HOTPLUG_PARALLEL
 	select PCI_DRIVERS_GENERIC
 	select SMP_UP if SMP
 	select SWAP_IO_SPACE
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index d235396c4514..0cc49aecc841 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -210,6 +210,7 @@ config RISCV
 	select OF
 	select OF_EARLY_FLATTREE
 	select OF_IRQ
+	select PARALLEL_SMT_PRIMARY_FIRST if HOTPLUG_PARALLEL
 	select PCI_DOMAINS_GENERIC if PCI
 	select PCI_ECAM if (ACPI && PCI)
 	select PCI_MSI if PCI
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index f3f7cb01d69d..3ad4115ad051 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -314,6 +314,7 @@ config X86
 	select NEED_PER_CPU_PAGE_FIRST_CHUNK
 	select NEED_SG_DMA_LENGTH
 	select NUMA_MEMBLKS			if NUMA
+	select PARALLEL_SMT_PRIMARY_FIRST	if HOTPLUG_PARALLEL
 	select PCI_DOMAINS			if PCI
 	select PCI_LOCKLESS_CONFIG		if PCI
 	select PERF_EVENTS
diff --git a/kernel/cpu.c b/kernel/cpu.c
index bc4f7a9ba64e..7ef8cdf4d239 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1792,6 +1792,7 @@ static int __init parallel_bringup_parse_param(char *arg)
 }
 early_param("cpuhp.parallel", parallel_bringup_parse_param);
 
+#ifdef CONFIG_PARALLEL_SMT_PRIMARY_FIRST
 #ifdef CONFIG_HOTPLUG_SMT
 static inline bool cpuhp_smt_aware(void)
 {
@@ -1811,7 +1812,8 @@ static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
 {
 	return cpu_none_mask;
 }
-#endif
+#endif /* CONFIG_HOTPLUG_SMT */
+#endif /* CONFIG_PARALLEL_SMT_PRIMARY_FIRST */
 
 bool __weak arch_cpuhp_init_parallel_bringup(void)
 {
@@ -1837,6 +1839,7 @@ static bool __init cpuhp_bringup_cpus_parallel(unsigned int ncpus)
 	if (!__cpuhp_parallel_bringup)
 		return false;
 
+#ifdef CONFIG_PARALLEL_SMT_PRIMARY_FIRST
 	if (cpuhp_smt_aware()) {
 		const struct cpumask *pmask = cpuhp_get_primary_thread_mask();
 		static struct cpumask tmp_mask __initdata;
@@ -1857,6 +1860,7 @@ static bool __init cpuhp_bringup_cpus_parallel(unsigned int ncpus)
 		cpumask_andnot(&tmp_mask, mask, pmask);
 		mask = &tmp_mask;
 	}
+#endif /* CONFIG_PARALLEL_SMT_PRIMARY_FIRST */
 
 	/* Bring the not-yet started CPUs up */
 	cpuhp_bringup_mask(mask, ncpus, CPUHP_BP_KICK_AP);
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Jun 18 02:24:40 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 18 Jun 2026 17:24:40 +0800
Subject: [PATCH v2 0/4] arm64: Add HOTPLUG_PARALLEL support for secondary CPUs
Message-ID: <20260618092444.1316336-1-ruanjinjie@huawei.com>

Support for parallel secondary CPU bringup is already utilized by x86,
MIPS, and RISC-V. This patch brings this capability to the arm64
architecture.

Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST to avoid primary SMT threads
to boot first constraint.

And Add a 'cpu' parameter to update_cpu_boot_status() to allow updating the
boot status at a per-CPU granularity during parallel bringup.

Rework the global `secondary_data` accessed during early boot into
a per-CPU array `cpu_boot_data` to allow secondary CPUs to boot
in parallel.

And reuse `__cpu_logical_map` array in the early boot code in head.S
to resolve each secondary CPU's logical ID concurrently.

Changes in v2:
- Remove RFC.
- Add Tested-by.
- Fix AI review issues in [1].
- Add arch_cpuhp_init_parallel_bringup() to check psci boot.
- Reuse `__cpu_logical_map` instead of a new aray.
- Defer rcutree_report_cpu_starting() until after
  check_local_cpu_capabilities() to prevent a potential control CPU
  deadlock if an early capability check fails.
- Move the assembly in head.S to a macro called `mpidr_to_cpuid`.
- Add `SECONDARY_DATA_SHIFT` for `lsl` to access `cpu_boot_data`.
- Add sizeof(struct secondary_data) power of 2 assert check.
- Expand testing with more data collected from real hardware.

[1] https://sashiko.dev/#/patchset/20260611133809.3854977-1-ruanjinjie%40huawei.com

Jinjie Ruan (4):
  cpu/hotplug: Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST
  arm64: smp: Pass CPU ID to update_cpu_boot_status()
  arm64: smp: Defer RCU reporting until after local CPU capability
    checks
  arm64: Add HOTPLUG_PARALLEL support for secondary CPUs

 arch/Kconfig                    |  4 +++
 arch/arm64/Kconfig              |  1 +
 arch/arm64/include/asm/smp.h    | 17 ++++++++++---
 arch/arm64/kernel/asm-offsets.c |  4 +++
 arch/arm64/kernel/cpufeature.c  | 22 ++++++++--------
 arch/arm64/kernel/head.S        | 36 ++++++++++++++++++++++++++
 arch/arm64/kernel/smp.c         | 45 ++++++++++++++++++++++++++++-----
 arch/arm64/mm/context.c         |  4 +--
 arch/mips/Kconfig               |  1 +
 arch/riscv/Kconfig              |  1 +
 arch/x86/Kconfig                |  1 +
 kernel/cpu.c                    |  6 ++++-
 12 files changed, 119 insertions(+), 23 deletions(-)

-- 
2.34.1



From ruanjinjie at huawei.com  Thu Jun 18 02:24:42 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 18 Jun 2026 17:24:42 +0800
Subject: [PATCH v2 2/4] arm64: smp: Pass CPU ID to update_cpu_boot_status()
In-Reply-To: <20260618092444.1316336-1-ruanjinjie@huawei.com>
References: <20260618092444.1316336-1-ruanjinjie@huawei.com>
Message-ID: <20260618092444.1316336-3-ruanjinjie@huawei.com>

To support CONFIG_HOTPLUG_PARALLEL, the CPU boot status tracking must
be refactored from a single global variable (secondary_data.status)
to a per-CPU tracking structure to prevent multi-core race conditions.

Add a 'cpu' parameter to update_cpu_boot_status() and update all its
callsites to pass the corresponding CPU ID. This allows updating the
boot status at a per-CPU granularity during parallel bringup.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/include/asm/smp.h   | 6 +++---
 arch/arm64/kernel/cpufeature.c | 2 +-
 arch/arm64/kernel/smp.c        | 8 ++++----
 arch/arm64/mm/context.c        | 2 +-
 4 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index 10ea4f543069..e2151a01731f 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -122,7 +122,7 @@ static inline void __noreturn cpu_park_loop(void)
 	}
 }
 
-static inline void update_cpu_boot_status(int val)
+static inline void update_cpu_boot_status(unsigned int cpu, int val)
 {
 	WRITE_ONCE(secondary_data.status, val);
 	/* Ensure the visibility of the status update */
@@ -134,9 +134,9 @@ static inline void update_cpu_boot_status(int val)
  * which calls for a kernel panic. Update the boot status and park the calling
  * CPU.
  */
-static inline void __noreturn cpu_panic_kernel(void)
+static inline void __noreturn cpu_panic_kernel(unsigned int cpu)
 {
-	update_cpu_boot_status(CPU_PANIC_KERNEL);
+	update_cpu_boot_status(cpu, CPU_PANIC_KERNEL);
 	cpu_park_loop();
 }
 
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 6d53bb15cf7b..0552202702bf 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -3674,7 +3674,7 @@ static void verify_local_cpu_caps(u16 scope_mask)
 			caps->desc, system_has_cap, cpu_has_cap);
 
 		if (cpucap_panic_on_conflict(caps))
-			cpu_panic_kernel();
+			cpu_panic_kernel(smp_processor_id());
 		else
 			cpu_die_early();
 	}
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 24f8448e1fbb..6bc90ee4820a 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -118,7 +118,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
 	 * page tables.
 	 */
 	secondary_data.task = idle;
-	update_cpu_boot_status(CPU_MMU_OFF);
+	update_cpu_boot_status(cpu, CPU_MMU_OFF);
 
 	/* Now bring the CPU into our world */
 	ret = boot_secondary(cpu, idle);
@@ -252,7 +252,7 @@ asmlinkage notrace void secondary_start_kernel(void)
 	pr_info("CPU%u: Booted secondary processor 0x%010lx [0x%08x]\n",
 					 cpu, (unsigned long)mpidr,
 					 read_cpuid_id());
-	update_cpu_boot_status(CPU_BOOT_SUCCESS);
+	update_cpu_boot_status(cpu, CPU_BOOT_SUCCESS);
 	set_cpu_online(cpu, true);
 	complete(&cpu_running);
 
@@ -411,11 +411,11 @@ void __noreturn cpu_die_early(void)
 	rcutree_report_cpu_dead();
 
 	if (IS_ENABLED(CONFIG_HOTPLUG_CPU)) {
-		update_cpu_boot_status(CPU_KILL_ME);
+		update_cpu_boot_status(cpu, CPU_KILL_ME);
 		__cpu_try_die(cpu);
 	}
 
-	update_cpu_boot_status(CPU_STUCK_IN_KERNEL);
+	update_cpu_boot_status(cpu, CPU_STUCK_IN_KERNEL);
 
 	cpu_park_loop();
 }
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index 0f4a28b87469..6b8a3245f393 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -72,7 +72,7 @@ void verify_cpu_asid_bits(void)
 		 */
 		pr_crit("CPU%d: smaller ASID size(%u) than boot CPU (%u)\n",
 				smp_processor_id(), asid, asid_bits);
-		cpu_panic_kernel();
+		cpu_panic_kernel(smp_processor_id());
 	}
 }
 
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Jun 18 02:24:44 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 18 Jun 2026 17:24:44 +0800
Subject: [PATCH v2 4/4] arm64: Add HOTPLUG_PARALLEL support for secondary CPUs
In-Reply-To: <20260618092444.1316336-1-ruanjinjie@huawei.com>
References: <20260618092444.1316336-1-ruanjinjie@huawei.com>
Message-ID: <20260618092444.1316336-5-ruanjinjie@huawei.com>

Support for parallel secondary CPU bringup is already utilized by x86,
MIPS, and RISC-V. This patch brings this capability to the arm64
architecture.

Rework the global `secondary_data` accessed during early boot into
a per-CPU array `cpu_boot_data` to allow secondary CPUs to boot
in parallel.

And reuse `__cpu_logical_map` array in the early boot code in head.S
to resolve each secondary CPU's logical ID concurrently.

To fully enable HOTPLUG_PARALLEL, this patch implements:
1) An arm64-specific arch_cpuhp_init_parallel_bringup() handler.
2) An arm64-specific arch_cpuhp_kick_ap_alive() handler.
3) Callbacks to cpuhp_ap_sync_alive() inside secondary_start_kernel().

Tested natively with ATF on QEMU arm64 virt machine with 64 cores
and also tested with KVM arm64 guest with 128 vCPUs.

Bringup Time Comparison (ms, lower is better):

|     Platform			   | Baseline|   P=0   |   P=1  | Delta(%)|
| -------------------------------- | ------- | ------- | ------ | ------- |
| 128 vCPUs KVM (256-core HIP09)   | 1921.5  | 1895.9  | 2776.9 | -44.52% |
| 48 vCPUs KVM (64-core Cortex-A72)| 3644.7  | 3883.6  | 4406.3 | -20.9%  |
| 64-core ATF QEMU		   | 2075.8  | 2080.7  | 1653.4 | 20.34%  |
| 192-core server(HIP12)	   | 14619.2 | 14619.1 | 8589.4 | 41.21%  |
| 32-core board			   | 2776.5  | 2881.0  | 1045.0 | 62.36%  |

Tested-by: Michael Kelley <mhklinux at outlook.com>
Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/Kconfig              |  1 +
 arch/arm64/include/asm/smp.h    | 11 ++++++++++
 arch/arm64/kernel/asm-offsets.c |  4 ++++
 arch/arm64/kernel/head.S        | 36 +++++++++++++++++++++++++++++++++
 arch/arm64/kernel/smp.c         | 33 ++++++++++++++++++++++++++++++
 5 files changed, 85 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9091c67e1cc2..8735e9d8ed13 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -113,6 +113,7 @@ config ARM64
 	select CPUMASK_OFFSTACK if NR_CPUS > 256
 	select DCACHE_WORD_ACCESS
 	select HAVE_EXTRA_IPI_TRACEPOINTS
+	select HOTPLUG_PARALLEL if SMP && HOTPLUG_CPU
 	select DYNAMIC_FTRACE if FUNCTION_TRACER
 	select DMA_BOUNCE_UNALIGNED_KMALLOC
 	select DMA_DIRECT_REMAP
diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h
index e2151a01731f..30025030489c 100644
--- a/arch/arm64/include/asm/smp.h
+++ b/arch/arm64/include/asm/smp.h
@@ -92,7 +92,14 @@ struct secondary_data {
 	long status;
 };
 
+#ifdef CONFIG_HOTPLUG_PARALLEL
+static_assert((sizeof(struct secondary_data) & (sizeof(struct secondary_data) - 1)) == 0,
+	      "secondary_data size must be a power of 2 for assembly lsl assembly!");
+
+extern struct secondary_data cpu_boot_data[NR_CPUS];
+#else
 extern struct secondary_data secondary_data;
+#endif
 extern long __early_cpu_boot_status;
 extern void secondary_entry(void);
 
@@ -124,7 +131,11 @@ static inline void __noreturn cpu_park_loop(void)
 
 static inline void update_cpu_boot_status(unsigned int cpu, int val)
 {
+#ifdef CONFIG_HOTPLUG_PARALLEL
+	WRITE_ONCE(cpu_boot_data[cpu].status, val);
+#else
 	WRITE_ONCE(secondary_data.status, val);
+#endif
 	/* Ensure the visibility of the status update */
 	dsb(ishst);
 }
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index b6367ff3a49c..0a0aa965dbb4 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -11,6 +11,7 @@
 #include <linux/arm_sdei.h>
 #include <linux/sched.h>
 #include <linux/ftrace.h>
+#include <linux/log2.h>
 #include <linux/kexec.h>
 #include <linux/mm.h>
 #include <linux/kvm_host.h>
@@ -97,6 +98,9 @@ int main(void)
   BLANK();
 #endif
   DEFINE(CPU_BOOT_TASK,		offsetof(struct secondary_data, task));
+#ifdef CONFIG_HOTPLUG_PARALLEL
+  DEFINE(SECONDARY_DATA_SHIFT,	ilog2(sizeof(struct secondary_data)));
+#endif
   BLANK();
   DEFINE(FTR_OVR_VAL_OFFSET,	offsetof(struct arm64_ftr_override, val));
   DEFINE(FTR_OVR_MASK_OFFSET,	offsetof(struct arm64_ftr_override, mask));
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 87a822e5c4ca..000ab1acf7c5 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -12,6 +12,7 @@
 #include <linux/linkage.h>
 #include <linux/init.h>
 #include <linux/pgtable.h>
+#include <linux/threads.h>
 
 #include <asm/asm_pointer_auth.h>
 #include <asm/assembler.h>
@@ -378,6 +379,33 @@ alternative_else_nop_endif
 	br	x8
 SYM_FUNC_END(secondary_startup)
 
+#ifdef CONFIG_HOTPLUG_PARALLEL
+	/*
+	 * Convert the physical MPIDR of the current secondary CPU
+	 * to its logical CPUID by traversing __cpu_logical_map
+	 * in parallel.
+	 */
+	.macro	mpidr_to_cpuid, mpidr, cpuid, tmp1, tmp2
+	mov_q	\tmp1, MPIDR_HWID_BITMASK
+	and	\mpidr, \mpidr, \tmp1
+
+	adr_l	\tmp1, __cpu_logical_map
+	mov	\cpuid, #0
+.Lfind_cpuid\@:
+	ldr	\tmp2, [\tmp1, \cpuid, lsl #3]
+	cmp	\tmp2, #-1
+	b.eq	.Lnext_cpu\@
+	cmp	\tmp2, \mpidr
+	b.eq	.Lfound_cpuid\@
+.Lnext_cpu\@:
+	add	\cpuid, \cpuid, #1
+	cmp	\cpuid, #NR_CPUS
+	b.ne	.Lfind_cpuid\@
+	b	__secondary_too_slow
+.Lfound_cpuid\@:
+	.endm
+#endif
+
 	.text
 SYM_FUNC_START_LOCAL(__secondary_switched)
 	mov	x0, x20
@@ -391,7 +419,15 @@ SYM_FUNC_START_LOCAL(__secondary_switched)
 	msr	vbar_el1, x5
 	isb
 
+#ifdef CONFIG_HOTPLUG_PARALLEL
+	mrs	x0, mpidr_el1
+	mpidr_to_cpuid mpidr=x0, cpuid=x2, tmp1=x1, tmp2=x3
+
+	adr_l	x0, cpu_boot_data
+	add	x0, x0, x2, lsl #SECONDARY_DATA_SHIFT
+#else
 	adr_l	x0, secondary_data
+#endif
 	ldr	x2, [x0, #CPU_BOOT_TASK]
 	cbz	x2, __secondary_too_slow
 
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 52edabc13d51..f7562c38d724 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -61,6 +61,11 @@
  * where to place its SVC stack
  */
 struct secondary_data secondary_data;
+
+#ifdef CONFIG_HOTPLUG_PARALLEL
+struct secondary_data cpu_boot_data[NR_CPUS] ____cacheline_aligned;
+#endif
+
 /* Number of CPUs which aren't online, but looping in kernel text. */
 static int cpus_stuck_in_kernel;
 
@@ -106,8 +111,30 @@ static int boot_secondary(unsigned int cpu, struct task_struct *idle)
 	return -EOPNOTSUPP;
 }
 
+#ifndef CONFIG_HOTPLUG_PARALLEL
 static DECLARE_COMPLETION(cpu_running);
+#endif
+
+#ifdef CONFIG_HOTPLUG_PARALLEL
+extern const struct cpu_operations smp_spin_table_ops;
+
+/* Establish whether parallel bringup can be supported. */
+bool __init arch_cpuhp_init_parallel_bringup(void)
+{
+	int cpu = smp_processor_id();
+	const struct cpu_operations *ops = get_cpu_ops(cpu);
 
+	return ops && ops != &smp_spin_table_ops;
+}
+
+int arch_cpuhp_kick_ap_alive(unsigned int cpu, struct task_struct *tidle)
+{
+	cpu_boot_data[cpu].task = tidle;
+	update_cpu_boot_status(cpu, CPU_MMU_OFF);
+
+	return boot_secondary(cpu, tidle);
+}
+#else
 int __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
 	int ret;
@@ -172,6 +199,7 @@ int __cpu_up(unsigned int cpu, struct task_struct *idle)
 
 	return -EIO;
 }
+#endif /* CONFIG_HOTPLUG_PARALLEL */
 
 static void init_gic_priority_masking(void)
 {
@@ -223,6 +251,9 @@ asmlinkage notrace void secondary_start_kernel(void)
 	 * fail to come online.
 	 */
 	check_local_cpu_capabilities();
+#ifdef CONFIG_HOTPLUG_PARALLEL
+	cpuhp_ap_sync_alive();
+#endif
 	rcutree_report_cpu_starting(cpu);
 
 	ops = get_cpu_ops(cpu);
@@ -254,7 +285,9 @@ asmlinkage notrace void secondary_start_kernel(void)
 					 read_cpuid_id());
 	update_cpu_boot_status(cpu, CPU_BOOT_SUCCESS);
 	set_cpu_online(cpu, true);
+#ifndef CONFIG_HOTPLUG_PARALLEL
 	complete(&cpu_running);
+#endif
 
 	/*
 	 * Secondary CPUs enter the kernel with all DAIF exceptions masked.
-- 
2.34.1



From ruanjinjie at huawei.com  Thu Jun 18 02:24:43 2026
From: ruanjinjie at huawei.com (Jinjie Ruan)
Date: Thu, 18 Jun 2026 17:24:43 +0800
Subject: [PATCH v2 3/4] arm64: smp: Defer RCU reporting until after local CPU capability checks
In-Reply-To: <20260618092444.1316336-1-ruanjinjie@huawei.com>
References: <20260618092444.1316336-1-ruanjinjie@huawei.com>
Message-ID: <20260618092444.1316336-4-ruanjinjie@huawei.com>

To support HOTPLUG_PARALLEL on arm64, and to prevent a potential deadlock
on the control CPU, check_local_cpu_capabilities() must be executed
before cpuhp_ap_sync_alive(). This ensures that if an early capability
mismatch occurs and the AP invokes cpu_die_early(), the control CPU
can detect the boot timeout and proceed, rather than hanging
indefinitely.

Furthermore, under parallel bringup, cpuhp_ap_sync_alive() must be called
before rcutree_report_cpu_starting(). This sequence prevents a false
RCU CPU Stall Warning caused by the prolonged spin-waiting/busy-waiting
required during the AP synchronization process.

	GICv3: CPU1: using allocated LPI pending table @0x0000000104160000
	CPU1: Booted secondary processor 0x0000000001 [0x410fd082]
	rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
	rcu:     2-O..!: (2 GPs behind) idle=0004/1/0x4000000000000000 softirq=0/0 fqs=2625
	rcu:     3-O..!: (2 GPs behind) idle=0004/1/0x4000000000000000 softirq=0/0 fqs=2625
	rcu:     (detected by 0, t=5252 jiffies, g=-1187, q=1 ncpus=16)
	rcu: Offline CPU 2 blocking current GP.
	rcu: Offline CPU 3 blocking current GP.

To avoid suspicious RCU usage, commit ce3d31ad3cac ("arm64/smp: Move
rcu_cpu_starting() earlier") move rcutree_report_cpu_starting() earlier
which is before check_local_cpu_capabilities().

But For parallel bringup, the order should be as following:

	secondary_start_kernel()
	    -> check_local_cpu_capabilities()
	       -> cpu_die_early()
	    -> cpuhp_ap_sync_alive()
	    -> rcutree_report_cpu_starting()

And this required order forces standard printk/pr_* statements inside
check_local_cpu_capabilities() to execute while the secondary CPU is still
marked as offline to RCU, triggering a lockdep "suspicious RCU usage" splat
due to console semaphore operations.

So converting early capability logging and failure paths to printk_deferred().
This pushes the logs into the lockless ringbuffer without triggering console
locks or RCU validation on the offline CPU, resolving the lockdep splat while
preserving critical error messages and the strictly required initialization
order.

Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
---
 arch/arm64/kernel/cpufeature.c | 20 ++++++++++----------
 arch/arm64/kernel/smp.c        |  4 ++--
 arch/arm64/mm/context.c        |  2 +-
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 0552202702bf..a5e0bc4d383b 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -3546,7 +3546,7 @@ static void update_cpu_capabilities(u16 scope_mask)
 		 * system capabilities are finalised.
 		 */
 		if (!match_all && caps->desc && !caps->cpus)
-			pr_info("detected: %s\n", caps->desc);
+			printk_deferred(KERN_INFO "detected: %s\n", caps->desc);
 
 		__set_bit(caps->capability, system_cpucaps);
 
@@ -3669,7 +3669,7 @@ static void verify_local_cpu_caps(u16 scope_mask)
 	}
 
 	if (i < ARM64_NCAPS) {
-		pr_crit("CPU%d: Detected conflict for capability %d (%s), System: %d, CPU: %d\n",
+		printk_deferred(KERN_CRIT "CPU%d: Detected conflict for capability %d (%s), System: %d, CPU: %d\n",
 			smp_processor_id(), caps->capability,
 			caps->desc, system_has_cap, cpu_has_cap);
 
@@ -3697,7 +3697,7 @@ __verify_local_elf_hwcaps(const struct arm64_cpu_capabilities *caps)
 
 	for (; caps->matches; caps++)
 		if (cpus_have_elf_hwcap(caps) && !caps->matches(caps, SCOPE_LOCAL_CPU)) {
-			pr_crit("CPU%d: missing HWCAP: %s\n",
+			printk_deferred(KERN_CRIT "CPU%d: missing HWCAP: %s\n",
 					smp_processor_id(), caps->desc);
 			cpu_die_early();
 		}
@@ -3716,7 +3716,7 @@ static void verify_sve_features(void)
 	unsigned long cpacr = cpacr_save_enable_kernel_sve();
 
 	if (vec_verify_vq_map(ARM64_VEC_SVE)) {
-		pr_crit("CPU%d: SVE: vector length support mismatch\n",
+		printk_deferred(KERN_CRIT "CPU%d: SVE: vector length support mismatch\n",
 			smp_processor_id());
 		cpu_die_early();
 	}
@@ -3729,7 +3729,7 @@ static void verify_sme_features(void)
 	unsigned long cpacr = cpacr_save_enable_kernel_sme();
 
 	if (vec_verify_vq_map(ARM64_VEC_SME)) {
-		pr_crit("CPU%d: SME: vector length support mismatch\n",
+		printk_deferred(KERN_CRIT "CPU%d: SME: vector length support mismatch\n",
 			smp_processor_id());
 		cpu_die_early();
 	}
@@ -3754,7 +3754,7 @@ static void verify_hyp_capabilities(void)
 	safe_vmid_bits = get_vmid_bits(safe_mmfr1);
 	vmid_bits = get_vmid_bits(mmfr1);
 	if (vmid_bits < safe_vmid_bits) {
-		pr_crit("CPU%d: VMID width mismatch\n", smp_processor_id());
+		printk_deferred(KERN_CRIT "CPU%d: VMID width mismatch\n", smp_processor_id());
 		cpu_die_early();
 	}
 
@@ -3763,7 +3763,7 @@ static void verify_hyp_capabilities(void)
 				ID_AA64MMFR0_EL1_PARANGE_SHIFT);
 	ipa_max = id_aa64mmfr0_parange_to_phys_shift(parange);
 	if (ipa_max < get_kvm_ipa_limit()) {
-		pr_crit("CPU%d: IPA range mismatch\n", smp_processor_id());
+		printk_deferred(KERN_CRIT "CPU%d: IPA range mismatch\n", smp_processor_id());
 		cpu_die_early();
 	}
 }
@@ -3776,7 +3776,7 @@ static void verify_mpam_capabilities(void)
 
 	if (FIELD_GET(ID_AA64PFR0_EL1_MPAM_MASK, cpu_idr) !=
 	    FIELD_GET(ID_AA64PFR0_EL1_MPAM_MASK, sys_idr)) {
-		pr_crit("CPU%d: MPAM version mismatch\n", smp_processor_id());
+		printk_deferred(KERN_CRIT "CPU%d: MPAM version mismatch\n", smp_processor_id());
 		cpu_die_early();
 	}
 
@@ -3784,7 +3784,7 @@ static void verify_mpam_capabilities(void)
 	sys_idr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1);
 	if (FIELD_GET(MPAMIDR_EL1_HAS_HCR, cpu_idr) !=
 	    FIELD_GET(MPAMIDR_EL1_HAS_HCR, sys_idr)) {
-		pr_crit("CPU%d: Missing MPAM HCR\n", smp_processor_id());
+		printk_deferred(KERN_CRIT "CPU%d: Missing MPAM HCR\n", smp_processor_id());
 		cpu_die_early();
 	}
 
@@ -3793,7 +3793,7 @@ static void verify_mpam_capabilities(void)
 	sys_partid_max = FIELD_GET(MPAMIDR_EL1_PARTID_MAX, sys_idr);
 	sys_pmg_max = FIELD_GET(MPAMIDR_EL1_PMG_MAX, sys_idr);
 	if (cpu_partid_max < sys_partid_max || cpu_pmg_max < sys_pmg_max) {
-		pr_crit("CPU%d: MPAM PARTID/PMG max values are mismatched\n", smp_processor_id());
+		printk_deferred(KERN_CRIT "CPU%d: MPAM PARTID/PMG max values are mismatched\n", smp_processor_id());
 		cpu_die_early();
 	}
 }
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index 6bc90ee4820a..52edabc13d51 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -215,7 +215,6 @@ asmlinkage notrace void secondary_start_kernel(void)
 	if (system_uses_irq_prio_masking())
 		init_gic_priority_masking();
 
-	rcutree_report_cpu_starting(cpu);
 	trace_hardirqs_off();
 
 	/*
@@ -224,6 +223,7 @@ asmlinkage notrace void secondary_start_kernel(void)
 	 * fail to come online.
 	 */
 	check_local_cpu_capabilities();
+	rcutree_report_cpu_starting(cpu);
 
 	ops = get_cpu_ops(cpu);
 	if (ops->cpu_postboot)
@@ -404,7 +404,7 @@ void __noreturn cpu_die_early(void)
 {
 	int cpu = smp_processor_id();
 
-	pr_crit("CPU%d: will not boot\n", cpu);
+	printk_deferred(KERN_CRIT "CPU%d: will not boot\n", cpu);
 
 	/* Mark this CPU absent */
 	set_cpu_present(cpu, 0);
diff --git a/arch/arm64/mm/context.c b/arch/arm64/mm/context.c
index 6b8a3245f393..9b5ab56aad5a 100644
--- a/arch/arm64/mm/context.c
+++ b/arch/arm64/mm/context.c
@@ -70,7 +70,7 @@ void verify_cpu_asid_bits(void)
 		 * We cannot decrease the ASID size at runtime, so panic if we support
 		 * fewer ASID bits than the boot CPU.
 		 */
-		pr_crit("CPU%d: smaller ASID size(%u) than boot CPU (%u)\n",
+		printk_deferred(KERN_CRIT "CPU%d: smaller ASID size(%u) than boot CPU (%u)\n",
 				smp_processor_id(), asid, asid_bits);
 		cpu_panic_kernel(smp_processor_id());
 	}
-- 
2.34.1



From guoren at kernel.org  Thu Jun 18 02:51:34 2026
From: guoren at kernel.org (Guo Ren)
Date: Thu, 18 Jun 2026 17:51:34 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <e051d822-d0be-4a88-ba86-ec9b5905fd1e@iscas.ac.cn>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org> <7c490aeb-a3d9-4fe9-81de-f9662577851d@iscas.ac.cn>
 <CAJF2gTQ+-gpvUDtOh99aKP2-iDJy3MYOWti9k2Ntd0-J0MXqxQ@mail.gmail.com> <e051d822-d0be-4a88-ba86-ec9b5905fd1e@iscas.ac.cn>
Message-ID: <CAJF2gTRH6x78A3J5HJ5kUM47aDv8R0yFr8LRP+7jiLX4GL3ssg@mail.gmail.com>

Hi Vivian,

As noted in the RISC-V IOMMU Specification, Chapter 6:
> Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses ? first to the high half and second to the low half ? were performed.

Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
not clearly defined in the current ratified RISC-V IOMMU
specification. To handle this correctly, the Linux RISC-V IOMMU driver
should fall back to 32-bit MMIO accesses when reading 64-bit registers
(e.g., performance counters). The behavior of 32-bit MMIO accesses is
more precisely defined in the RISC-V IOMMU specification.

Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
MMIO) based on the current ratified RISC-V IOMMU specification, and
this driver does not appear to benefit from 64-bit MMIO access either.
Performance is fundamentally constrained by bus latency; assuming that
simply reducing the number of accesses will improve performance is an
oversimplification that ignores the underlying hardware
characteristics.

Hi Zhang,

The hardware targeted by the 32-bit MMIO access in your patch is
precisely the kind that deserves the official ACPI HID RSCV0004 and
Devicetree compatible string (riscv,iommu). It is rather the hardware
that supports only 64-bit MMIO access ? whose atomicity is explicitly
left as UNSPECIFIED by the RISC-V IOMMU specification ? that should be
relegated to a non-standard ACPI ID. That is what truly constitutes
poor hardware design.

I will consistently support your position of adopting 32-bit MMIO
access in this patch, and will advocate for making it the default
behavior in the Linux RISC-V IOMMU driver, as it better aligns with
the intent of the RISC-V IOMMU specification.

--
Best Regards
 Guo Ren

On Thu, Jun 18, 2026 at 3:33?PM Vivian Wang <wangruikang at iscas.ac.cn> wrote:
>
> On 6/18/26 11:45, Guo Ren wrote:
> > On Thu, Jun 18, 2026 at 11:20?AM Vivian Wang <wangruikang at iscas.ac.cn> wrote:
> >> On 6/15/26 20:38, Guo Ren wrote:
> >>> Hi Zhanpeng Zhang,
> >>>
> >>> I noticed you posted a similar fix recently. However, I had already
> >>> submitted a similar solution back in September 2025 [1]. It would be
> >>> great if you could review it. A few concerns with the current patch:
> >>>
> >>> 1. Using spin_lock_irqsave in such a small semantic structure is
> >>> unnecessary. IRQ protection should be provided by the higher-level
> >>> IOMMU driver interfaces. Many existing call sites already handle IRQ
> >>> disabling, so adding it here feels redundant and adds avoidable
> >>> overhead.
> >>>
> >>> 2. More critically, the RISCV_IOMMU_32BIT_ACCESS Kconfig option is
> >>> problematic. According to the RISC-V IOMMU specification (Software
> >>> Guidelines, ?Reading and writing IOMMU registers?):
> >>>
> >>>> Registers that are 64-bit wide may be accessed using either a 32-bit
> >>>> or a 64-bit access.
> >>> This clearly requires that any hardware supporting 64-bit MMIO access
> >>> must also support 32-bit MMIO access. Therefore, the IOMMU driver should
> >>> be built on a 32-bit access base for maximum hardware compatibility.
> >> I agree that the driver should be build with 32-bit accesses to support
> >> these hardware. However there's one minor thing that I want to propose
> >> regarding this, for the sake of clarity:
> >>
> >> RISC-V IOMMU implementations that do not support 64-bit accesses are not
> >> fully compliant with the RISC-V IOMMU specification and should not use
> >> the standard RISC-V identifiers, namely:
> >>
> >> - Devicetree compatible riscv,iommu
> >> - ACPI HID RSCV0004
> >>
> >> This, in my opinion, is not only the right thing to do (not claiming to
> >> be standard hardware without actually being standard hardware), but also
> >> saves a lot of trouble for operating system developers (yes, there are
> >> RISC-V operating systems other than Linux out there), since invalid IO
> >> accesses usually manifest as mysterious access faults (that would
> >> usually suggest an incorrect IOMMU address), or worse, system hangs.
> >>
> >> I would appreciate if the hardware vendors shipping 32-bit-access-only
> >> IOMMUs would consider this.
> >>
> >> Vivian "dramforever" Wang
> >>
> > 32-bit MMIO access is explicitly supported by the RISC-V IOMMU
> > specification and is a valid choice (64-bit MMIO access is optional).
>
> Hmm... I think it's optional in software but not optional in hardware,
> but the specs are not super clear on this. I've opened a GitHub issue to
> ask:
>
>     https://github.com/riscv-non-isa/riscv-iommu/issues/765
>
> > 64-bit MMIO access is not "free" ? it consumes additional interconnect
> > hardware resources.
> >
> > Could you elaborate on the concrete benefit of using 64-bit MMIO
> > access in this driver, for these non-PMU registers? A clear
> > justification would help evaluate whether the trade-off is worthwhile.
> >
> >
>


From wangruikang at iscas.ac.cn  Thu Jun 18 03:01:43 2026
From: wangruikang at iscas.ac.cn (Vivian Wang)
Date: Thu, 18 Jun 2026 18:01:43 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <CAJF2gTRH6x78A3J5HJ5kUM47aDv8R0yFr8LRP+7jiLX4GL3ssg@mail.gmail.com>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org>
 <7c490aeb-a3d9-4fe9-81de-f9662577851d@iscas.ac.cn>
 <CAJF2gTQ+-gpvUDtOh99aKP2-iDJy3MYOWti9k2Ntd0-J0MXqxQ@mail.gmail.com>
 <e051d822-d0be-4a88-ba86-ec9b5905fd1e@iscas.ac.cn>
 <CAJF2gTRH6x78A3J5HJ5kUM47aDv8R0yFr8LRP+7jiLX4GL3ssg@mail.gmail.com>
Message-ID: <ce3c80ae-fca0-4728-a93c-778dcbab32f2@iscas.ac.cn>


On 6/18/26 17:51, Guo Ren wrote:
> Hi Vivian,
>
> As noted in the RISC-V IOMMU Specification, Chapter 6:
>> Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses ? first to the high half and second to the low half ? were performed.
> Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> not clearly defined in the current ratified RISC-V IOMMU
> specification. To handle this correctly, the Linux RISC-V IOMMU driver
> should fall back to 32-bit MMIO accesses when reading 64-bit registers
> (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> more precisely defined in the RISC-V IOMMU specification.
>
> Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> MMIO) based on the current ratified RISC-V IOMMU specification, and
> this driver does not appear to benefit from 64-bit MMIO access either.
> Performance is fundamentally constrained by bus latency; assuming that
> simply reducing the number of accesses will improve performance is an
> oversimplification that ignores the underlying hardware
> characteristics.

Just as a clarification, I had never said that the driver *should* use
64-bit accesses. In fact, I said:

    I agree that the driver should be build with 32-bit accesses to support
    these hardware.

Perhaps I wasn't clear enough. I meant that I agree that the RISC-V
IOMMU driver should use 32-bit accesses. At *no* point had I claimed
that 64-bit accesses are better.

> Hi Zhang,
>
> The hardware targeted by the 32-bit MMIO access in your patch is
> precisely the kind that deserves the official ACPI HID RSCV0004 and
> Devicetree compatible string (riscv,iommu). It is rather the hardware
> that supports only 64-bit MMIO access ? whose atomicity is explicitly
> [...]

IOMMU Hardware that supports only 64-bit MMIO access for 8-byte
registers has never come up in this discussion. If they ever show up
we'll talk about them then.

Vivian "dramforever" Wang



From namcao at linutronix.de  Thu Jun 18 03:10:00 2026
From: namcao at linutronix.de (Nam Cao)
Date: Thu, 18 Jun 2026 12:10:00 +0200
Subject: [PATCH] riscv: Add kCFI type prefix to unaligned copy routines
In-Reply-To: <20260618081252.work.711-kees@kernel.org>
References: <20260618081252.work.711-kees@kernel.org>
Message-ID: <877bnwtb0n.fsf@yellow.woof>

Kees Cook <kees at kernel.org> writes:
> __riscv_copy_words_unaligned() and __riscv_copy_bytes_unaligned() are
> called indirectly through function pointers from measure_cycles() (via
> compare_unaligned_access()) during the boot-time unaligned-access
> probe. Under kCFI, an indirect call checks the type id stored in the
> word immediately preceding the callee against the type id of the
> function-pointer type at the call site. These two routines are defined
> with SYM_FUNC_START(), which emits no __cfi_ prefix, so the check reads
> the alignment padding ahead of the function (zero) instead of a type id
> and traps:

This has already been fixed by commit f2abc305aa93f ("riscv: Define
__riscv_copy_{,vec_}{words,bytes}_unaligned() using SYM_TYPED_FUNC_START")

Nam


From p.zabel at pengutronix.de  Thu Jun 18 03:13:36 2026
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Thu, 18 Jun 2026 12:13:36 +0200
Subject: [PATCH 2/2] reset: spacemit: k3: fix USB2 ahb reset
In-Reply-To: <20260518-06-clk-reset-usb-fix-v1-2-14fc235e692b@kernel.org>
References: <20260518-06-clk-reset-usb-fix-v1-0-14fc235e692b@kernel.org>
	 <20260518-06-clk-reset-usb-fix-v1-2-14fc235e692b@kernel.org>
Message-ID: <0af47f978c8a93165cbdbe4ca88a186acbb35157.camel@pengutronix.de>

On Mo, 2026-05-18 at 02:58 +0000, Yixun Lan wrote:
> According to SpacemiT K3's updated docs, the USB2 ahb reset and USB2 bus
> clock enable bit was wrongly swapped, the correct one should be:
> 
> Register : APMU_USB_CLK_RES_CTRL
> bit[1]   : usb2_port_bus_clk_en
> bit[0]   : usb2_port_ahb_rstn
> 
> Fixes: a0e0c2f8c5f3 ("reset: spacemit: k3: Decouple composite reset lines")
> Reported-by: Junzhong Pan <panjunzhong at linux.spacemit.com>
> Signed-off-by: Yixun Lan <dlan at kernel.org>

Reviewed-by: Philipp Zabel <p.zabel at pengutronix.de>

regards
Philipp


From p.zabel at pengutronix.de  Thu Jun 18 03:14:00 2026
From: p.zabel at pengutronix.de (Philipp Zabel)
Date: Thu, 18 Jun 2026 12:14:00 +0200
Subject: [PATCH 2/2] reset: spacemit: k3: fix USB2 ahb reset
In-Reply-To: <20260526132335-GKB3748271@kernel.org>
References: <20260518-06-clk-reset-usb-fix-v1-0-14fc235e692b@kernel.org>
	 <20260518-06-clk-reset-usb-fix-v1-2-14fc235e692b@kernel.org>
	 <20260526132335-GKB3748271@kernel.org>
Message-ID: <8882bc976c1d6e1de253780a4102a3a5cd5df7bf.camel@pengutronix.de>

On Di, 2026-05-26 at 13:23 +0000, Yixun Lan wrote:
> Hi Philipp Zabel,
> 
> On 02:58 Mon 18 May     , Yixun Lan wrote:
> > According to SpacemiT K3's updated docs, the USB2 ahb reset and USB2 bus
> > clock enable bit was wrongly swapped, the correct one should be:
> > 
> > Register : APMU_USB_CLK_RES_CTRL
> > bit[1]   : usb2_port_bus_clk_en
> > bit[0]   : usb2_port_ahb_rstn
> > 
> > Fixes: a0e0c2f8c5f3 ("reset: spacemit: k3: Decouple composite reset lines")
> > Reported-by: Junzhong Pan <panjunzhong at linux.spacemit.com>
> > Signed-off-by: Yixun Lan <dlan at kernel.org>
> 
> Would be it ok from your side to queue this patch for v7.2 cycle?

Yes, I'll queue it for v7.2.

regards
Philipp


From miguel.ojeda.sandonis at gmail.com  Thu Jun 18 03:40:14 2026
From: miguel.ojeda.sandonis at gmail.com (Miguel Ojeda)
Date: Thu, 18 Jun 2026 12:40:14 +0200
Subject: [PATCH v4 3/3] rust: clk: use 'kernel vertical style' for imports
In-Reply-To: <20260618-clk-type-state-v4-3-8be082786080@collabora.com>
References: <20260618-clk-type-state-v4-0-8be082786080@collabora.com> <20260618-clk-type-state-v4-3-8be082786080@collabora.com>
Message-ID: <CANiq72myoVT9npyaB0pVvbJ1v9ELzw68uAvSoAkdJJX2MJQ=kA@mail.gmail.com>

On Thu, Jun 18, 2026 at 5:48?AM Daniel Almeida
<daniel.almeida at collabora.com> wrote:
>
> +            Result, //

Since you import the prelude, I think you can take the change to
remove e.g. this one.

>          /// use kernel::error::Result;

>      /// use kernel::error::Result;

>      /// use kernel::error::Result;

>          /// use kernel::error::Result;

Similarly, the prelude is imported in doctests by default.

Cheers,
Miguel


From will at kernel.org  Thu Jun 18 05:21:08 2026
From: will at kernel.org (Will Deacon)
Date: Thu, 18 Jun 2026 13:21:08 +0100
Subject: [PATCH RFC 3/3] arm64: Add HOTPLUG_PARALLEL support for
 secondary CPUs
In-Reply-To: <e96a2579-c010-4198-a2a3-6ba35b14aef0@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
 <20260611133809.3854977-4-ruanjinjie@huawei.com>
 <SN6PR02MB41575306521E6223561F476FD4182@SN6PR02MB4157.namprd02.prod.outlook.com>
 <e96a2579-c010-4198-a2a3-6ba35b14aef0@huawei.com>
Message-ID: <ajPitENEHWa8lDfC@willie-the-truck>

Hi Jinjie,

On Mon, Jun 15, 2026 at 04:51:48PM +0800, Jinjie Ruan wrote:
> On 6/12/2026 11:45 PM, Michael Kelley wrote:
> > From: Jinjie Ruan <ruanjinjie at huawei.com> Sent: Thursday, June 11, 2026 6:38 AM
> >>
> >> Support for parallel secondary CPU bringup is already utilized by x86,
> >> MIPS, and RISC-V. This patch brings this capability to the arm64
> >> architecture.
> >>
> >> Rework the global `secondary_data` accessed during early boot into
> >> a per-CPU array. This array maps logical CPU IDs to MPIDR_EL1 values,
> >> enabling the early boot code in head.S to resolve each secondary CPU's
> >> logical ID concurrently.
> >>
> >> To fully enable HOTPLUG_PARALLEL, this patch implements:
> >> 1) An arm64-specific arch_cpuhp_kick_ap_alive() handler.
> >> 2) Callbacks to cpuhp_ap_sync_alive() inside secondary_start_kernel().
> >>
> >> Successfully tested on QEMU ARM64 virt machine (KVM on, 128 vCPUs).
> >>
> >> |     test kernel	   | secondary CPUs boot time |
> >> |  ---------------------   |	--------------------  |
> >> |   Without this patch     |		155.672	      |
> >> |   cpuhp.parallel=0	   |		62.897	      |
> >> |   cpuhp.parallel=1	   |		166.703	      |
> > 
> > The last two rows seem mixed up. I would expect parallel=0 to
> > result in a longer boot time.
> 
> Hi, Michael,
> 
> The results are correct and not mixed up.
> 
> Compared to the original non?HOTPLUG_PARALLEL approach, the advantage of
> cpuhp.parallel=0 lies in its use of cpu_relax(`yield` on arm64) instead
> of the wait_for_completion_timeout() mechanism (which may cause sleep
> and context switching). This significantly reduces the overhead of VM
> exits and context switches in a KVM guest, thereby cutting the secondary
> CPU boot time by more than half.

I don't think that's a particularly compelling reason to enable this for
arm64, in all honesty. The yield instruction typically doesn't do
anything on actual arm64 silicon, so this probably means that you're
introducing busy-loops which tend to be bad for power and scalability.

I implemented this a while ago [1] but didn't manage to see much in terms
of performance improvement and so I didn't bother to send the patches out
after talking about it at KVM forum [2]. However, as mentioned at the end
of that talk, it _is_ still useful for confidential VMs using PSCI so
let me dust off my old series and send it out to see what you think.

It relies on PSCI v0.2, which means we don't need the NR_CPUS size array
for secondary_data and I also have some support for error handling (it
doesn't look like you handle __early_cpu_boot_status properly).

It looks like I could include your first patch, though!

Will

[1] https://git.kernel.org/pub/scm/linux/kernel/git/will/linux.git/log/?h=cpu-hotplug
[2] https://www.youtube.com/watch?v=Q6kOshnnQuE


From emil.renner.berthing at canonical.com  Thu Jun 18 06:11:36 2026
From: emil.renner.berthing at canonical.com (Emil Renner Berthing)
Date: Thu, 18 Jun 2026 08:11:36 -0500
Subject: [PATCH v2] rcu: Use an intermediate irq_work to start process_srcu()
In-Reply-To: <20260320222916.19987-1-boqun@kernel.org>
References: <ab2yd35rm6OgZUmb@gpd4> <20260320222916.19987-1-boqun@kernel.org>
Message-ID: <CAJM55Z-hiNDuu5UwoBe7m0wq+_WJrRY0cwopALUgpG+r3ixj8g@mail.gmail.com>

Quoting Boqun Feng (2026-03-20 23:29:16)
> Since commit c27cea4416a3 ("rcu: Re-implement RCU Tasks Trace in terms
> of SRCU-fast") we switched to SRCU in BPF. However as BPF instrument can
> happen basically everywhere (including where a scheduler lock is held),
> call_srcu() now needs to avoid acquiring scheduler lock because
> otherwise it could cause deadlock [1]. Fix this by following what the
> previous RCU Tasks Trace did: using an irq_work to delay the queuing of
> the work to start process_srcu().
>
> [boqun: Apply Joel's feedback]
> [boqun: Apply Andrea's test feedback]
>
> Reported-by: Andrea Righi <arighi at nvidia.com>
> Closes: https://lore.kernel.org/all/abjzvz_tL_siV17s at gpd4/
> Fixes: commit c27cea4416a3 ("rcu: Re-implement RCU Tasks Trace in terms of SRCU-fast")
> Link: https://lore.kernel.org/rcu/3c4c5a29-24ea-492d-aeee-e0d9605b4183 at nvidia.com/ [1]
> Suggested-by: Zqiang <qiang.zhang at linux.dev>
> Tested-by: Andrea Righi <arighi at nvidia.com>
> Signed-off-by: Boqun Feng <boqun at kernel.org>

Thanks for the patch, which is now upstream as
7c405fb3279b ("rcu: Use an intermediate irq_work to start process_srcu()")

Unfortunately it seems to halt booting on the Allwinner D1 single-core RISC-V
SoC both on the 7.0 and 7.1 kernels:

https://esmil.dk/d1-7.0.txt
https://esmil.dk/d1-7.1.txt

Reverting this patch seems to fix the issue although it then breaks when loading
modules which is can be fixed by reverting:
d6e152d905bd ("clockevents: Prevent timer interrupt starvation")

This might be a side-effect of reverting this patch though.

We'd really like to continue support for this SoC on the 7.0 kernel, but since
this patch is a bugfix just shippping the revert doesn't sound appealing.
So some guidance would be much appreciated, thanks!

/Emil


From david.laight.linux at gmail.com  Thu Jun 18 06:36:34 2026
From: david.laight.linux at gmail.com (David Laight)
Date: Thu, 18 Jun 2026 14:36:34 +0100
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <CAJF2gTRH6x78A3J5HJ5kUM47aDv8R0yFr8LRP+7jiLX4GL3ssg@mail.gmail.com>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
	<20260615123821.373248-1-guoren@kernel.org>
	<7c490aeb-a3d9-4fe9-81de-f9662577851d@iscas.ac.cn>
	<CAJF2gTQ+-gpvUDtOh99aKP2-iDJy3MYOWti9k2Ntd0-J0MXqxQ@mail.gmail.com>
	<e051d822-d0be-4a88-ba86-ec9b5905fd1e@iscas.ac.cn>
	<CAJF2gTRH6x78A3J5HJ5kUM47aDv8R0yFr8LRP+7jiLX4GL3ssg@mail.gmail.com>
Message-ID: <20260618143634.7f3dd6c5@pumpkin>

On Thu, 18 Jun 2026 17:51:34 +0800
Guo Ren <guoren at kernel.org> wrote:

> Hi Vivian,
> 
> As noted in the RISC-V IOMMU Specification, Chapter 6:
> > Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses ? first to the high half and second to the low half ? were performed.  
> 
> Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> not clearly defined in the current ratified RISC-V IOMMU
> specification. To handle this correctly, the Linux RISC-V IOMMU driver
> should fall back to 32-bit MMIO accesses when reading 64-bit registers
> (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> more precisely defined in the RISC-V IOMMU specification.
> 
> Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> MMIO) based on the current ratified RISC-V IOMMU specification, and
> this driver does not appear to benefit from 64-bit MMIO access either.
> Performance is fundamentally constrained by bus latency; assuming that
> simply reducing the number of accesses will improve performance is an
> oversimplification that ignores the underlying hardware
> characteristics.

If the bus latency is significant it is almost certainly worth using
memory accesses to avoid re-reading the hi register.

Something like this might work:

static volatile u32 hi_prev, lo_prev;

	u32 hi = read_reg_hi();
	u32 lo = read_reg_lo();

	if (lo <= lo_prev || hi != hi_prev) {
		u32 hi_tmp = read_reg_hi;
		if (hi_tmp != hi) {
			hi = hi_tmp;
			lo = 0;
		}
		lo_prev = ~0u;
		hi_prev = hi;
	}
	lo_prev = lo;
	return (u64)hi << 32 | lo;

It shouldn't need any locking but the accesses do need to be ordered.

	David




From andriy.shevchenko at linux.intel.com  Thu Jun 18 07:13:46 2026
From: andriy.shevchenko at linux.intel.com (Andy Shevchenko)
Date: Thu, 18 Jun 2026 16:13:46 +0200
Subject: [PATCH v1 1/1] i2c: microchip-corei2c: Use generic definitions for bus frequencies
Message-ID: <20260618141346.3241286-1-andriy.shevchenko@linux.intel.com>

Since we have generic definitions for bus frequencies, let's use them.

Signed-off-by: Andy Shevchenko <andriy.shevchenko at linux.intel.com>
---
 drivers/i2c/busses/i2c-microchip-corei2c.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/i2c/busses/i2c-microchip-corei2c.c b/drivers/i2c/busses/i2c-microchip-corei2c.c
index c8599733633e..330e150ef6d5 100644
--- a/drivers/i2c/busses/i2c-microchip-corei2c.c
+++ b/drivers/i2c/busses/i2c-microchip-corei2c.c
@@ -565,10 +565,10 @@ static int mchp_corei2c_probe(struct platform_device *pdev)
 				       &idev->bus_clk_rate);
 	if (ret || !idev->bus_clk_rate) {
 		dev_info(&pdev->dev, "default to 100kHz\n");
-		idev->bus_clk_rate = 100000;
+		idev->bus_clk_rate = I2C_MAX_STANDARD_MODE_FREQ;
 	}
 
-	if (idev->bus_clk_rate > 400000)
+	if (idev->bus_clk_rate > I2C_MAX_FAST_MODE_FREQ)
 		return dev_err_probe(&pdev->dev, -EINVAL,
 				     "clock-frequency too high: %d\n",
 				     idev->bus_clk_rate);
-- 
2.50.1



From tglx at kernel.org  Thu Jun 18 08:17:03 2026
From: tglx at kernel.org (Thomas Gleixner)
Date: Thu, 18 Jun 2026 17:17:03 +0200
Subject: [PATCH RFC 1/3] cpu/hotplug: Introduce
 CONFIG_PARALLEL_SMT_PRIMARY_FIRST
In-Reply-To: <20260611133809.3854977-2-ruanjinjie@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
 <20260611133809.3854977-2-ruanjinjie@huawei.com>
Message-ID: <87a4srdgk0.ffs@fw13>

On Thu, Jun 11 2026 at 21:38, Jinjie Ruan wrote:

> During parallel CPU bringup, x86 requires primary SMT threads to boot
> first to avoid siblings stopping during microcode updates. This constraint
> is architecture-specific and unnecessary for other platforms
> like arm64.
>
> Introduce CONFIG_PARALLEL_SMT_PRIMARY_FIRST to decouple this constraint.
> Platforms requiring this temporal order (e.g., x86) can select it
> in Kconfig. Other architectures (e.g., arm64) can leave it unselected
> to entirely bypass the SMT branch via the preprocessor.
>
> Signed-off-by: Jinjie Ruan <ruanjinjie at huawei.com>
> ---
>  arch/Kconfig       | 4 ++++
>  arch/mips/Kconfig  | 1 +
>  arch/riscv/Kconfig | 1 +
>  arch/x86/Kconfig   | 1 +
>  kernel/cpu.c       | 6 +++++-
>  5 files changed, 12 insertions(+), 1 deletion(-)
>
> diff --git a/arch/Kconfig b/arch/Kconfig
> index e86880045158..0365d2df2659 100644
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -102,6 +102,10 @@ config HOTPLUG_PARALLEL
>  	bool
>  	select HOTPLUG_SPLIT_STARTUP
>  
> +config PARALLEL_SMT_PRIMARY_FIRST

Proper namespaces are overrated, right?

All related options start with HOTPLUG_....

> +	bool
> +	depends on HOTPLUG_PARALLEL
> +
>  config GENERIC_IRQ_ENTRY
>  	bool
>  
> diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
> index 4364f3dba688..84e11ac0cf71 100644
> --- a/arch/mips/Kconfig
> +++ b/arch/mips/Kconfig
> @@ -642,6 +642,7 @@ config EYEQ
>  	select MIPS_CPU_SCACHE
>  	select MIPS_GIC
>  	select MIPS_L1_CACHE_SHIFT_7
> +	select PARALLEL_SMT_PRIMARY_FIRST if HOTPLUG_PARALLEL
>  	select PCI_DRIVERS_GENERIC
>  	select SMP_UP if SMP
>  	select SWAP_IO_SPACE
> diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
> index d235396c4514..0cc49aecc841 100644
> --- a/arch/riscv/Kconfig
> +++ b/arch/riscv/Kconfig
> @@ -210,6 +210,7 @@ config RISCV
>  	select OF
>  	select OF_EARLY_FLATTREE
>  	select OF_IRQ
> +	select PARALLEL_SMT_PRIMARY_FIRST if HOTPLUG_PARALLEL

Why does RISCV need this? It does not select HOTPLUG_SMT to begin with.

> +#ifdef CONFIG_PARALLEL_SMT_PRIMARY_FIRST
>  #ifdef CONFIG_HOTPLUG_SMT

More #ifdeffery is better, right?

>  static inline bool cpuhp_smt_aware(void)
>  {
> @@ -1811,7 +1812,8 @@ static inline const struct cpumask *cpuhp_get_primary_thread_mask(void)
>  {
>  	return cpu_none_mask;
>  }
> -#endif
> +#endif /* CONFIG_HOTPLUG_SMT */
> +#endif /* CONFIG_PARALLEL_SMT_PRIMARY_FIRST */
>  
>  bool __weak arch_cpuhp_init_parallel_bringup(void)
>  {
> @@ -1837,6 +1839,7 @@ static bool __init cpuhp_bringup_cpus_parallel(unsigned int ncpus)
>  	if (!__cpuhp_parallel_bringup)
>  		return false;
>  
> +#ifdef CONFIG_PARALLEL_SMT_PRIMARY_FIRST

Seriously?

>  	if (cpuhp_smt_aware()) {
>  		const struct cpumask *pmask = cpuhp_get_primary_thread_mask();
>  		static struct cpumask tmp_mask __initdata;
> @@ -1857,6 +1860,7 @@ static bool __init cpuhp_bringup_cpus_parallel(unsigned int ncpus)
>  		cpumask_andnot(&tmp_mask, mask, pmask);
>  		mask = &tmp_mask;
>  	}
> +#endif /* CONFIG_PARALLEL_SMT_PRIMARY_FIRST */

Something simple like the uncompiled below should just work, no?

---
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -102,6 +102,10 @@ config HOTPLUG_PARALLEL
 	bool
 	select HOTPLUG_SPLIT_STARTUP
 
+config HOTPLUG_PARALLEL_SMT
+	bool
+	select HOTPLUG_PARALLEL
+
 config GENERIC_IRQ_ENTRY
 	bool
 
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -657,7 +657,7 @@ config EYEQ
 	select USB_UHCI_BIG_ENDIAN_DESC if CPU_BIG_ENDIAN
 	select USB_UHCI_BIG_ENDIAN_MMIO if CPU_BIG_ENDIAN
 	select USE_OF
-	select HOTPLUG_PARALLEL if HOTPLUG_CPU
+	select HOTPLUG_PARALLEL_SMT if HOTPLUG_CPU
 	help
 	  Select this to build a kernel supporting EyeQ SoC from Mobileye.
 
@@ -2295,7 +2295,6 @@ config MIPS_CPS
 	select MIPS_CM
 	select MIPS_CPS_PM if HOTPLUG_CPU
 	select SMP
-	select HOTPLUG_SMT if HOTPLUG_PARALLEL
 	select HOTPLUG_CORE_SYNC_DEAD if HOTPLUG_CPU
 	select SYNC_R4K if (CEVT_R4K || CSRC_R4K)
 	select SYS_SUPPORTS_HOTPLUG_CPU
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -304,7 +304,7 @@ config X86
 	select HAVE_USER_RETURN_NOTIFIER
 	select HAVE_GENERIC_VDSO
 	select VDSO_GETRANDOM			if X86_64
-	select HOTPLUG_PARALLEL			if SMP && X86_64
+	select HOTPLUG_PARALLEL_SMT		if SMP && X86_64
 	select HOTPLUG_SMT			if SMP
 	select HOTPLUG_SPLIT_STARTUP		if SMP && X86_32
 	select IRQ_FORCED_THREADING
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -1792,7 +1792,7 @@ static int __init parallel_bringup_parse
 }
 early_param("cpuhp.parallel", parallel_bringup_parse_param);
 
-#ifdef CONFIG_HOTPLUG_SMT
+#ifdef CONFIG_HOTPLUG_PARALLEL_SMT
 static inline bool cpuhp_smt_aware(void)
 {
 	return cpu_smt_max_threads > 1;


From boqun at kernel.org  Thu Jun 18 08:30:10 2026
From: boqun at kernel.org (Boqun Feng)
Date: Thu, 18 Jun 2026 08:30:10 -0700
Subject: [PATCH v2] rcu: Use an intermediate irq_work to start
 process_srcu()
In-Reply-To: <CAJM55Z-hiNDuu5UwoBe7m0wq+_WJrRY0cwopALUgpG+r3ixj8g@mail.gmail.com>
References: <ab2yd35rm6OgZUmb@gpd4>
 <20260320222916.19987-1-boqun@kernel.org>
 <CAJM55Z-hiNDuu5UwoBe7m0wq+_WJrRY0cwopALUgpG+r3ixj8g@mail.gmail.com>
Message-ID: <ajQPAk_ALP-84obp@MacBook-0RXW5>

On Thu, Jun 18, 2026 at 08:11:36AM -0500, Emil Renner Berthing wrote:
> Quoting Boqun Feng (2026-03-20 23:29:16)
> > Since commit c27cea4416a3 ("rcu: Re-implement RCU Tasks Trace in terms
> > of SRCU-fast") we switched to SRCU in BPF. However as BPF instrument can
> > happen basically everywhere (including where a scheduler lock is held),
> > call_srcu() now needs to avoid acquiring scheduler lock because
> > otherwise it could cause deadlock [1]. Fix this by following what the
> > previous RCU Tasks Trace did: using an irq_work to delay the queuing of
> > the work to start process_srcu().
> >
> > [boqun: Apply Joel's feedback]
> > [boqun: Apply Andrea's test feedback]
> >
> > Reported-by: Andrea Righi <arighi at nvidia.com>
> > Closes: https://lore.kernel.org/all/abjzvz_tL_siV17s at gpd4/
> > Fixes: commit c27cea4416a3 ("rcu: Re-implement RCU Tasks Trace in terms of SRCU-fast")
> > Link: https://lore.kernel.org/rcu/3c4c5a29-24ea-492d-aeee-e0d9605b4183 at nvidia.com/ [1]
> > Suggested-by: Zqiang <qiang.zhang at linux.dev>
> > Tested-by: Andrea Righi <arighi at nvidia.com>
> > Signed-off-by: Boqun Feng <boqun at kernel.org>
> 
> Thanks for the patch, which is now upstream as
> 7c405fb3279b ("rcu: Use an intermediate irq_work to start process_srcu()")
> 
> Unfortunately it seems to halt booting on the Allwinner D1 single-core RISC-V
> SoC both on the 7.0 and 7.1 kernels:
> 

By "single-core", is it only one CPU in that system?

> https://esmil.dk/d1-7.0.txt
> https://esmil.dk/d1-7.1.txt
> 

>From the callstack,

[  243.002818] "echo 0 > /proc/sys/kernel/hung_task_timeout_secs" disables this message.
[  243.010681] task:kworker/0:0     state:D stack:0     pid:9     tgid:9     ppid:2      task_flags:0x4208060 flags:0x00000000
[  243.021858] Workqueue: device_link_wq device_link_release_fn
[  243.027587] Call Trace:
[  243.030079] [<ffffffff80745b66>] __schedule+0x232/0x530
[  243.035365] [<ffffffff80745e82>] schedule+0x1e/0x94
[  243.040298] [<ffffffff8074aa7a>] schedule_timeout+0x6e/0xa8
[  243.045929] [<ffffffff8004d6a0>] wakeup_preempt+0x8c/0x98
[  243.051380] [<ffffffff80746aee>] wait_for_completion+0x3a/0xb0
[  243.057267] [<ffffffff80087226>] __synchronize_srcu.part.0+0x4e/0x60
[  243.063712] [<ffffffff80084414>] rcu_tasks_get_gp_data+0xc/0x10
[  243.069699] [<ffffffff80490898>] device_link_release_fn+0x14/0x80
[  243.075850] [<ffffffff8003dbd0>] process_one_work+0xf8/0x1c8
[  243.081583] [<ffffffff8003e282>] worker_thread+0x11a/0x254
[  243.087127] [<ffffffff8003e164>] rescuer_thread+0x3a0/0x3a4
[  243.092755] [<ffffffff8003e164>] rescuer_thread+0x3a0/0x3a4
[  243.098381] [<ffffffff8004499e>] kthread+0xbe/0xe4
[  243.103231] [<ffffffff8001349e>] ret_from_fork_kernel+0x6/0xd0
[  243.109127] [<ffffffff800517a8>] schedule_tail+0x8/0xac
[  243.114410] [<ffffffff800448dc>] kthreads_online_cpu+0x0/0x4
[  243.120121] [<ffffffff8074be0a>] ret_from_fork_kernel_asm+0x12/0x18

I will guess for some reasons the irq_work was missed or the IPI never
happened. Is it possible for you to enable trace points ipi_send_cpu and
ipi_entry to get more information?

> Reverting this patch seems to fix the issue although it then breaks when loading
> modules which is can be fixed by reverting:
> d6e152d905bd ("clockevents: Prevent timer interrupt starvation")
> 
> This might be a side-effect of reverting this patch though.
> 

I'm not so sure about this, i.e. you might have *two* problems :(

Regards,
Boqun

> We'd really like to continue support for this SoC on the 7.0 kernel, but since
> this patch is a bugfix just shippping the revert doesn't sound appealing.
> So some guidance would be much appreciated, thanks!
> 
> /Emil


From namcao at linutronix.de  Thu Jun 18 08:31:31 2026
From: namcao at linutronix.de (Nam Cao)
Date: Thu, 18 Jun 2026 17:31:31 +0200
Subject: [PATCH 04/16] riscv: kprobes: Use generated instruction headers
In-Reply-To: <ajOezhejx7PcOw_x@blinky>
References: <20260407-riscv_insn_table-v1-0-54b4736a1e77@gmail.com>
 <20260407-riscv_insn_table-v1-4-54b4736a1e77@gmail.com>
 <87jys5egum.fsf@yellow.woof> <ajOezhejx7PcOw_x@blinky>
Message-ID: <87fr2jq2zw.fsf@yellow.woof>

Charlie Jenkins <thecharlesjenkins at gmail.com> writes:
> Since I was checking against the previous version it's not possible to
> do a straight one-to-one conversion to the kunit. I think it might be
> possible to do something similar but I will need to mess with that to
> determine a good way of doing it.

Perhaps not to the existing kunit, but a new kunit which calls the
simulate_*() functions directly. Just an idea.

Nam


From tglx at kernel.org  Thu Jun 18 08:49:53 2026
From: tglx at kernel.org (Thomas Gleixner)
Date: Thu, 18 Jun 2026 17:49:53 +0200
Subject: [PATCH RFC 3/3] arm64: Add HOTPLUG_PARALLEL support for
 secondary CPUs
In-Reply-To: <20260611133809.3854977-4-ruanjinjie@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
 <20260611133809.3854977-4-ruanjinjie@huawei.com>
Message-ID: <877bnvdf1a.ffs@fw13>

On Thu, Jun 11 2026 at 21:38, Jinjie Ruan wrote:
> --- a/arch/arm64/Kconfig
> +++ b/arch/arm64/Kconfig
> @@ -113,6 +113,7 @@ config ARM64
>  	select CPUMASK_OFFSTACK if NR_CPUS > 256
>  	select DCACHE_WORD_ACCESS
>  	select HAVE_EXTRA_IPI_TRACEPOINTS
> +	select HOTPLUG_PARALLEL if SMP && HOTPLUG_CPU

Why do you tie that to HOTPLUG_CPU? HOTPLUG_CPU lets you unplug/plug
CPUs at runtime, but if its disabled then a SMP system still has to
bring up the APs. So why should that fall back to the existing variant?

> +#ifdef CONFIG_HOTPLUG_PARALLEL
> +extern struct secondary_data cpu_boot_data[NR_CPUS];
> +#endif
> +
>  extern struct secondary_data secondary_data;
>  extern long __early_cpu_boot_status;
>  extern void secondary_entry(void);
> @@ -124,7 +128,11 @@ static inline void __noreturn cpu_park_loop(void)
>  
>  static inline void update_cpu_boot_status(unsigned int cpu, int val)
>  {
> +#ifdef CONFIG_HOTPLUG_PARALLEL
> +	WRITE_ONCE(cpu_boot_data[cpu].status, val);
> +#else
>  	WRITE_ONCE(secondary_data.status, val);
> +#endif

You're really a great fan of #ifdefs, right?

Just convert it over to the parallel mode unconditionally and get rid of
the existing cruft.

>  	/*
>  	 * TTBR0 is only used for the identity mapping at this stage. Make it
>  	 * point to zero page to avoid speculatively fetching new entries.
> @@ -254,7 +276,9 @@ asmlinkage notrace void secondary_start_kernel(void)
>  					 read_cpuid_id());
>  	update_cpu_boot_status(cpu, CPU_BOOT_SUCCESS);
>  	set_cpu_online(cpu, true);
> +#ifndef CONFIG_HOTPLUG_PARALLEL
>  	complete(&cpu_running);
> +#endif

Just for the record. You can get rid of this completion w/o PARALLEL
hotplug by selecting HOTPLUG_SPLIT_STARTUP and implementing the
kick/sync parts.
  
Thanks,

        tglx


From tglx at kernel.org  Thu Jun 18 08:53:41 2026
From: tglx at kernel.org (Thomas Gleixner)
Date: Thu, 18 Jun 2026 17:53:41 +0200
Subject: [PATCH RFC 3/3] arm64: Add HOTPLUG_PARALLEL support for
 secondary CPUs
In-Reply-To: <4588efb4-e757-4ca7-9197-025b67ca9ef6@huawei.com>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
 <20260611133809.3854977-4-ruanjinjie@huawei.com>
 <SN6PR02MB41575306521E6223561F476FD4182@SN6PR02MB4157.namprd02.prod.outlook.com>
 <4588efb4-e757-4ca7-9197-025b67ca9ef6@huawei.com>
Message-ID: <874iizdeuy.ffs@fw13>

On Mon, Jun 15 2026 at 17:57, Jinjie Ruan wrote:
> On 6/12/2026 11:45 PM, Michael Kelley wrote:
>
> - Default (no patch): Slowest HVC64 handling (126??s), highest WFx count
> (85k), and most total VM?exits.
>
> - cpuhp.parallel=1: HVC64 latency improved to 78??s (close to
> cpuhp.parallel=0), but IRQ exits increased dramatically (12.9k, 2.7?
> that of `cpuhp.parallel=0`), accounting for 95% of event time and
> becoming the new bottleneck.
>
> - cpuhp.parallel=0: Fastest HVC64 (69??s), lowest IRQ exits (4.8k), and
> lowest total samples, delivering the best overall boot performance.
>
> Therefor, `cpuhp.parallel=1` reduces HVC cost but suffers from a massive
> increase in IRQ exits, while `cpuhp.parallel=0` avoids this interrupt
> storm and therefore performs best in a KVM guest.

What's the cause for having this massive interrupt exit rate in parallel
mode? Just because parallel does not give a useful explanation.

Thanks,

        tglx


From conor at kernel.org  Thu Jun 18 09:37:06 2026
From: conor at kernel.org (Conor Dooley)
Date: Thu, 18 Jun 2026 17:37:06 +0100
Subject: [PATCH v4 1/3] dt-bindings: riscv: describe Svadu as disabled at
 boot
In-Reply-To: <20260618064406.14508-2-cuiyunhui@bytedance.com>
References: <20260618064406.14508-1-cuiyunhui@bytedance.com>
 <20260618064406.14508-2-cuiyunhui@bytedance.com>
Message-ID: <20260618-speech-whacking-852cd7142f3d@spud>

Acked-by: Conor Dooley <conor.dooley at microchip.com>
pw-bot: not-applicable
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-riscv/attachments/20260618/35d1cec9/attachment.sig>

From guoren at kernel.org  Thu Jun 18 09:40:47 2026
From: guoren at kernel.org (Guo Ren)
Date: Fri, 19 Jun 2026 00:40:47 +0800
Subject: [PATCH v1] iommu/riscv: Support 32-bit register accesses
In-Reply-To: <20260618143634.7f3dd6c5@pumpkin>
References: <20260615064855.90316-1-zhangzhanpeng.jasper@bytedance.com>
 <20260615123821.373248-1-guoren@kernel.org> <7c490aeb-a3d9-4fe9-81de-f9662577851d@iscas.ac.cn>
 <CAJF2gTQ+-gpvUDtOh99aKP2-iDJy3MYOWti9k2Ntd0-J0MXqxQ@mail.gmail.com>
 <e051d822-d0be-4a88-ba86-ec9b5905fd1e@iscas.ac.cn> <CAJF2gTRH6x78A3J5HJ5kUM47aDv8R0yFr8LRP+7jiLX4GL3ssg@mail.gmail.com>
 <20260618143634.7f3dd6c5@pumpkin>
Message-ID: <CAJF2gTQqnpHPrE-df_kDZ-Y9g7sSfTQco3jKKnDzkuJfOEKmxQ@mail.gmail.com>

On Thu, Jun 18, 2026 at 9:36?PM David Laight
<david.laight.linux at gmail.com> wrote:
>
> On Thu, 18 Jun 2026 17:51:34 +0800
> Guo Ren <guoren at kernel.org> wrote:
>
> > Hi Vivian,
> >
> > As noted in the RISC-V IOMMU Specification, Chapter 6:
> > > Whether an 8-byte access to an IOMMU register is single-copy atomic is UNSPECIFIED, and such an access may appear, internally to the IOMMU, as if two separate 4-byte accesses ? first to the high half and second to the low half ? were performed.
> >
> > Therefore, the atomicity of 64-bit MMIO accesses is UNSPECIFIED and
> > not clearly defined in the current ratified RISC-V IOMMU
> > specification. To handle this correctly, the Linux RISC-V IOMMU driver
> > should fall back to 32-bit MMIO accesses when reading 64-bit registers
> > (e.g., performance counters). The behavior of 32-bit MMIO accesses is
> > more precisely defined in the RISC-V IOMMU specification.
> >
> > Thus, many hardware vendors implement 32-bit MMIO (rather than 64-bit
> > MMIO) based on the current ratified RISC-V IOMMU specification, and
> > this driver does not appear to benefit from 64-bit MMIO access either.
> > Performance is fundamentally constrained by bus latency; assuming that
> > simply reducing the number of accesses will improve performance is an
> > oversimplification that ignores the underlying hardware
> > characteristics.
>
> If the bus latency is significant it is almost certainly worth using
> memory accesses to avoid re-reading the hi register.
>
> Something like this might work:
>
> static volatile u32 hi_prev, lo_prev;
>
>         u32 hi = read_reg_hi();
>         u32 lo = read_reg_lo();
>
>         if (lo <= lo_prev || hi != hi_prev) {
>                 u32 hi_tmp = read_reg_hi;
>                 if (hi_tmp != hi) {
>                         hi = hi_tmp;
>                         lo = 0;
>                 }
>                 lo_prev = ~0u;
>                 hi_prev = hi;
>         }
>         lo_prev = lo;
>         return (u64)hi << 32 | lo;
>
> It shouldn't need any locking but the accesses do need to be ordered.
Thank you for the suggestion. However, I believe this feedback is more
relevant to the RISC-V IOMMU HPM patchset [1], as no counter registers
are involved in the current patchset. That said, the idea of improving
the hi-lo-hi slow-path mechanism to better handle high-latency
hardware scenarios is well taken and worth discussing in the
appropriate thread.
[1]: https://lore.kernel.org/linux-riscv/20260208063848.3547817-2-zong.li at sifive.com/

P.S. The hardware I have at hand exhibits very low interconnect
latency. And I have never observed the slow path where hi_tmp != hi
being triggered ? my approach was to remove the retry mechanism
directly in 32-bit mmio mode and run stress tests to check whether
perf stat produced incorrect results. That said, I may have simply
been lucky instead of hw guarantee.

-- 
Best Regards
 Guo Ren


From kees at kernel.org  Thu Jun 18 09:54:11 2026
From: kees at kernel.org (Kees Cook)
Date: Thu, 18 Jun 2026 09:54:11 -0700
Subject: [PATCH] riscv: Add kCFI type prefix to unaligned copy routines
In-Reply-To: <877bnwtb0n.fsf@yellow.woof>
References: <20260618081252.work.711-kees@kernel.org> <877bnwtb0n.fsf@yellow.woof>
Message-ID: <9E1CFDD7-018E-4945-B261-0D46B355A369@kernel.org>



On June 18, 2026 3:10:00 AM PDT, Nam Cao <namcao at linutronix.de> wrote:
>Kees Cook <kees at kernel.org> writes:
>> __riscv_copy_words_unaligned() and __riscv_copy_bytes_unaligned() are
>> called indirectly through function pointers from measure_cycles() (via
>> compare_unaligned_access()) during the boot-time unaligned-access
>> probe. Under kCFI, an indirect call checks the type id stored in the
>> word immediately preceding the callee against the type id of the
>> function-pointer type at the call site. These two routines are defined
>> with SYM_FUNC_START(), which emits no __cfi_ prefix, so the check reads
>> the alignment padding ahead of the function (zero) instead of a type id
>> and traps:
>
>This has already been fixed by commit f2abc305aa93f ("riscv: Define
>__riscv_copy_{,vec_}{words,bytes}_unaligned() using SYM_TYPED_FUNC_START")

Ah-ha! Great. I need to update my tree, it seems. :)

-Kees

-- 
Kees Cook


From gary at garyguo.net  Thu Jun 18 10:03:37 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:37 +0100
Subject: [PATCH 00/10] rust: driver: use pointers instead of indices for ID
 info
Message-ID: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>

Most C drivers use a pointer (and cast to kernel_ulong_t) for driver_data
fields in device_id. Rust code currently does not do this, but rather use
indices. These indices then needs to be translated to `&IdInfo` separately
and this is by a side table.

This leads to open-coded ACPI/OF handling in driver.rs, which is not
desirable. Convert the code to use pointers (or rather, static references)
instead.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
Gary Guo (10):
      rust: driver: remove `IdTable::id`
      rust: driver: simplify `IdArray::new_without_index`
      rust: pci: use `Option<&IdInfo>` for device ID info
      rust: net/phy: remove expansion from doc
      rust: driver: centralize device ID handling
      rust: driver: remove `$module_table_name` from `module_device_table`
      rust: driver: store pointers in `DeviceId`
      rust: driver: remove open-coded matching logic
      rust: driver: remove duplicate ID table
      RFC: rust: driver: support map-like syntax for ID table

 drivers/cpufreq/rcpufreq_dt.rs        |   1 -
 drivers/gpu/drm/nova/driver.rs        |   1 -
 drivers/gpu/drm/tyr/driver.rs         |   1 -
 drivers/gpu/nova-core/driver.rs       |   3 +-
 drivers/pwm/pwm_th1520.rs             |   1 -
 rust/kernel/acpi.rs                   |  14 +--
 rust/kernel/auxiliary.rs              |  18 +--
 rust/kernel/device_id.rs              | 205 +++++++++++++++++++---------------
 rust/kernel/driver.rs                 | 114 ++-----------------
 rust/kernel/i2c.rs                    |  26 ++---
 rust/kernel/net/phy.rs                |  66 +----------
 rust/kernel/of.rs                     |  14 +--
 rust/kernel/pci.rs                    |  24 ++--
 rust/kernel/platform.rs               |   5 +-
 rust/kernel/usb.rs                    |  18 +--
 samples/rust/rust_debugfs.rs          |   1 -
 samples/rust/rust_dma.rs              |   3 +-
 samples/rust/rust_driver_auxiliary.rs |   4 +-
 samples/rust/rust_driver_i2c.rs       |   3 -
 samples/rust/rust_driver_pci.rs       |  11 +-
 samples/rust/rust_driver_platform.rs  |   2 -
 samples/rust/rust_driver_usb.rs       |   1 -
 samples/rust/rust_i2c_client.rs       |   2 -
 samples/rust/rust_soc.rs              |   2 -
 24 files changed, 166 insertions(+), 374 deletions(-)
---
base-commit: 4fa3f5fabb30bf00d7475d5a33459ea83d639bf9
change-id: 20260612-id_info-23eca472ccd8

Best regards,
--  
Gary Guo <gary at garyguo.net>



From gary at garyguo.net  Thu Jun 18 10:03:39 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:39 +0100
Subject: [PATCH 02/10] rust: driver: simplify `IdArray::new_without_index`
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-2-96af1e559ef9@garyguo.net>

This method can very easily construct the `IdArray` on its own without
delegating to `Self::build`. Doing so also simplifies the phy device table
macro because it does not need to construct tuples anymore.

This also allows simplification of `new` and `build` which removes the
`unsafe`.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 rust/kernel/device_id.rs | 64 ++++++++++++++++++++----------------------------
 rust/kernel/net/phy.rs   |  2 +-
 2 files changed, 28 insertions(+), 38 deletions(-)

diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index fbf6d8e6afb9..eeef3f5e7b63 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -73,19 +73,11 @@ pub struct IdArray<T: RawDeviceId, U, const N: usize> {
     id_infos: [U; N],
 }
 
-impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
     /// Creates a new instance of the array.
     ///
     /// The contents are derived from the given identifiers and context information.
-    ///
-    /// # Safety
-    ///
-    /// `data_offset` as `None` is always safe.
-    /// If `data_offset` is `Some(data_offset)`, then:
-    /// - `data_offset` must be the correct offset (in bytes) to the context/data field
-    ///   (e.g., the `driver_data` field) within the raw device ID structure.
-    /// - The field at `data_offset` must be correctly sized to hold a `usize`.
-    const unsafe fn build(ids: [(T, U); N], data_offset: Option<usize>) -> Self {
+    pub const fn new(ids: [(T, U); N]) -> Self {
         let mut raw_ids = [const { MaybeUninit::<T::RawType>::uninit() }; N];
         let mut infos = [const { MaybeUninit::uninit() }; N];
 
@@ -94,16 +86,14 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
             // SAFETY: by the safety requirement of `RawDeviceId`, we're guaranteed that `T` is
             // layout-wise compatible with `RawType`.
             raw_ids[i] = unsafe { core::mem::transmute_copy(&ids[i].0) };
-            if let Some(data_offset) = data_offset {
-                // SAFETY: by the safety requirement of this function, this would be effectively
-                // `raw_ids[i].driver_data = i;`.
-                unsafe {
-                    raw_ids[i]
-                        .as_mut_ptr()
-                        .byte_add(data_offset)
-                        .cast::<usize>()
-                        .write(i);
-                }
+            // SAFETY: by the safety requirement of `RawDeviceIdIndex`, this would be effectively
+            // `raw_ids[i].driver_data = i;`.
+            unsafe {
+                raw_ids[i]
+                    .as_mut_ptr()
+                    .byte_add(T::DRIVER_DATA_OFFSET)
+                    .cast::<usize>()
+                    .write(i);
             }
 
             // SAFETY: this is effectively a move: `infos[i] = ids[i].1`. We make a copy here but
@@ -127,32 +117,32 @@ impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
             id_infos: unsafe { core::mem::transmute_copy(&infos) },
         }
     }
+}
 
-    /// Creates a new instance of the array without writing index values.
-    ///
-    /// The contents are derived from the given identifiers and context information.
-    /// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead.
-    pub const fn new_without_index(ids: [(T, U); N]) -> Self {
-        // SAFETY: Calling `Self::build` with `offset = None` is always safe,
-        // because no raw memory writes are performed in this case.
-        unsafe { Self::build(ids, None) }
-    }
-
+impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
     /// Reference to the contained [`RawIdArray`].
     pub const fn raw_ids(&self) -> &RawIdArray<T, N> {
         &self.raw_ids
     }
 }
 
-impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
-    /// Creates a new instance of the array.
+impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
+    /// Creates a new instance of the array without writing index values.
     ///
     /// The contents are derived from the given identifiers and context information.
-    pub const fn new(ids: [(T, U); N]) -> Self {
-        // SAFETY: by the safety requirement of `RawDeviceIdIndex`,
-        // `T::DRIVER_DATA_OFFSET` is guaranteed to be the correct offset (in bytes) to
-        // a field within `T::RawType`.
-        unsafe { Self::build(ids, Some(T::DRIVER_DATA_OFFSET)) }
+    /// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead.
+    pub const fn new_without_index(ids: [T; N]) -> Self {
+        // SAFETY: `T` is layout-wise compatible with `T::RawType`, so is the array of them.
+        let raw_ids: [T::RawType; N] = unsafe { core::mem::transmute_copy(&ids) };
+        core::mem::forget(ids);
+
+        Self {
+            raw_ids: RawIdArray {
+                ids: raw_ids,
+                sentinel: MaybeUninit::zeroed(),
+            },
+            id_infos: [(); N],
+        }
     }
 }
 
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 3ca99db5cccf..2868e3a9e02c 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -868,7 +868,7 @@ macro_rules! module_phy_driver {
         const N: usize = $crate::module_phy_driver!(@count_devices $($dev),+);
 
         const TABLE: $crate::device_id::IdArray<$crate::net::phy::DeviceId, (), N> =
-            $crate::device_id::IdArray::new_without_index([ $(($dev,())),+, ]);
+            $crate::device_id::IdArray::new_without_index([ $($dev),+, ]);
 
         $crate::module_device_table!("mdio", phydev, TABLE);
     };

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:40 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:40 +0100
Subject: [PATCH 03/10] rust: pci: use `Option<&IdInfo>` for device ID info
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-3-96af1e559ef9@garyguo.net>

It is possible that `pci_device_id_any` will be passed to the driver, e.g.
`driver_override` is used on the device. Therefore, the driver must be able
to handle the case where `driver_data` is 0. Thus, update the `probe`
functions to get `Option`.

The current code cannot tell if the info does not exist or is the first
entry; however this will be achievable once the code is updated to use a
`&'static IdInfo` pointer instead of indices.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 drivers/gpu/nova-core/driver.rs       | 2 +-
 rust/kernel/pci.rs                    | 6 +++---
 samples/rust/rust_dma.rs              | 2 +-
 samples/rust/rust_driver_auxiliary.rs | 2 +-
 samples/rust/rust_driver_pci.rs       | 3 ++-
 5 files changed, 8 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 5738d4ac521b..5a5f0b63e0f3 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -70,7 +70,7 @@ impl pci::Driver for NovaCoreDriver {
 
     fn probe<'bound>(
         pdev: &'bound pci::Device<Core<'_>>,
-        _info: &'bound Self::IdInfo,
+        _info: Option<&'bound Self::IdInfo>,
     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
         pin_init::pin_init_scope(move || {
             dev_dbg!(pdev, "Probe Nova Core GPU driver.\n");
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 5071cae6543f..0e055e4df99e 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -113,7 +113,7 @@ extern "C" fn probe_callback(
         let info = T::ID_TABLE.info(id.index());
 
         from_result(|| {
-            let data = T::probe(pdev, info);
+            let data = T::probe(pdev, Some(info));
 
             pdev.as_ref().set_drvdata(data)?;
             Ok(0)
@@ -284,7 +284,7 @@ macro_rules! pci_device_table {
 ///
 ///     fn probe<'bound>(
 ///         _pdev: &'bound pci::Device<Core<'_>>,
-///         _id_info: &'bound Self::IdInfo,
+///         _id_info: Option<&'bound Self::IdInfo>,
 ///     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
 ///         Err(ENODEV)
 ///     }
@@ -313,7 +313,7 @@ pub trait Driver {
     /// attempt to initialize the device here.
     fn probe<'bound>(
         dev: &'bound Device<device::Core<'_>>,
-        id_info: &'bound Self::IdInfo,
+        id_info: Option<&'bound Self::IdInfo>,
     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound;
 
     /// PCI driver unbind.
diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
index 5046b4628d0e..9beb37275e0d 100644
--- a/samples/rust/rust_dma.rs
+++ b/samples/rust/rust_dma.rs
@@ -63,7 +63,7 @@ impl pci::Driver for DmaSampleDriver {
 
     fn probe<'bound>(
         pdev: &'bound pci::Device<Core<'_>>,
-        _info: &'bound Self::IdInfo,
+        _info: Option<&'bound Self::IdInfo>,
     ) -> impl PinInit<Self, Error> + 'bound {
         pin_init::pin_init_scope(move || {
             dev_info!(pdev, "Probe DMA test driver.\n");
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
index 2c1351040e45..73c63afc046a 100644
--- a/samples/rust/rust_driver_auxiliary.rs
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -79,7 +79,7 @@ impl pci::Driver for ParentDriver {
 
     fn probe<'bound>(
         pdev: &'bound pci::Device<Core<'_>>,
-        _info: &'bound Self::IdInfo,
+        _info: Option<&'bound Self::IdInfo>,
     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
         Ok(ParentData {
             // SAFETY: `ParentData` is the driver's private data, which is dropped when the
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 1aa8197d8698..5547dd704a1b 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -144,7 +144,7 @@ impl pci::Driver for SampleDriver {
 
     fn probe<'bound>(
         pdev: &'bound pci::Device<Core<'_>>,
-        info: &'bound Self::IdInfo,
+        info: Option<&'bound Self::IdInfo>,
     ) -> impl PinInit<Self::Data<'bound>, Error> + 'bound {
         let vendor = pdev.vendor_id();
         dev_dbg!(
@@ -153,6 +153,7 @@ fn probe<'bound>(
             vendor,
             pdev.device_id()
         );
+        let info = info.ok_or(ENODEV)?;
 
         pdev.enable_device_mem()?;
         pdev.set_master();

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:38 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:38 +0100
Subject: [PATCH 01/10] rust: driver: remove `IdTable::id`
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-1-96af1e559ef9@garyguo.net>

This is unused.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 rust/kernel/device_id.rs | 7 -------
 1 file changed, 7 deletions(-)

diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 8e9721446014..fbf6d8e6afb9 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -166,9 +166,6 @@ pub trait IdTable<T: RawDeviceId, U> {
     /// Obtain the pointer to the ID table.
     fn as_ptr(&self) -> *const T::RawType;
 
-    /// Obtain the pointer to the bus specific device ID from an index.
-    fn id(&self, index: usize) -> &T::RawType;
-
     /// Obtain the pointer to the driver-specific information from an index.
     fn info(&self, index: usize) -> &U;
 }
@@ -180,10 +177,6 @@ fn as_ptr(&self) -> *const T::RawType {
         core::ptr::from_ref(self).cast()
     }
 
-    fn id(&self, index: usize) -> &T::RawType {
-        &self.raw_ids.ids[index]
-    }
-
     fn info(&self, index: usize) -> &U {
         &self.id_infos[index]
     }

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:41 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:41 +0100
Subject: [PATCH 04/10] rust: net/phy: remove expansion from doc
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-4-96af1e559ef9@garyguo.net>

The expansion serves little purpose and it can easily diverge.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 rust/kernel/net/phy.rs | 56 --------------------------------------------------
 1 file changed, 56 deletions(-)

diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 2868e3a9e02c..965ecca7d55f 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -800,62 +800,6 @@ const fn as_int(&self) -> u32 {
 /// }
 /// # }
 /// ```
-///
-/// This expands to the following code:
-///
-/// ```ignore
-/// use kernel::net::phy::{self, DeviceId};
-/// use kernel::prelude::*;
-///
-/// struct Module {
-///     _reg: ::kernel::net::phy::Registration,
-/// }
-///
-/// module! {
-///     type: Module,
-///     name: "rust_sample_phy",
-///     authors: ["Rust for Linux Contributors"],
-///     description: "Rust sample PHYs driver",
-///     license: "GPL",
-/// }
-///
-/// struct PhySample;
-///
-/// #[vtable]
-/// impl phy::Driver for PhySample {
-///     const NAME: &'static CStr = c"PhySample";
-///     const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);
-/// }
-///
-/// const _: () = {
-///     static mut DRIVERS: [::kernel::net::phy::DriverVTable; 1] =
-///         [::kernel::net::phy::create_phy_driver::<PhySample>()];
-///
-///     impl ::kernel::Module for Module {
-///         fn init(module: &'static ::kernel::ThisModule) -> Result<Self> {
-///             let drivers = unsafe { &mut DRIVERS };
-///             let mut reg = ::kernel::net::phy::Registration::register(
-///                 module,
-///                 ::core::pin::Pin::static_mut(drivers),
-///             )?;
-///             Ok(Module { _reg: reg })
-///         }
-///     }
-/// };
-///
-/// const N: usize = 1;
-///
-/// const TABLE: ::kernel::device_id::IdArray<::kernel::net::phy::DeviceId, (), N> =
-///     ::kernel::device_id::IdArray::new_without_index([
-///         ::kernel::net::phy::DeviceId(
-///             ::kernel::bindings::mdio_device_id {
-///                 phy_id: 0x00000001,
-///                 phy_id_mask: 0xffffffff,
-///             }),
-///     ]);
-///
-/// ::kernel::module_device_table!("mdio", phydev, TABLE);
-/// ```
 #[macro_export]
 macro_rules! module_phy_driver {
     (@replace_expr $_t:tt $sub:expr) => {$sub};

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:42 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:42 +0100
Subject: [PATCH 05/10] rust: driver: centralize device ID handling
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-5-96af1e559ef9@garyguo.net>

Move the `IdArray` creation from individual buses to be handled by shared
code in `device_id.rs`.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 rust/kernel/acpi.rs      | 10 ++--------
 rust/kernel/auxiliary.rs | 10 ++--------
 rust/kernel/device_id.rs | 31 ++++++++++++++++++++++++++++++-
 rust/kernel/i2c.rs       | 10 ++--------
 rust/kernel/net/phy.rs   | 10 ++++------
 rust/kernel/of.rs        | 10 ++--------
 rust/kernel/pci.rs       | 10 ++--------
 rust/kernel/usb.rs       | 10 ++--------
 8 files changed, 46 insertions(+), 55 deletions(-)

diff --git a/rust/kernel/acpi.rs b/rust/kernel/acpi.rs
index 9b8efa623130..315f2f2af446 100644
--- a/rust/kernel/acpi.rs
+++ b/rust/kernel/acpi.rs
@@ -53,13 +53,7 @@ pub const fn new(id: &'static CStr) -> Self {
 /// Create an ACPI `IdTable` with an "alias" for modpost.
 #[macro_export]
 macro_rules! acpi_device_table {
-    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
-        const $table_name: $crate::device_id::IdArray<
-            $crate::acpi::DeviceId,
-            $id_info_type,
-            { $table_data.len() },
-        > = $crate::device_id::IdArray::new($table_data);
-
-        $crate::module_device_table!("acpi", $module_table_name, $table_name);
+    ($($tt:tt)*) => {
+        $crate::module_device_table!("acpi", $crate::acpi::DeviceId, $($tt)*);
     };
 }
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index c42928d5a239..59787c9bff26 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -181,14 +181,8 @@ fn index(&self) -> usize {
 /// Create a auxiliary `IdTable` with its alias for modpost.
 #[macro_export]
 macro_rules! auxiliary_device_table {
-    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
-        const $table_name: $crate::device_id::IdArray<
-            $crate::auxiliary::DeviceId,
-            $id_info_type,
-            { $table_data.len() },
-        > = $crate::device_id::IdArray::new($table_data);
-
-        $crate::module_device_table!("auxiliary", $module_table_name, $table_name);
+    ($($tt:tt)*) => {
+        $crate::module_device_table!("auxiliary", $crate::auxiliary::DeviceId, $($tt)*);
     };
 }
 
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index eeef3f5e7b63..0239f89d5f69 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -175,7 +175,36 @@ fn info(&self, index: usize) -> &U {
 /// Create device table alias for modpost.
 #[macro_export]
 macro_rules! module_device_table {
-    ($table_type: literal, $module_table_name:ident, $table_name:ident) => {
+    (
+        $table_type: literal, $device_id_ty: ty,
+        $table_name: ident, $module_table_name: ident, $id_info_type: ty,
+        [$(($id: expr, $info:expr $(,)?)),* $(,)?]
+    ) => {
+        const $table_name: $crate::device_id::IdArray<
+            $device_id_ty,
+            $id_info_type,
+            { <[$device_id_ty]>::len(&[$($id,)*]) },
+        > = $crate::device_id::IdArray::new([$(($id, $info),)*]);
+
+        $crate::module_device_table!($table_type, $module_table_name, $table_name);
+    };
+
+    // Case for no ID info.
+    (
+        $table_type: literal, $device_id_ty: ty,
+        $table_name: ident, $module_table_name: ident, @none,
+        [$($id: expr),* $(,)?]
+    ) => {
+        const $table_name: $crate::device_id::IdArray<
+            $device_id_ty,
+            (),
+            { <[$device_id_ty]>::len(&[$($id,)*]) },
+        > = $crate::device_id::IdArray::new_without_index([$($id),*]);
+
+        $crate::module_device_table!($table_type, $module_table_name, $table_name);
+    };
+
+    ($table_type: literal, $module_table_name: ident, $table_name:ident) => {
         #[rustfmt::skip]
         #[export_name =
             concat!("__mod_device_table__", line!(),
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 7655d61daac8..a7d9b88ae616 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -77,14 +77,8 @@ fn index(&self) -> usize {
 /// Create a I2C `IdTable` with its alias for modpost.
 #[macro_export]
 macro_rules! i2c_device_table {
-    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
-        const $table_name: $crate::device_id::IdArray<
-            $crate::i2c::DeviceId,
-            $id_info_type,
-            { $table_data.len() },
-        > = $crate::device_id::IdArray::new($table_data);
-
-        $crate::module_device_table!("i2c", $module_table_name, $table_name);
+    ($($tt:tt)*) => {
+        $crate::module_device_table!("i2c", $crate::i2c::DeviceId, $($tt)*);
     };
 }
 
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 965ecca7d55f..166572861e61 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -809,12 +809,10 @@ macro_rules! module_phy_driver {
     };
 
     (@device_table [$($dev:expr),+]) => {
-        const N: usize = $crate::module_phy_driver!(@count_devices $($dev),+);
-
-        const TABLE: $crate::device_id::IdArray<$crate::net::phy::DeviceId, (), N> =
-            $crate::device_id::IdArray::new_without_index([ $($dev),+, ]);
-
-        $crate::module_device_table!("mdio", phydev, TABLE);
+        $crate::module_device_table!(
+            "mdio", $crate::net::phy::DeviceId,
+            phydev, TABLE, @none, [$($dev),+]
+        );
     };
 
     (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => {
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
index 58b20c367f99..35aa6d36d309 100644
--- a/rust/kernel/of.rs
+++ b/rust/kernel/of.rs
@@ -53,13 +53,7 @@ pub const fn new(compatible: &'static CStr) -> Self {
 /// Create an OF `IdTable` with an "alias" for modpost.
 #[macro_export]
 macro_rules! of_device_table {
-    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
-        const $table_name: $crate::device_id::IdArray<
-            $crate::of::DeviceId,
-            $id_info_type,
-            { $table_data.len() },
-        > = $crate::device_id::IdArray::new($table_data);
-
-        $crate::module_device_table!("of", $module_table_name, $table_name);
+    ($($tt:tt)*) => {
+        $crate::module_device_table!("of", $crate::of::DeviceId, $($tt)*);
     };
 }
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 0e055e4df99e..34e07a53244d 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -245,14 +245,8 @@ fn index(&self) -> usize {
 /// Create a PCI `IdTable` with its alias for modpost.
 #[macro_export]
 macro_rules! pci_device_table {
-    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
-        const $table_name: $crate::device_id::IdArray<
-            $crate::pci::DeviceId,
-            $id_info_type,
-            { $table_data.len() },
-        > = $crate::device_id::IdArray::new($table_data);
-
-        $crate::module_device_table!("pci", $module_table_name, $table_name);
+    ($($tt:tt)*) => {
+        $crate::module_device_table!("pci", $crate::pci::DeviceId, $($tt)*);
     };
 }
 
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 7aff0c82d0af..154919ee1e19 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -254,14 +254,8 @@ fn index(&self) -> usize {
 /// Create a USB `IdTable` with its alias for modpost.
 #[macro_export]
 macro_rules! usb_device_table {
-    ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => {
-        const $table_name: $crate::device_id::IdArray<
-            $crate::usb::DeviceId,
-            $id_info_type,
-            { $table_data.len() },
-        > = $crate::device_id::IdArray::new($table_data);
-
-        $crate::module_device_table!("usb", $module_table_name, $table_name);
+    ($($tt:tt)*) => {
+        $crate::module_device_table!("usb", $crate::usb::DeviceId, $($tt)*);
     };
 }
 

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:43 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:43 +0100
Subject: [PATCH 06/10] rust: driver: remove `$module_table_name` from
 `module_device_table`
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-6-96af1e559ef9@garyguo.net>

Wrap the generated code in a `const _: ()` block to avoid symbol conflict.
This removes the need of creating a new identifier.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 drivers/cpufreq/rcpufreq_dt.rs        |  1 -
 drivers/gpu/drm/nova/driver.rs        |  1 -
 drivers/gpu/drm/tyr/driver.rs         |  1 -
 drivers/gpu/nova-core/driver.rs       |  1 -
 drivers/pwm/pwm_th1520.rs             |  1 -
 rust/kernel/device_id.rs              | 30 ++++++++++++++++--------------
 rust/kernel/i2c.rs                    |  3 ---
 rust/kernel/net/phy.rs                |  2 +-
 rust/kernel/pci.rs                    |  1 -
 rust/kernel/platform.rs               |  2 --
 rust/kernel/usb.rs                    |  1 -
 samples/rust/rust_debugfs.rs          |  1 -
 samples/rust/rust_dma.rs              |  1 -
 samples/rust/rust_driver_auxiliary.rs |  2 --
 samples/rust/rust_driver_i2c.rs       |  3 ---
 samples/rust/rust_driver_pci.rs       |  1 -
 samples/rust/rust_driver_platform.rs  |  2 --
 samples/rust/rust_driver_usb.rs       |  1 -
 samples/rust/rust_i2c_client.rs       |  2 --
 samples/rust/rust_soc.rs              |  2 --
 20 files changed, 17 insertions(+), 42 deletions(-)

diff --git a/drivers/cpufreq/rcpufreq_dt.rs b/drivers/cpufreq/rcpufreq_dt.rs
index 10106fa13095..145daa12072f 100644
--- a/drivers/cpufreq/rcpufreq_dt.rs
+++ b/drivers/cpufreq/rcpufreq_dt.rs
@@ -194,7 +194,6 @@ fn register_em(policy: &mut cpufreq::Policy) {
 
 kernel::of_device_table!(
     OF_TABLE,
-    MODULE_OF_TABLE,
     <CPUFreqDTDriver as platform::Driver>::IdInfo,
     [(of::DeviceId::new(c"operating-points-v2"), ())]
 );
diff --git a/drivers/gpu/drm/nova/driver.rs b/drivers/gpu/drm/nova/driver.rs
index 48933d86ddda..43f15cdfeb09 100644
--- a/drivers/gpu/drm/nova/driver.rs
+++ b/drivers/gpu/drm/nova/driver.rs
@@ -43,7 +43,6 @@ pub(crate) struct NovaData {
 
 kernel::auxiliary_device_table!(
     AUX_TABLE,
-    MODULE_AUX_TABLE,
     <NovaDriver as auxiliary::Driver>::IdInfo,
     [(
         auxiliary::DeviceId::new(NOVA_CORE_MODULE_NAME, AUXILIARY_NAME),
diff --git a/drivers/gpu/drm/tyr/driver.rs b/drivers/gpu/drm/tyr/driver.rs
index d063bc664cc1..218e9af899c7 100644
--- a/drivers/gpu/drm/tyr/driver.rs
+++ b/drivers/gpu/drm/tyr/driver.rs
@@ -87,7 +87,6 @@ fn issue_soft_reset(dev: &Device, iomem: &IoMem<'_>) -> Result {
 
 kernel::of_device_table!(
     OF_TABLE,
-    MODULE_OF_TABLE,
     <TyrPlatformDriver as platform::Driver>::IdInfo,
     [
         (of::DeviceId::new(c"rockchip,rk3588-mali"), ()),
diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 5a5f0b63e0f3..0c53b7239ac9 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -40,7 +40,6 @@ pub(crate) struct NovaCore<'bound> {
 
 kernel::pci_device_table!(
     PCI_TABLE,
-    MODULE_PCI_TABLE,
     <NovaCoreDriver as pci::Driver>::IdInfo,
     [
         // Modern NVIDIA GPUs will show up as either VGA or 3D controllers.
diff --git a/drivers/pwm/pwm_th1520.rs b/drivers/pwm/pwm_th1520.rs
index 3e3fa51ccef9..1df752330e8f 100644
--- a/drivers/pwm/pwm_th1520.rs
+++ b/drivers/pwm/pwm_th1520.rs
@@ -303,7 +303,6 @@ fn drop(self: Pin<&mut Self>) {
 
 kernel::of_device_table!(
     OF_TABLE,
-    MODULE_OF_TABLE,
     <Th1520PwmPlatformDriver as platform::Driver>::IdInfo,
     [(of::DeviceId::new(c"thead,th1520-pwm"), ())]
 );
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 0239f89d5f69..84852a2d9ad7 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -177,7 +177,7 @@ fn info(&self, index: usize) -> &U {
 macro_rules! module_device_table {
     (
         $table_type: literal, $device_id_ty: ty,
-        $table_name: ident, $module_table_name: ident, $id_info_type: ty,
+        $table_name: ident, $id_info_type: ty,
         [$(($id: expr, $info:expr $(,)?)),* $(,)?]
     ) => {
         const $table_name: $crate::device_id::IdArray<
@@ -186,13 +186,13 @@ macro_rules! module_device_table {
             { <[$device_id_ty]>::len(&[$($id,)*]) },
         > = $crate::device_id::IdArray::new([$(($id, $info),)*]);
 
-        $crate::module_device_table!($table_type, $module_table_name, $table_name);
+        $crate::module_device_table!($table_type, $table_name);
     };
 
     // Case for no ID info.
     (
         $table_type: literal, $device_id_ty: ty,
-        $table_name: ident, $module_table_name: ident, @none,
+        $table_name: ident, @none,
         [$($id: expr),* $(,)?]
     ) => {
         const $table_name: $crate::device_id::IdArray<
@@ -201,18 +201,20 @@ macro_rules! module_device_table {
             { <[$device_id_ty]>::len(&[$($id,)*]) },
         > = $crate::device_id::IdArray::new_without_index([$($id),*]);
 
-        $crate::module_device_table!($table_type, $module_table_name, $table_name);
+        $crate::module_device_table!($table_type, $table_name);
     };
 
-    ($table_type: literal, $module_table_name: ident, $table_name:ident) => {
-        #[rustfmt::skip]
-        #[export_name =
-            concat!("__mod_device_table__", line!(),
-                    "__kmod_", module_path!(),
-                    "__", $table_type,
-                    "__", stringify!($table_name))
-        ]
-        static $module_table_name: [::core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] =
-            unsafe { ::core::mem::transmute_copy($table_name.raw_ids()) };
+    ($table_type: literal, $table_name:ident) => {
+        const _: () = {
+            #[rustfmt::skip]
+            #[export_name =
+                concat!("__mod_device_table__", line!(),
+                        "__kmod_", module_path!(),
+                        "__", $table_type,
+                        "__", stringify!($table_name))
+            ]
+            static TABLE: [::core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] =
+                unsafe { ::core::mem::transmute_copy($table_name.raw_ids()) };
+        };
     };
 }
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index a7d9b88ae616..55c89ba3a82a 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -261,7 +261,6 @@ macro_rules! module_i2c_driver {
 ///
 /// kernel::acpi_device_table!(
 ///     ACPI_TABLE,
-///     MODULE_ACPI_TABLE,
 ///     <MyDriver as i2c::Driver>::IdInfo,
 ///     [
 ///         (acpi::DeviceId::new(c"LNUXBEEF"), ())
@@ -270,7 +269,6 @@ macro_rules! module_i2c_driver {
 ///
 /// kernel::i2c_device_table!(
 ///     I2C_TABLE,
-///     MODULE_I2C_TABLE,
 ///     <MyDriver as i2c::Driver>::IdInfo,
 ///     [
 ///          (i2c::DeviceId::new(c"rust_driver_i2c"), ())
@@ -279,7 +277,6 @@ macro_rules! module_i2c_driver {
 ///
 /// kernel::of_device_table!(
 ///     OF_TABLE,
-///     MODULE_OF_TABLE,
 ///     <MyDriver as i2c::Driver>::IdInfo,
 ///     [
 ///         (of::DeviceId::new(c"test,device"), ())
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 166572861e61..1e86b901c391 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -811,7 +811,7 @@ macro_rules! module_phy_driver {
     (@device_table [$($dev:expr),+]) => {
         $crate::module_device_table!(
             "mdio", $crate::net::phy::DeviceId,
-            phydev, TABLE, @none, [$($dev),+]
+            TABLE, @none, [$($dev),+]
         );
     };
 
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 34e07a53244d..a3dd48f76353 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -261,7 +261,6 @@ macro_rules! pci_device_table {
 ///
 /// kernel::pci_device_table!(
 ///     PCI_TABLE,
-///     MODULE_PCI_TABLE,
 ///     <MyDriver as pci::Driver>::IdInfo,
 ///     [
 ///         (
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 9b362e0495d3..210a815925ce 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -176,7 +176,6 @@ macro_rules! module_platform_driver {
 ///
 /// kernel::of_device_table!(
 ///     OF_TABLE,
-///     MODULE_OF_TABLE,
 ///     <MyDriver as platform::Driver>::IdInfo,
 ///     [
 ///         (of::DeviceId::new(c"test,device"), ())
@@ -185,7 +184,6 @@ macro_rules! module_platform_driver {
 ///
 /// kernel::acpi_device_table!(
 ///     ACPI_TABLE,
-///     MODULE_ACPI_TABLE,
 ///     <MyDriver as platform::Driver>::IdInfo,
 ///     [
 ///         (acpi::DeviceId::new(c"LNUXBEEF"), ())
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 154919ee1e19..500b5e0ba4ea 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -271,7 +271,6 @@ macro_rules! usb_device_table {
 ///
 /// kernel::usb_device_table!(
 ///     USB_TABLE,
-///     MODULE_USB_TABLE,
 ///     <MyDriver as usb::Driver>::IdInfo,
 ///     [
 ///         (usb::DeviceId::from_id(0x1234, 0x5678), ()),
diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs
index 1f59e08aaa4b..181fd98ae5b6 100644
--- a/samples/rust/rust_debugfs.rs
+++ b/samples/rust/rust_debugfs.rs
@@ -110,7 +110,6 @@ fn from_str(s: &str) -> Result<Self> {
 
 kernel::acpi_device_table!(
     ACPI_TABLE,
-    MODULE_ACPI_TABLE,
     <RustDebugFs as platform::Driver>::IdInfo,
     [(acpi::DeviceId::new(c"LNUXBEEF"), ())]
 );
diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
index 9beb37275e0d..80c309ce07e9 100644
--- a/samples/rust/rust_dma.rs
+++ b/samples/rust/rust_dma.rs
@@ -51,7 +51,6 @@ unsafe impl kernel::transmute::FromBytes for MyStruct {}
 
 kernel::pci_device_table!(
     PCI_TABLE,
-    MODULE_PCI_TABLE,
     <DmaSampleDriver as pci::Driver>::IdInfo,
     [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
 );
diff --git a/samples/rust/rust_driver_auxiliary.rs b/samples/rust/rust_driver_auxiliary.rs
index 73c63afc046a..704567a072ba 100644
--- a/samples/rust/rust_driver_auxiliary.rs
+++ b/samples/rust/rust_driver_auxiliary.rs
@@ -24,7 +24,6 @@
 
 kernel::auxiliary_device_table!(
     AUX_TABLE,
-    MODULE_AUX_TABLE,
     <AuxiliaryDriver as auxiliary::Driver>::IdInfo,
     [(auxiliary::DeviceId::new(MODULE_NAME, AUXILIARY_NAME), ())]
 );
@@ -66,7 +65,6 @@ struct ParentData<'bound> {
 
 kernel::pci_device_table!(
     PCI_TABLE,
-    MODULE_PCI_TABLE,
     <ParentDriver as pci::Driver>::IdInfo,
     [(pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5), ())]
 );
diff --git a/samples/rust/rust_driver_i2c.rs b/samples/rust/rust_driver_i2c.rs
index ead8263a7d48..a0df0c6097c4 100644
--- a/samples/rust/rust_driver_i2c.rs
+++ b/samples/rust/rust_driver_i2c.rs
@@ -14,21 +14,18 @@
 
 kernel::acpi_device_table! {
     ACPI_TABLE,
-    MODULE_ACPI_TABLE,
     <SampleDriver as i2c::Driver>::IdInfo,
     [(acpi::DeviceId::new(c"LNUXBEEF"), 0)]
 }
 
 kernel::i2c_device_table! {
     I2C_TABLE,
-    MODULE_I2C_TABLE,
     <SampleDriver as i2c::Driver>::IdInfo,
     [(i2c::DeviceId::new(c"rust_driver_i2c"), 0)]
 }
 
 kernel::of_device_table! {
     OF_TABLE,
-    MODULE_OF_TABLE,
     <SampleDriver as i2c::Driver>::IdInfo,
     [(of::DeviceId::new(c"test,rust_driver_i2c"), 0)]
 }
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 5547dd704a1b..2282191e6292 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -74,7 +74,6 @@ struct SampleDriverData<'bound> {
 
 kernel::pci_device_table!(
     PCI_TABLE,
-    MODULE_PCI_TABLE,
     <SampleDriver as pci::Driver>::IdInfo,
     [(
         pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5),
diff --git a/samples/rust/rust_driver_platform.rs b/samples/rust/rust_driver_platform.rs
index ec0d6cac4f57..710145b3605a 100644
--- a/samples/rust/rust_driver_platform.rs
+++ b/samples/rust/rust_driver_platform.rs
@@ -87,14 +87,12 @@ struct SampleDriver {
 
 kernel::of_device_table!(
     OF_TABLE,
-    MODULE_OF_TABLE,
     <SampleDriver as platform::Driver>::IdInfo,
     [(of::DeviceId::new(c"test,rust-device"), Info(42))]
 );
 
 kernel::acpi_device_table!(
     ACPI_TABLE,
-    MODULE_ACPI_TABLE,
     <SampleDriver as platform::Driver>::IdInfo,
     [(acpi::DeviceId::new(c"LNUXBEEF"), Info(0))]
 );
diff --git a/samples/rust/rust_driver_usb.rs b/samples/rust/rust_driver_usb.rs
index 02bd5085f9bc..284042c5969b 100644
--- a/samples/rust/rust_driver_usb.rs
+++ b/samples/rust/rust_driver_usb.rs
@@ -19,7 +19,6 @@ struct SampleDriver {
 
 kernel::usb_device_table!(
     USB_TABLE,
-    MODULE_USB_TABLE,
     <SampleDriver as usb::Driver>::IdInfo,
     [(usb::DeviceId::from_id(0x1234, 0x5678), ()),]
 );
diff --git a/samples/rust/rust_i2c_client.rs b/samples/rust/rust_i2c_client.rs
index 2d876f4e3ee0..c8a23875ef5b 100644
--- a/samples/rust/rust_i2c_client.rs
+++ b/samples/rust/rust_i2c_client.rs
@@ -87,14 +87,12 @@ struct SampleDriver {
 
 kernel::of_device_table!(
     OF_TABLE,
-    MODULE_OF_TABLE,
     <SampleDriver as platform::Driver>::IdInfo,
     [(of::DeviceId::new(c"test,rust-device"), ())]
 );
 
 kernel::acpi_device_table!(
     ACPI_TABLE,
-    MODULE_ACPI_TABLE,
     <SampleDriver as platform::Driver>::IdInfo,
     [(acpi::DeviceId::new(c"LNUXBEEF"), ())]
 );
diff --git a/samples/rust/rust_soc.rs b/samples/rust/rust_soc.rs
index 808d58200eb6..f5e5f2f9adf7 100644
--- a/samples/rust/rust_soc.rs
+++ b/samples/rust/rust_soc.rs
@@ -23,14 +23,12 @@ struct SampleSocDriver {
 
 kernel::of_device_table!(
     OF_TABLE,
-    MODULE_OF_TABLE,
     <SampleSocDriver as platform::Driver>::IdInfo,
     [(of::DeviceId::new(c"test,rust-device"), ())]
 );
 
 kernel::acpi_device_table!(
     ACPI_TABLE,
-    MODULE_ACPI_TABLE,
     <SampleSocDriver as platform::Driver>::IdInfo,
     [(acpi::DeviceId::new(c"LNUXBEEF"), ())]
 );

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:44 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:44 +0100
Subject: [PATCH 07/10] rust: driver: store pointers in `DeviceId`
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-7-96af1e559ef9@garyguo.net>

The common practice in C drivers is to store pointers into `driver_data`
field of device IDs. The Rust code is however currently storing indices
into the fields and then carry a side table that maps the index to
pointers.

It is much simpler to just have `DeviceId` carry the pointer like C code
does. However, just doing so naively would cause a "pointers cannot be cast
to integers during const eval" error, as kernel_ulong_t does not have
provenance while pointers do, and Rust forbids `expose_provenance` during
consteval.

Work around this limitation by wrapping raw IDs in `MaybeUninit`.
`MaybeUninit` is allowed to host arbitrary bytes with or without
provenance, so we can just then use `unsafe` to store a pointer with
provenance there. This has the same effect as changing the C-side
definition to use `void*` instead of `kernel_ulong_t`, but without actually
changing the C side.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 rust/kernel/acpi.rs      |  4 ---
 rust/kernel/auxiliary.rs |  8 ++---
 rust/kernel/device_id.rs | 88 +++++++++++++++++++++++++++++-------------------
 rust/kernel/driver.rs    | 14 ++++----
 rust/kernel/i2c.rs       |  7 ++--
 rust/kernel/of.rs        |  4 ---
 rust/kernel/pci.rs       | 11 +++---
 rust/kernel/usb.rs       |  7 ++--
 8 files changed, 73 insertions(+), 70 deletions(-)

diff --git a/rust/kernel/acpi.rs b/rust/kernel/acpi.rs
index 315f2f2af446..ea2ce61ee393 100644
--- a/rust/kernel/acpi.rs
+++ b/rust/kernel/acpi.rs
@@ -25,10 +25,6 @@ unsafe impl RawDeviceId for DeviceId {
 // SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
 unsafe impl RawDeviceIdIndex for DeviceId {
     const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::acpi_device_id, driver_data);
-
-    fn index(&self) -> usize {
-        self.0.driver_data
-    }
 }
 
 impl DeviceId {
diff --git a/rust/kernel/auxiliary.rs b/rust/kernel/auxiliary.rs
index 59787c9bff26..aa13d8866a19 100644
--- a/rust/kernel/auxiliary.rs
+++ b/rust/kernel/auxiliary.rs
@@ -93,7 +93,9 @@ extern "C" fn probe_callback(
         // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id`
         // and does not add additional invariants, so it's safe to transmute.
         let id = unsafe { &*id.cast::<DeviceId>() };
-        let info = T::ID_TABLE.info(id.index());
+
+        // SAFETY: `id` comes from `T::ID_TABLE` which is of type `IdArray<_, T::IdInfo>`.
+        let info = unsafe { id.info_unchecked::<T::IdInfo>() };
 
         from_result(|| {
             let data = T::probe(adev, info);
@@ -169,10 +171,6 @@ unsafe impl RawDeviceId for DeviceId {
 unsafe impl RawDeviceIdIndex for DeviceId {
     const DRIVER_DATA_OFFSET: usize =
         core::mem::offset_of!(bindings::auxiliary_device_id, driver_data);
-
-    fn index(&self) -> usize {
-        self.0.driver_data
-    }
 }
 
 /// IdTable type for auxiliary drivers.
diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 84852a2d9ad7..59453588df0e 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -5,7 +5,10 @@
 //! Each bus / subsystem that matches device and driver through a bus / subsystem specific ID is
 //! expected to implement [`RawDeviceId`].
 
-use core::mem::MaybeUninit;
+use core::{
+    marker::PhantomData,
+    mem::MaybeUninit, //
+};
 
 /// Marker trait to indicate a Rust device ID type represents a corresponding C device ID type.
 ///
@@ -47,15 +50,48 @@ pub unsafe trait RawDeviceIdIndex: RawDeviceId {
     /// The offset (in bytes) to the context/data field in the raw device ID.
     const DRIVER_DATA_OFFSET: usize;
 
-    /// The index stored at `DRIVER_DATA_OFFSET` of the implementor of the [`RawDeviceIdIndex`]
-    /// trait.
-    fn index(&self) -> usize;
+    /// Obtain the data pointer stored inside the device ID.
+    ///
+    /// # Safety
+    ///
+    /// `&Self` must be stored inside a `IdArray<Self, U>`.
+    unsafe fn info_unchecked<U>(&self) -> &'static U {
+        // SAFETY: By safety requirement of the trait, this is `self.driver_data as *const U` and by
+        // the safety requirement of the function, this is stored in `IdArray<Self, U>` so is
+        // convertible to `&'static U`.
+        unsafe {
+            core::ptr::from_ref(self)
+                .byte_add(Self::DRIVER_DATA_OFFSET)
+                .cast::<&U>()
+                .read()
+        }
+    }
+
+    /// Obtain the data pointer stored inside the device ID.
+    ///
+    /// # Safety
+    ///
+    /// `&Self` must be stored inside a `IdArray<Self, U>`, or has NULL (or 0) as driver data.
+    unsafe fn info_unchecked_opt<U>(&self) -> Option<&'static U> {
+        // SAFETY: By safety requirement of the trait, this is `self.driver_data as *const U` and by
+        // the safety requirement of the function, if this is stored in `IdArray<Self, U>`, this is
+        // convertible to `Option<&'static U>`. Otherwise it is NULL which is `None` as
+        // `Option<&U>`.
+        unsafe {
+            core::ptr::from_ref(self)
+                .byte_add(Self::DRIVER_DATA_OFFSET)
+                .cast::<Option<&U>>()
+                .read()
+        }
+    }
 }
 
 /// A zero-terminated device id array.
 #[repr(C)]
 pub struct RawIdArray<T: RawDeviceId, const N: usize> {
-    ids: [T::RawType; N],
+    // This is `MaybeUninit<T::RawType>` so any bytes inside it can carry provenance in CTFE.
+    // If this were `T::RawType`, integer fields would not be able to contain pointers.
+    ids: [MaybeUninit<T::RawType>; N],
     sentinel: MaybeUninit<T::RawType>,
 }
 
@@ -68,18 +104,17 @@ pub const fn size(&self) -> usize {
 
 /// A zero-terminated device id array, followed by context data.
 #[repr(C)]
-pub struct IdArray<T: RawDeviceId, U, const N: usize> {
+pub struct IdArray<T: RawDeviceId, U: 'static, const N: usize> {
     raw_ids: RawIdArray<T, N>,
-    id_infos: [U; N],
+    phantom: PhantomData<&'static U>,
 }
 
-impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
+impl<T: RawDeviceId + RawDeviceIdIndex, U: 'static, const N: usize> IdArray<T, U, N> {
     /// Creates a new instance of the array.
     ///
     /// The contents are derived from the given identifiers and context information.
-    pub const fn new(ids: [(T, U); N]) -> Self {
+    pub const fn new(ids: [(T, &'static U); N]) -> Self {
         let mut raw_ids = [const { MaybeUninit::<T::RawType>::uninit() }; N];
-        let mut infos = [const { MaybeUninit::uninit() }; N];
 
         let mut i = 0usize;
         while i < N {
@@ -87,18 +122,15 @@ impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
             // layout-wise compatible with `RawType`.
             raw_ids[i] = unsafe { core::mem::transmute_copy(&ids[i].0) };
             // SAFETY: by the safety requirement of `RawDeviceIdIndex`, this would be effectively
-            // `raw_ids[i].driver_data = i;`.
+            // `raw_ids[i].driver_data = ids[i].1;`.
             unsafe {
                 raw_ids[i]
                     .as_mut_ptr()
                     .byte_add(T::DRIVER_DATA_OFFSET)
-                    .cast::<usize>()
-                    .write(i);
+                    .cast::<&U>()
+                    .write(ids[i].1);
             }
 
-            // SAFETY: this is effectively a move: `infos[i] = ids[i].1`. We make a copy here but
-            // later forget `ids`.
-            infos[i] = MaybeUninit::new(unsafe { core::ptr::read(&ids[i].1) });
             i += 1;
         }
 
@@ -106,20 +138,15 @@ impl<T: RawDeviceId + RawDeviceIdIndex, U, const N: usize> IdArray<T, U, N> {
 
         Self {
             raw_ids: RawIdArray {
-                // SAFETY: this is effectively `array_assume_init`, which is unstable, so we use
-                // `transmute_copy` instead. We have initialized all elements of `raw_ids` so this
-                // `array_assume_init` is safe.
-                ids: unsafe { core::mem::transmute_copy(&raw_ids) },
+                ids: raw_ids,
                 sentinel: MaybeUninit::zeroed(),
             },
-            // SAFETY: We have initialized all elements of `infos` so this `array_assume_init` is
-            // safe.
-            id_infos: unsafe { core::mem::transmute_copy(&infos) },
+            phantom: PhantomData,
         }
     }
 }
 
-impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
+impl<T: RawDeviceId, U: 'static, const N: usize> IdArray<T, U, N> {
     /// Reference to the contained [`RawIdArray`].
     pub const fn raw_ids(&self) -> &RawIdArray<T, N> {
         &self.raw_ids
@@ -133,7 +160,7 @@ impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
     /// If the device implements [`RawDeviceIdIndex`], consider using [`IdArray::new`] instead.
     pub const fn new_without_index(ids: [T; N]) -> Self {
         // SAFETY: `T` is layout-wise compatible with `T::RawType`, so is the array of them.
-        let raw_ids: [T::RawType; N] = unsafe { core::mem::transmute_copy(&ids) };
+        let raw_ids: [MaybeUninit<T::RawType>; N] = unsafe { core::mem::transmute_copy(&ids) };
         core::mem::forget(ids);
 
         Self {
@@ -141,7 +168,7 @@ impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
                 ids: raw_ids,
                 sentinel: MaybeUninit::zeroed(),
             },
-            id_infos: [(); N],
+            phantom: PhantomData,
         }
     }
 }
@@ -155,9 +182,6 @@ impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
 pub trait IdTable<T: RawDeviceId, U> {
     /// Obtain the pointer to the ID table.
     fn as_ptr(&self) -> *const T::RawType;
-
-    /// Obtain the pointer to the driver-specific information from an index.
-    fn info(&self, index: usize) -> &U;
 }
 
 impl<T: RawDeviceId, U, const N: usize> IdTable<T, U> for IdArray<T, U, N> {
@@ -166,10 +190,6 @@ fn as_ptr(&self) -> *const T::RawType {
         // to access the sentinel.
         core::ptr::from_ref(self).cast()
     }
-
-    fn info(&self, index: usize) -> &U {
-        &self.id_infos[index]
-    }
 }
 
 /// Create device table alias for modpost.
@@ -184,7 +204,7 @@ macro_rules! module_device_table {
             $device_id_ty,
             $id_info_type,
             { <[$device_id_ty]>::len(&[$($id,)*]) },
-        > = $crate::device_id::IdArray::new([$(($id, $info),)*]);
+        > = $crate::device_id::IdArray::new([$(($id, &$info),)*]);
 
         $crate::module_device_table!($table_type, $table_name);
     };
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
index bf5ba0d27553..824899d76fed 100644
--- a/rust/kernel/driver.rs
+++ b/rust/kernel/driver.rs
@@ -107,6 +107,7 @@
 use crate::{
     acpi,
     device,
+    device_id::RawDeviceIdIndex,
     of,
     prelude::*,
     types::Opaque,
@@ -350,7 +351,8 @@ fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
                 // and does not add additional invariants, so it's safe to transmute.
                 let id = unsafe { &*raw_id.cast::<acpi::DeviceId>() };
 
-                Some(table.info(<acpi::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id)))
+                // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
+                Some(unsafe { id.info_unchecked::<Self::IdInfo>() })
             }
         }
     }
@@ -381,9 +383,8 @@ fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
                 // and does not add additional invariants, so it's safe to transmute.
                 let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
 
-                return Some(table.info(
-                    <of::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id),
-                ));
+                // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
+                return Some(unsafe { id.info_unchecked::<Self::IdInfo>() });
             }
         }
 
@@ -412,9 +413,8 @@ fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
                 //   and does not add additional invariants, so it's safe to transmute.
                 let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
 
-                return Some(table.info(
-                    <of::DeviceId as crate::device_id::RawDeviceIdIndex>::index(id),
-                ));
+                // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
+                return Some(unsafe { id.info_unchecked::<Self::IdInfo>() });
             }
         }
 
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 55c89ba3a82a..9e551c7e8e41 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -65,10 +65,6 @@ unsafe impl RawDeviceId for DeviceId {
 // SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
 unsafe impl RawDeviceIdIndex for DeviceId {
     const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::i2c_device_id, driver_data);
-
-    fn index(&self) -> usize {
-        self.0.driver_data
-    }
 }
 
 /// IdTable type for I2C
@@ -212,7 +208,8 @@ fn i2c_id_info(dev: &I2cClient) -> Option<&'static <Self as driver::Adapter>::Id
         // does not add additional invariants, so it's safe to transmute.
         let id = unsafe { &*raw_id.cast::<DeviceId>() };
 
-        Some(table.info(<DeviceId as RawDeviceIdIndex>::index(id)))
+        // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
+        Some(unsafe { id.info_unchecked::<T::IdInfo>() })
     }
 }
 
diff --git a/rust/kernel/of.rs b/rust/kernel/of.rs
index 35aa6d36d309..d0318f62afd7 100644
--- a/rust/kernel/of.rs
+++ b/rust/kernel/of.rs
@@ -25,10 +25,6 @@ unsafe impl RawDeviceId for DeviceId {
 // SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `data` field.
 unsafe impl RawDeviceIdIndex for DeviceId {
     const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::of_device_id, data);
-
-    fn index(&self) -> usize {
-        self.0.data as usize
-    }
 }
 
 impl DeviceId {
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index a3dd48f76353..a630c7fc6a85 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -110,10 +110,13 @@ extern "C" fn probe_callback(
         // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct pci_device_id` and
         // does not add additional invariants, so it's safe to transmute.
         let id = unsafe { &*id.cast::<DeviceId>() };
-        let info = T::ID_TABLE.info(id.index());
+
+        // SAFETY: `id` comes from `T::ID_TABLE` which is of type `IdArray<_, T::IdInfo>` or
+        // `pci_device_id_any` which has 0 as driver_data.
+        let info = unsafe { id.info_unchecked_opt::<T::IdInfo>() };
 
         from_result(|| {
-            let data = T::probe(pdev, Some(info));
+            let data = T::probe(pdev, info);
 
             pdev.as_ref().set_drvdata(data)?;
             Ok(0)
@@ -233,10 +236,6 @@ unsafe impl RawDeviceId for DeviceId {
 // SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field.
 unsafe impl RawDeviceIdIndex for DeviceId {
     const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::pci_device_id, driver_data);
-
-    fn index(&self) -> usize {
-        self.0.driver_data
-    }
 }
 
 /// `IdTable` type for PCI.
diff --git a/rust/kernel/usb.rs b/rust/kernel/usb.rs
index 500b5e0ba4ea..8aeff5011755 100644
--- a/rust/kernel/usb.rs
+++ b/rust/kernel/usb.rs
@@ -89,7 +89,8 @@ extern "C" fn probe_callback(
             // does not add additional invariants, so it's safe to transmute.
             let id = unsafe { &*id.cast::<DeviceId>() };
 
-            let info = T::ID_TABLE.info(id.index());
+            // SAFETY: `id` comes from `T::ID_TABLE` which is of type `IdArray<_, T::IdInfo>`.
+            let info = unsafe { id.info_unchecked::<T::IdInfo>() };
             let data = T::probe(intf, id, info);
 
             let dev: &device::Device<device::CoreInternal<'_>> = intf.as_ref();
@@ -242,10 +243,6 @@ unsafe impl RawDeviceId for DeviceId {
 // SAFETY: `DRIVER_DATA_OFFSET` is the offset to the `driver_info` field.
 unsafe impl RawDeviceIdIndex for DeviceId {
     const DRIVER_DATA_OFFSET: usize = core::mem::offset_of!(bindings::usb_device_id, driver_info);
-
-    fn index(&self) -> usize {
-        self.0.driver_info
-    }
 }
 
 /// [`IdTable`](kernel::device_id::IdTable) type for USB.

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:45 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:45 +0100
Subject: [PATCH 08/10] rust: driver: remove open-coded matching logic
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-8-96af1e559ef9@garyguo.net>

With device ID info now including pointers instead of indices, the
open-coded ACPI/OF matching is no longer needed and can be replaced with
`device_get_match_data`.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 rust/kernel/driver.rs   | 114 ++++--------------------------------------------
 rust/kernel/i2c.rs      |   6 ++-
 rust/kernel/platform.rs |   3 +-
 3 files changed, 15 insertions(+), 108 deletions(-)

diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs
index 824899d76fed..a881f5ef99ec 100644
--- a/rust/kernel/driver.rs
+++ b/rust/kernel/driver.rs
@@ -107,7 +107,6 @@
 use crate::{
     acpi,
     device,
-    device_id::RawDeviceIdIndex,
     of,
     prelude::*,
     types::Opaque,
@@ -325,117 +324,22 @@ pub trait Adapter {
     /// The [`acpi::IdTable`] of the corresponding driver
     fn acpi_id_table() -> Option<acpi::IdTable<Self::IdInfo>>;
 
-    /// Returns the driver's private data from the matching entry in the [`acpi::IdTable`], if any.
-    ///
-    /// If this returns `None`, it means there is no match with an entry in the [`acpi::IdTable`].
-    fn acpi_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
-        #[cfg(not(CONFIG_ACPI))]
-        {
-            let _ = dev;
-            None
-        }
-
-        #[cfg(CONFIG_ACPI)]
-        {
-            let table = Self::acpi_id_table()?;
-
-            // SAFETY:
-            // - `table` has static lifetime, hence it's valid for read,
-            // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`.
-            let raw_id = unsafe { bindings::acpi_match_device(table.as_ptr(), dev.as_raw()) };
-
-            if raw_id.is_null() {
-                None
-            } else {
-                // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct acpi_device_id`
-                // and does not add additional invariants, so it's safe to transmute.
-                let id = unsafe { &*raw_id.cast::<acpi::DeviceId>() };
-
-                // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
-                Some(unsafe { id.info_unchecked::<Self::IdInfo>() })
-            }
-        }
-    }
-
     /// The [`of::IdTable`] of the corresponding driver.
     fn of_id_table() -> Option<of::IdTable<Self::IdInfo>>;
 
-    /// Returns the driver's private data from the matching entry in the [`of::IdTable`], if any.
-    ///
-    /// If this returns `None`, it means there is no match with an entry in the [`of::IdTable`].
-    fn of_id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
-        let table = Self::of_id_table()?;
-
-        #[cfg(not(any(CONFIG_OF, CONFIG_ACPI)))]
-        {
-            let _ = (dev, table);
-        }
-
-        #[cfg(CONFIG_OF)]
-        {
-            // SAFETY:
-            // - `table` has static lifetime, hence it's valid for read,
-            // - `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`.
-            let raw_id = unsafe { bindings::of_match_device(table.as_ptr(), dev.as_raw()) };
-
-            if !raw_id.is_null() {
-                // SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id`
-                // and does not add additional invariants, so it's safe to transmute.
-                let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
-
-                // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
-                return Some(unsafe { id.info_unchecked::<Self::IdInfo>() });
-            }
-        }
-
-        #[cfg(CONFIG_ACPI)]
-        {
-            use core::ptr;
-            use device::property::FwNode;
-
-            let mut raw_id = ptr::null();
-
-            let fwnode = dev.fwnode().map_or(ptr::null_mut(), FwNode::as_raw);
-
-            // SAFETY: `fwnode` is a pointer to a valid `fwnode_handle`. A null pointer will be
-            // passed through the function.
-            let adev = unsafe { bindings::to_acpi_device_node(fwnode) };
-
-            // SAFETY:
-            // - `adev` is a valid pointer to `acpi_device` or is null. It is guaranteed to be
-            //   valid as long as `dev` is alive.
-            // - `table` has static lifetime, hence it's valid for read.
-            if unsafe { acpi_of_match_device(adev, table.as_ptr(), &raw mut raw_id) } {
-                // SAFETY:
-                // - the function returns true, therefore `raw_id` has been set to a pointer to a
-                //   valid `of_device_id`.
-                // - `DeviceId` is a `#[repr(transparent)]` wrapper of `struct of_device_id`
-                //   and does not add additional invariants, so it's safe to transmute.
-                let id = unsafe { &*raw_id.cast::<of::DeviceId>() };
-
-                // SAFETY: `id` comes from `table` which is of type `IdArray<_, Self::IdInfo>`.
-                return Some(unsafe { id.info_unchecked::<Self::IdInfo>() });
-            }
-        }
-
-        None
-    }
-
     /// Returns the driver's private data from the matching entry of any of the ID tables, if any.
     ///
     /// If this returns `None`, it means that there is no match in any of the ID tables directly
     /// associated with a [`device::Device`].
-    fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
-        let id = Self::acpi_id_info(dev);
-        if id.is_some() {
-            return id;
-        }
-
-        let id = Self::of_id_info(dev);
-        if id.is_some() {
-            return id;
-        }
+    ///
+    /// # Safety
+    ///
+    /// The caller must ensure that the `dev` matched data is of type `Self::IdInfo`.
+    unsafe fn id_info(dev: &device::Device) -> Option<&'static Self::IdInfo> {
+        // SAFETY: `dev` is guaranteed to be valid while it's alive, and so is `dev.as_raw()`.
+        let data = unsafe { bindings::device_get_match_data(dev.as_raw()) };
 
-        None
+        // SAFETY: Per safety requirement, `data` is of type `Self::IdInfo`.
+        unsafe { data.cast::<Self::IdInfo>().as_ref() }
     }
 }
diff --git a/rust/kernel/i2c.rs b/rust/kernel/i2c.rs
index 9e551c7e8e41..07680fd2f3fc 100644
--- a/rust/kernel/i2c.rs
+++ b/rust/kernel/i2c.rs
@@ -149,8 +149,10 @@ extern "C" fn probe_callback(idev: *mut bindings::i2c_client) -> kernel::ffi::c_
         // INVARIANT: `idev` is valid for the duration of `probe_callback()`.
         let idev = unsafe { &*idev.cast::<I2cClient<device::CoreInternal<'_>>>() };
 
-        let info =
-            Self::i2c_id_info(idev).or_else(|| <Self as driver::Adapter>::id_info(idev.as_ref()));
+        let info = Self::i2c_id_info(idev).or_else(|| {
+            // SAFETY: `idev` matched data is of type `Self::IdInfo`.
+            unsafe { <Self as driver::Adapter>::id_info(idev.as_ref()) }
+        });
 
         from_result(|| {
             let data = T::probe(idev, info);
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index 210a815925ce..e12e88113ca5 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -100,7 +100,8 @@ extern "C" fn probe_callback(pdev: *mut bindings::platform_device) -> kernel::ff
         //
         // INVARIANT: `pdev` is valid for the duration of `probe_callback()`.
         let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() };
-        let info = <Self as driver::Adapter>::id_info(pdev.as_ref());
+        // SAFETY: `pdev` matched data is of type `Self::IdInfo`.
+        let info = unsafe { <Self as driver::Adapter>::id_info(pdev.as_ref()) };
 
         from_result(|| {
             let data = T::probe(pdev, info);

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:46 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:46 +0100
Subject: [PATCH 09/10] rust: driver: remove duplicate ID table
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-9-96af1e559ef9@garyguo.net>

Previously, `IdArray` contains both device ID table and info table so we
keep a separate copy for MODULE_DEVICE_TABLE for hotplug (which needs to be
just the device ID table). With the info being changed to be carried via
pointers, `IdArray` is now layout compatible with raw ID table and hence
there is no longer a need to keep the distinction.

Deduplicate the code, and remove the redundant copy for hotplug purpose by
just giving the `IdArray` instance a proper symbol name.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 rust/kernel/device_id.rs | 76 +++++++++++++++++-------------------------------
 1 file changed, 27 insertions(+), 49 deletions(-)

diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 59453588df0e..26618bcda276 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -86,28 +86,23 @@ unsafe fn info_unchecked_opt<U>(&self) -> Option<&'static U> {
     }
 }
 
-/// A zero-terminated device id array.
+/// A zero-terminated device id array, followed by context data.
 #[repr(C)]
-pub struct RawIdArray<T: RawDeviceId, const N: usize> {
+pub struct IdArray<T: RawDeviceId, U: 'static, const N: usize> {
     // This is `MaybeUninit<T::RawType>` so any bytes inside it can carry provenance in CTFE.
     // If this were `T::RawType`, integer fields would not be able to contain pointers.
     ids: [MaybeUninit<T::RawType>; N],
     sentinel: MaybeUninit<T::RawType>,
+    phantom: PhantomData<&'static U>,
 }
 
-impl<T: RawDeviceId, const N: usize> RawIdArray<T, N> {
-    #[doc(hidden)]
-    pub const fn size(&self) -> usize {
-        core::mem::size_of::<Self>()
-    }
-}
+// SAFETY: device ID is plain data plus a `&'static U` and can thus be sent between threads safely
+// if `&U` can.
+unsafe impl<T: RawDeviceId, U: Sync + 'static, const N: usize> Send for IdArray<T, U, N> {}
 
-/// A zero-terminated device id array, followed by context data.
-#[repr(C)]
-pub struct IdArray<T: RawDeviceId, U: 'static, const N: usize> {
-    raw_ids: RawIdArray<T, N>,
-    phantom: PhantomData<&'static U>,
-}
+// SAFETY: device ID is plain data plus a `&'static U` and can thus be shared between threads safely
+// if `&U` can.
+unsafe impl<T: RawDeviceId, U: Sync + 'static, const N: usize> Sync for IdArray<T, U, N> {}
 
 impl<T: RawDeviceId + RawDeviceIdIndex, U: 'static, const N: usize> IdArray<T, U, N> {
     /// Creates a new instance of the array.
@@ -137,22 +132,13 @@ impl<T: RawDeviceId + RawDeviceIdIndex, U: 'static, const N: usize> IdArray<T, U
         core::mem::forget(ids);
 
         Self {
-            raw_ids: RawIdArray {
-                ids: raw_ids,
-                sentinel: MaybeUninit::zeroed(),
-            },
+            ids: raw_ids,
+            sentinel: MaybeUninit::zeroed(),
             phantom: PhantomData,
         }
     }
 }
 
-impl<T: RawDeviceId, U: 'static, const N: usize> IdArray<T, U, N> {
-    /// Reference to the contained [`RawIdArray`].
-    pub const fn raw_ids(&self) -> &RawIdArray<T, N> {
-        &self.raw_ids
-    }
-}
-
 impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
     /// Creates a new instance of the array without writing index values.
     ///
@@ -164,10 +150,8 @@ impl<T: RawDeviceId, const N: usize> IdArray<T, (), N> {
         core::mem::forget(ids);
 
         Self {
-            raw_ids: RawIdArray {
-                ids: raw_ids,
-                sentinel: MaybeUninit::zeroed(),
-            },
+            ids: raw_ids,
+            sentinel: MaybeUninit::zeroed(),
             phantom: PhantomData,
         }
     }
@@ -200,13 +184,17 @@ macro_rules! module_device_table {
         $table_name: ident, $id_info_type: ty,
         [$(($id: expr, $info:expr $(,)?)),* $(,)?]
     ) => {
-        const $table_name: $crate::device_id::IdArray<
+        #[export_name =
+            concat!("__mod_device_table__", line!(),
+                    "__kmod_", module_path!(),
+                    "__", $table_type,
+                    "__", stringify!($table_name))
+        ]
+        static $table_name: $crate::device_id::IdArray<
             $device_id_ty,
             $id_info_type,
             { <[$device_id_ty]>::len(&[$($id,)*]) },
         > = $crate::device_id::IdArray::new([$(($id, &$info),)*]);
-
-        $crate::module_device_table!($table_type, $table_name);
     };
 
     // Case for no ID info.
@@ -215,26 +203,16 @@ macro_rules! module_device_table {
         $table_name: ident, @none,
         [$($id: expr),* $(,)?]
     ) => {
-        const $table_name: $crate::device_id::IdArray<
+        #[export_name =
+            concat!("__mod_device_table__", line!(),
+                    "__kmod_", module_path!(),
+                    "__", $table_type,
+                    "__", stringify!($table_name))
+        ]
+        static $table_name: $crate::device_id::IdArray<
             $device_id_ty,
             (),
             { <[$device_id_ty]>::len(&[$($id,)*]) },
         > = $crate::device_id::IdArray::new_without_index([$($id),*]);
-
-        $crate::module_device_table!($table_type, $table_name);
-    };
-
-    ($table_type: literal, $table_name:ident) => {
-        const _: () = {
-            #[rustfmt::skip]
-            #[export_name =
-                concat!("__mod_device_table__", line!(),
-                        "__kmod_", module_path!(),
-                        "__", $table_type,
-                        "__", stringify!($table_name))
-            ]
-            static TABLE: [::core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] =
-                unsafe { ::core::mem::transmute_copy($table_name.raw_ids()) };
-        };
     };
 }

-- 
2.54.0



From gary at garyguo.net  Thu Jun 18 10:03:47 2026
From: gary at garyguo.net (Gary Guo)
Date: Thu, 18 Jun 2026 18:03:47 +0100
Subject: [PATCH 10/10] RFC: rust: driver: support map-like syntax for ID
 table
In-Reply-To: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
References: <20260618-id_info-v1-0-96af1e559ef9@garyguo.net>
Message-ID: <20260618-id_info-v1-10-96af1e559ef9@garyguo.net>

The device ID table and its associated info is really just a map. Add a
syntax to `module_device_table` macro that reflects that.

Signed-off-by: Gary Guo <gary at garyguo.net>
---
 rust/kernel/device_id.rs        | 11 +++++++++++
 samples/rust/rust_driver_pci.rs |  7 +++----
 2 files changed, 14 insertions(+), 4 deletions(-)

diff --git a/rust/kernel/device_id.rs b/rust/kernel/device_id.rs
index 26618bcda276..7c61cdcc9427 100644
--- a/rust/kernel/device_id.rs
+++ b/rust/kernel/device_id.rs
@@ -183,6 +183,17 @@ macro_rules! module_device_table {
         $table_type: literal, $device_id_ty: ty,
         $table_name: ident, $id_info_type: ty,
         [$(($id: expr, $info:expr $(,)?)),* $(,)?]
+    ) => {
+        $crate::module_device_table!(
+            $table_type, $device_id_ty, $table_name, $id_info_type,
+            {$($id=>$info,)*}
+        );
+    };
+
+    (
+        $table_type: literal, $device_id_ty: ty,
+        $table_name: ident, $id_info_type: ty,
+        {$($id: expr => $info:expr),* $(,)?}
     ) => {
         #[export_name =
             concat!("__mod_device_table__", line!(),
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 2282191e6292..652819dff082 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -75,10 +75,9 @@ struct SampleDriverData<'bound> {
 kernel::pci_device_table!(
     PCI_TABLE,
     <SampleDriver as pci::Driver>::IdInfo,
-    [(
-        pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5),
-        TestIndex::NO_EVENTFD
-    )]
+    {
+        pci::DeviceId::from_id(pci::Vendor::REDHAT, 0x5) => TestIndex::NO_EVENTFD,
+    }
 );
 
 impl SampleDriverData<'_> {

-- 
2.54.0



From waldi at debian.org  Thu Jun 18 09:12:30 2026
From: waldi at debian.org (Bastian Blank)
Date: Thu, 18 Jun 2026 18:12:30 +0200
Subject: [PATCH] riscv: Add build salt to the vDSO
Message-ID: <ajQY7n0an0YwQ--j@steamhammer.waldi.eu.org>

The vDSO needs to have a unique build id in a similar manner
to the kernel and modules. Use the build salt macro.

Signed-off-by: Bastian Blank <waldi at debian.org>
---
 arch/riscv/kernel/vdso/note.S | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/riscv/kernel/vdso/note.S b/arch/riscv/kernel/vdso/note.S
index 3d92cc956b95..69bfe48be037 100644
--- a/arch/riscv/kernel/vdso/note.S
+++ b/arch/riscv/kernel/vdso/note.S
@@ -4,6 +4,7 @@
  * Here we can supply some information useful to userland.
  */
 
+#include <linux/build-salt.h>
 #include <linux/elfnote.h>
 #include <linux/version.h>
 #include <asm/assembler.h>
@@ -12,4 +13,6 @@ ELFNOTE_START(Linux, 0, "a")
 	.long LINUX_VERSION_CODE
 ELFNOTE_END
 
+BUILD_SALT
+
 emit_riscv_feature_1_and
-- 
2.53.0


From changhuang.liang at starfivetech.com  Fri Jun 19 01:41:29 2026
From: changhuang.liang at starfivetech.com (Changhuang Liang)
Date: Fri, 19 Jun 2026 08:41:29 +0000
Subject: [PATCH v3 04/21] pinctrl: starfive: Add StarFive JHB100 sys0
 controller driver
In-Reply-To: <CAD++jL=Qd8ADR_kX2Q7msM4Dd0xFayPGM4ZzB3uv2ufvkuybtQ@mail.gmail.com>
References: <20260603055347.66845-1-changhuang.liang@starfivetech.com>
 <20260603055347.66845-5-changhuang.liang@starfivetech.com>
 <CAD++jL=Qd8ADR_kX2Q7msM4Dd0xFayPGM4ZzB3uv2ufvkuybtQ@mail.gmail.com>
Message-ID: <ZQ4PR01MB12026B377AE07EDA00327B2EF2E22@ZQ4PR01MB1202.CHNPR01.prod.partner.outlook.cn>

Hi, Linus

Thanks for the review.

I will first try making revisions according to your suggestions below. It may take some time for 
the next version. If I run into any issues during the subsequent revisions, I may bother you then.


Best Regards,
Changhuang

> Hi Changhuang,
> 
> thanks for your patch!
> 
> On Wed, Jun 3, 2026 at 7:54?AM Changhuang Liang
> <changhuang.liang at starfivetech.com> wrote:
> 
> > Add pinctrl driver for StarFive JHB100 SoC System-0(sys0) pinctrl
> > controller.
> >
> > Co-developed-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> > Signed-off-by: Lianfeng Ouyang <lianfeng.ouyang at starfivetech.com>
> > Signed-off-by: Changhuang Liang <changhuang.liang at starfivetech.com>
> 
> This patch adds generic infrastructure "JHB100" that is then used by several
> drivers does it not?
> 
> Write something about that and some about the design in the commit
> message.
> 
> > +++ b/drivers/pinctrl/starfive/pinctrl-starfive-jhb100-sys0.c
> > @@ -0,0 +1,123 @@
> > +// SPDX-License-Identifier: GPL-2.0-or-later
> > +/*
> > + * Pinctrl / GPIO driver for StarFive JHB100 SoC System-0 domain
> > + *
> > + * Copyright (C) 2024 StarFive Technology Co., Ltd.
> > + * Author: Alex Soo <yuklin.soo at starfivetech.com>
> 
> Shouldn't this person be in the Signed-off-by?
> 
> I guess it's not legally necessary but feels appropriate.
> 
> > +static struct config_reg_layout_desc jhb100_sys0_pinctrl_crl_desc[] = {
> > +       {
> > +               .pin_start                      = 0,
> > +               .pin_cnt                        = 4,
> > +               .drive_strength_2bit            = { .shift = 0, .width
> = 2 },
> > +               .input_enable                   = { .shift =
> 2, .width = 1 },
> > +               .pull_down                      = { .shift =
> 3, .width = 1 },
> > +               .pull_up                        = { .shift =
> 4, .width = 1 },
> > +               .slew_rate                      = { .shift =
> 5, .width = 1 },
> > +               .schmitt_trigger_select         = { .shift = 6, .width =
> 1 },
> > +               .reserved                       = { .shift =
> 7, .width = 8 },
> > +               .debounce_width                 = { .shift =
> 15, .width = 17 },
> > +       },
> > +       {
> > +               .pin_start                      = 4,
> > +               .pin_cnt                        = 5,
> > +               .schmitt_trigger_select         = { .shift = 0, .width =
> 1 },
> > +               .reserved                       = { .shift =
> 1, .width = 31 },
> > +       },
> > +       {
> > +               .pin_start                      = 9,
> > +               .pin_cnt                        = 1,
> > +               .drive_strength_2bit            = { .shift = 0, .width
> = 2 },
> > +               .slew_rate                      = { .shift =
> 2, .width = 1 },
> > +               .reserved                       = { .shift =
> 3, .width = 29 },
> > +       },
> > +       {
> > +               .pin_start                      = 10,
> > +               .pin_cnt                        = 1,
> > +               .drive_strength_2bit            = { .shift = 0, .width
> = 2 },
> > +               .input_enable                   = { .shift =
> 2, .width = 1 },
> > +               .pull_down                      = { .shift =
> 3, .width = 1 },
> > +               .pull_up                        = { .shift =
> 4, .width = 1 },
> > +               .slew_rate                      = { .shift =
> 5, .width = 1 },
> > +               .schmitt_trigger_select         = { .shift = 6, .width =
> 1 },
> > +               .reserved                       = { .shift =
> 7, .width = 25 },
> > +       },
> > +       { 0xff },
> > +};
> 
> Would it be appropriate to index the different register variants with a enum
> with a good name so it is easy to understand which variant each entry in the
> array is?
> 
> > +#include <linux/string.h>
> > +#include <linux/sort.h>
> 
> Hm why... I guess I will see.
> 
> > +#define JHB100_DEBOUNCE_WIDTH_STAGES_MAX       0x1FFFFU
> 
> Is that a GENMASK(16,0)?
> 
> Since it seems to have something to do with bitfield widths.
> 
> > +/* i2c open-drain pull-up select */
> > +#define JHB100_I2C_OPEN_DRAIN_PU_600_OHMS      0
> > +#define JHB100_I2C_OPEN_DRAIN_PU_900_OHMS      1
> > +#define JHB100_I2C_OPEN_DRAIN_PU_1200_OHMS     2
> > +#define JHB100_I2C_OPEN_DRAIN_PU_2000_OHMS     3
> 
> Very nice and to the point! It's easy to read and understand drivers that are
> writing things out explicitly like this!
> 
> > +#define JHB100_NR_GPIOS_PER_BANK               32
> (...)
> > +static inline struct jhb100_gpio_bank *jhb100_gc_to_bank(struct
> > +gpio_chip *gc) {
> > +       return container_of(gc, struct jhb100_gpio_bank, gc); }
> > +
> > +static unsigned int jhb100_gpio_to_pin(struct gpio_chip *gc, unsigned
> > +int gpio) {
> > +       struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
> > +
> > +       return bank->id * JHB100_NR_GPIOS_PER_BANK + gpio; }
> 
> This usually tells me that GPIO_GENERIC can be used but maybe this has been
> discussed before...
> 
> > +static const struct pinctrl_ops jhb100_pinctrl_ops = {
> > +       .get_groups_count = pinctrl_generic_get_group_count,
> > +       .get_group_name   = pinctrl_generic_get_group_name,
> > +       .get_group_pins   = pinctrl_generic_get_group_pins,
> > +       .dt_node_to_map   =
> pinctrl_generic_pins_function_dt_node_to_map,
> > +       .dt_free_map      = pinctrl_utils_free_map,
> > +};
> 
> Nice use of the generic helpers!
> 
> > +static void jhb100_set_gpioval(struct jhb100_pinctrl *sfp, unsigned int pin,
> > +                              unsigned int val) {
> > +       const struct jhb100_pinctrl_domain_info *info = sfp->info;
> > +       unsigned int offset = 4 * (pin / 32);
> > +       unsigned int shift = 1 * (pin % 32);
> > +       unsigned int fs_offset = 4 * (pin / 16);
> > +       unsigned int fs_shift = 2 * (pin % 16);
> > +       u32 func_sel_mask;
> > +       u32 dout, doen, fs;
> > +       void __iomem *reg_gpio_o;
> > +       void __iomem *reg_gpio_oen;
> > +       void __iomem *reg_gpio_func_sel;
> > +       unsigned long flags;
> > +
> > +       reg_gpio_o = sfp->base + info->regs->output + offset;
> > +       reg_gpio_oen = sfp->base + info->regs->output_en + offset;
> > +       reg_gpio_func_sel = sfp->base + info->regs->func_sel.reg +
> > + fs_offset;
> 
> The part from here:
> 
> > +       func_sel_mask = GENMASK(info->regs->func_sel.width_per_pin -
> > + 1, 0) << fs_shift;
> (...)
> > +
> > +       raw_spin_lock_irqsave(&sfp->lock, flags);
> > +       fs = readl_relaxed(reg_gpio_func_sel);
> > +       if (fs & func_sel_mask) {
> > +               fs &= ~func_sel_mask;
> > +               writel_relaxed(fs, reg_gpio_func_sel);
> > +       }
> 
> ..to here seems to reimplement the shortcut
> .gpio_request_enable() in struct pinmux_ops.
> 
> Then this:
> 
> > +       dout = val << shift;
> > +       doen = 0;
> 
> > +       dout |= readl_relaxed(reg_gpio_o) & ~BIT(shift);
> > +       writel_relaxed(dout, reg_gpio_o);
> > +       doen |= readl_relaxed(reg_gpio_oen) & ~BIT(shift);
> > +       writel_relaxed(doen, reg_gpio_oen);
> 
> Seems more like the actual code that should be here.
> 
> > +       raw_spin_unlock_irqrestore(&sfp->lock, flags);
> 
> Please use guards for these spinlocks. They make for less bugs.
> 
> guard(raw_spinlock_irqsave)(&sfp->lock);
> 
> > +static const struct pinmux_ops jhb100_pinmux_ops = {
> > +       .get_functions_count = pinmux_generic_get_function_count,
> > +       .get_function_name   = pinmux_generic_get_function_name,
> > +       .get_function_groups = pinmux_generic_get_function_groups,
> > +       .set_mux             = jhb100_set_mux,
> > +};
> 
> Implement .gpio_request_enable() (see above) and
> .gpio_set_direction() see below.
> 
> Maybe also .gpio_disable_free() if you need to deconfigure stuff when a pin is
> release from GPIO.
> 
> > +static const struct pinconf_ops jhb100_pinconf_ops = {
> > +       .pin_config_get         = jhb100_pinconf_get,
> > +       .pin_config_set         = jhb100_pinconf_set,
> > +       .pin_config_group_get   = jhb100_pinconf_group_get,
> > +       .pin_config_group_set   = jhb100_pinconf_group_set,
> > +       .is_generic             = true,
> > +};
> 
> Overall this looks nice, good use of the group config!
> 
> > +static int jhb100_gpio_get_direction(struct gpio_chip *gc,
> > +                                    unsigned int gpio) {
> > +       struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
> > +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> > +       const struct jhb100_pinctrl_domain_info *info = sfp->info;
> > +       unsigned int offset = 4 * bank->id;
> > +       u32 doen;
> > +       void __iomem *reg_gpio_oen;
> > +
> > +       reg_gpio_oen = sfp->base + info->regs->output_en + offset;
> > +
> > +       doen = (readl_relaxed(reg_gpio_oen) & BIT(gpio)) >> gpio;
> > +
> > +       return doen == GPOEN_ENABLE ? GPIO_LINE_DIRECTION_OUT :
> > +GPIO_LINE_DIRECTION_IN; }
> > +
> > +static int jhb100_gpio_direction_input(struct gpio_chip *gc,
> > +                                      unsigned int gpio) {
> > +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> > +       struct device *dev = sfp->dev;
> > +       struct config_reg_layout_desc *crl_desc;
> > +       unsigned int pin = jhb100_gpio_to_pin(gc, gpio);
> > +
> > +       crl_desc = get_crl_desc_by_pin(sfp, pin);
> > +       if (!crl_desc) {
> > +               dev_err(dev, "pin %d can't not found reg layout
> descriptor\n",
> > +                       pin);
> > +               return -EINVAL;
> > +       }
> > +
> > +       jhb100_padcfg_rmw(sfp, pin,
> > +                         RL_DESC_GENMASK(crl_desc,
> input_enable) |
> > +                         RL_DESC_GENMASK(crl_desc,
> schmitt_trigger_select),
> > +                         RL_DESC_GENMASK(crl_desc,
> input_enable) |
> > +                         RL_DESC_GENMASK(crl_desc,
> > + schmitt_trigger_select));
> 
> Instead of doing these writes directly into the config registers, implement
> .gpio_set_direction() in struct pinmux_ops and call the pinmux generic
> back-end.
> 
> > +static int jhb100_gpio_direction_output(struct gpio_chip *gc,
> > +                                       unsigned int gpio, int
> value)
> > +{
> > +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> > +       struct device *dev = sfp->dev;
> > +       struct config_reg_layout_desc *crl_desc;
> > +       unsigned int pin = jhb100_gpio_to_pin(gc, gpio);
> > +
> > +       jhb100_set_one_pin_mux(sfp, pin, 0,
> > +                              value ? GPOUT_HIGH :
> GPOUT_LOW);
> > +
> > +       crl_desc = get_crl_desc_by_pin(sfp, pin);
> > +       if (!crl_desc) {
> > +               dev_err(dev, "pin %d can't not found reg layout
> descriptor\n",
> > +                       pin);
> > +               return -EINVAL;
> > +       }
> > +
> > +       jhb100_padcfg_rmw(sfp, pin,
> > +                         RL_DESC_GENMASK(crl_desc,
> input_enable) |
> > +                         RL_DESC_GENMASK(crl_desc,
> schmitt_trigger_select) |
> > +                         RL_DESC_GENMASK(crl_desc, pull_down) |
> > +                         RL_DESC_GENMASK(crl_desc, pull_up),
> > +                         0);
> 
> Dito.
> 
> > +static int jhb100_gpio_get(struct gpio_chip *gc, unsigned int gpio) {
> > +       struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
> > +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> > +       const struct jhb100_pinctrl_domain_info *info = sfp->info;
> > +       unsigned int offset = 4 * bank->id;
> > +       u32 doen = 0;
> > +       void __iomem *reg_gpio_oen;
> > +       void __iomem *reg;
> > +       unsigned long flags;
> > +
> > +       reg_gpio_oen = sfp->base + info->regs->output_en + offset;
> > +       reg = sfp->base + info->regs->gpio_status + offset;
> > +
> > +       raw_spin_lock_irqsave(&sfp->lock, flags);
> > +       doen = readl_relaxed(reg_gpio_oen) | BIT(gpio);
> > +       writel_relaxed(doen, reg_gpio_oen);
> > +       raw_spin_unlock_irqrestore(&sfp->lock, flags);
> 
> Why *on* *earth* are you read-modify-writing the output enable register in
> the *get* function? Is this a copy-on-paste error??
> 
> > +       return !!(readl_relaxed(reg) & BIT(gpio % 32));
> 
> Also you never actuall read reg .... ehhhh this is a glaring bug.
> 
> > +static int jhb100_gpio_set(struct gpio_chip *gc, unsigned int gpio,
> > +int value) {
> > +       struct jhb100_gpio_bank *bank = jhb100_gc_to_bank(gc);
> > +       struct jhb100_pinctrl *sfp = gpiochip_get_data(gc);
> > +       const struct jhb100_pinctrl_domain_info *info = sfp->info;
> > +       unsigned int offset = 4 * bank->id;
> > +       void __iomem *reg_dout;
> > +       u32 dout;
> > +       unsigned long flags;
> > +
> > +       reg_dout = sfp->base + info->regs->output + offset;
> > +       dout = (value ? GPOUT_HIGH : GPOUT_LOW) << gpio;
> > +
> > +       raw_spin_lock_irqsave(&sfp->lock, flags);
> > +       dout |= readl_relaxed(reg_dout) & ~BIT(gpio);
> > +       writel_relaxed(dout, reg_dout);
> > +       raw_spin_unlock_irqrestore(&sfp->lock, flags);
> > +
> > +       return 0;
> > +}
> 
> This looks right, did you only test output and not input..?
> 
> > +static const struct irq_chip jhb100_irq_chip = {
> > +       .irq_ack        = jhb100_irq_ack,
> > +       .irq_mask       = jhb100_irq_mask,
> > +       .irq_mask_ack   = jhb100_irq_mask_ack,
> > +       .irq_unmask     = jhb100_irq_unmask,
> > +       .irq_set_type   = jhb100_irq_set_type,
> > +       .irq_set_wake   = jhb100_irq_set_wake,
> > +       .irq_print_chip = jhb100_irq_print_chip,
> > +       .flags          = IRQCHIP_SET_TYPE_MASKED |
> > +                         IRQCHIP_IMMUTABLE |
> > +                         IRQCHIP_ENABLE_WAKEUP_ON_SUSPEND
> |
> > +                         IRQCHIP_MASK_ON_SUSPEND |
> > +                         IRQCHIP_SKIP_SET_WAKE,
> > +       GPIOCHIP_IRQ_RESOURCE_HELPERS, };
> 
> The irqchip looks good!
> 
> > +static int field_compare(const void *a, const void *b) {
> > +       const struct field_info *fa = (const struct field_info *)a;
> > +       const struct field_info *fb = (const struct field_info *)b;
> > +
> > +       if (fa->shift < fb->shift)
> > +               return -1;
> > +
> > +       if (fa->shift > fb->shift)
> > +               return 1;
> > +
> > +       return 0;
> > +}
> 
> Are you sure the kernel doesn't already have a helper like this...
> 
> > +       sfp->num_banks = DIV_ROUND_UP(sfp->ngpios,
> > + JHB100_NR_GPIOS_PER_BANK);
> > +
> > +       for (unsigned int i = 0; i < sfp->num_banks; i++) {
> > +               if (sfp->ngpios > (i + 1) *
> JHB100_NR_GPIOS_PER_BANK)
> > +                       sfp->banks[i].gc.ngpio = (i + 1) *
> JHB100_NR_GPIOS_PER_BANK;
> > +               else
> > +                       sfp->banks[i].gc.ngpio = sfp->ngpios - i *
> > + JHB100_NR_GPIOS_PER_BANK;
> 
> This looks completely bananas, shouldn't this be simply:
> 
> sfp->banks[i].gc.ngpio = JHB100_NR_GPIOS_PER_BANK;
> 
> ???
> 
> What is getting assigned to ngpios looks like a gpiochip base, and have all the
> signs of a real bad AI hallucination.
> 
> > +
> > +               sfp->banks[i].id = i;
> > +
> > +               sfp->banks[i].gc.parent = dev;
> > +               sfp->banks[i].gc.label = dev_name(dev);
> > +               sfp->banks[i].gc.owner = THIS_MODULE;
> > +               sfp->banks[i].gc.request = pinctrl_gpio_request;
> 
> Use
> gpiochip_generic_request
> 
> > +               sfp->banks[i].gc.free = pinctrl_gpio_free;
> 
> Use
> gpiochip_generic_free
> 
> These calls will do what you want, and also check that the right gpio ranges
> are available.
> 
> Make sure you add GPIO ranges (the mapping between pin control pins and
> corresponding GPIO offsets) for this to work properly.
> 
> I'm pretty sure you can have a generic pin config backend as well.
> 
> sfp->banks[i].gc.set_config = gpiochip_generic_config;
> 
> This will make config calls to the gpiochip call into the pinctrl backend = what
> you want.
> 
> > +               sfp->banks[i].gc.get_direction =
> jhb100_gpio_get_direction;
> > +               sfp->banks[i].gc.direction_input =
> jhb100_gpio_direction_input;
> > +               sfp->banks[i].gc.direction_output =
> jhb100_gpio_direction_output;
> > +               sfp->banks[i].gc.get = jhb100_gpio_get;
> > +               sfp->banks[i].gc.set = jhb100_gpio_set;
> > +               sfp->banks[i].gc.set_config = gpiochip_generic_config;
> > +               sfp->banks[i].gc.base = -1;
> > +               sfp->banks[i].gc.of_gpio_n_cells = 3;
> > +               sfp->banks[i].gc.of_node_instance_match =
> > + starfive_of_node_instance_match;
> 
> Since you have a threecell scheme with 32 gpios
> (JHB100_NR_GPIOS_PER_BANK)  per instance (right? the ngpios code above
> made me really confused....) you should be able so select GPIO_GENERIC,
> #include <linux/gpio/generic.h> and use the generic GPIO pretty much the
> same way drivers/gpio/gpio-spacemit-k1.c does it, check that driver out
> (especially spacemit_gpio_add_bank()).
> 
> Yours,
> Linus Walleij

From namcao at linutronix.de  Fri Jun 19 02:11:25 2026
From: namcao at linutronix.de (Nam Cao)
Date: Fri, 19 Jun 2026 11:11:25 +0200
Subject: [PATCH v2] riscv: stacktrace: fix stack-out-of-bounds in
 walk_stackframe()
In-Reply-To: <DIM3B5ZM2WCI.27FLMTRS5IYNN@gmail.com>
References: <20260517143704.659416-1-xujiakai2025@iscas.ac.cn>
 <DIM3B5ZM2WCI.27FLMTRS5IYNN@gmail.com>
Message-ID: <8733yi6gjm.fsf@yellow.woof>

"Matthew Bystrin" <dev.mbstr at gmail.com> writes:
>> +	high = (unsigned long)task_pt_regs(task);
>
> After noticing end_of_stack() function I'm not sure task_pt_regs() is the best
> candidate for the boundary. Let's see what maintainers are going to say.

end_of_stack() is the lower bound of the stack, that's not what we want.

Nam


From peterz at infradead.org  Fri Jun 19 02:41:30 2026
From: peterz at infradead.org (Peter Zijlstra)
Date: Fri, 19 Jun 2026 11:41:30 +0200
Subject: [PATCH RFC 1/3] cpu/hotplug: Introduce
 CONFIG_PARALLEL_SMT_PRIMARY_FIRST
In-Reply-To: <87a4srdgk0.ffs@fw13>
References: <20260611133809.3854977-1-ruanjinjie@huawei.com>
 <20260611133809.3854977-2-ruanjinjie@huawei.com>
 <87a4srdgk0.ffs@fw13>
Message-ID: <20260619094130.GU49951@noisy.programming.kicks-ass.net>

On Thu, Jun 18, 2026 at 05:17:03PM +0200, Thomas Gleixner wrote:

> Something simple like the uncompiled below should just work, no?
> 
> ---
> --- a/arch/Kconfig
> +++ b/arch/Kconfig
> @@ -102,6 +102,10 @@ config HOTPLUG_PARALLEL
>  	bool
>  	select HOTPLUG_SPLIT_STARTUP
>  
> +config HOTPLUG_PARALLEL_SMT
> +	bool
> +	select HOTPLUG_PARALLEL

	depends on ARCH_SUPPORTS_SCHED_SMT ?


From namcao at linutronix.de  Fri Jun 19 02:51:28 2026
From: namcao at linutronix.de (Nam Cao)
Date: Fri, 19 Jun 2026 11:51:28 +0200
Subject: [PATCH v2] riscv: stacktrace: fix stack-out-of-bounds in
 walk_stackframe()
In-Reply-To: <20260517143704.659416-1-xujiakai2025@iscas.ac.cn>
References: <20260517143704.659416-1-xujiakai2025@iscas.ac.cn>
Message-ID: <87zf0q504f.fsf@yellow.woof>

Jiakai Xu <xujiakai2025 at iscas.ac.cn> writes:
> +	if (!task)
> +		task = current;
> +
> +	high = (unsigned long)task_pt_regs(task);

I am concerned when CONFIG_IRQ_STACKS=y and we are on the irq stack,
wouldn't this "high" be the wrong one?

I haven't validated it, we probably need something like

if (on_thread_stack()) {
	if (!task)
        	task = current;
	high = (unsigned long)task_pt_regs(task);
} else {
	high = per_cpu(irq_stack_ptr, smp_processor_id()) + IRQ_STACK_SIZE/sizeof(ulong);
}

Nam


From namcao at linutronix.de  Fri Jun 19 03:23:17 2026
From: namcao at linutronix.de (Nam Cao)
Date: Fri, 19 Jun 2026 12:23:17 +0200
Subject: [PATCH] riscv: Add build salt to the vDSO
In-Reply-To: <ajQY7n0an0YwQ--j@steamhammer.waldi.eu.org>
References: <ajQY7n0an0YwQ--j@steamhammer.waldi.eu.org>
Message-ID: <87v7be4yne.fsf@yellow.woof>

Bastian Blank <waldi at debian.org> writes:
> The vDSO needs to have a unique build id in a similar manner
> to the kernel and modules. Use the build salt macro.
>
> Signed-off-by: Bastian Blank <waldi at debian.org>

Reviewed-by: Nam Cao <namcao at linutronix.de>


