Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [PATCH RFC v4 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support
@ 2026-09-21 12:27 GUO Ren (XuanTie)
  2026-09-21 12:27 ` [PATCH RFC v4 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend GUO Ren (XuanTie)
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: GUO Ren (XuanTie) @ 2026-09-21 12:27 UTC (permalink / raw)
  To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Fangyu Yu, CHEN Jiankang
  Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-doc,
	Leonardo Bras, GUO Ren (XuanTie)

Paravirtualized spinlocks allow an unfair qspinlock to replace the
ticket-lock or native fair qspinlock implementation with something
virtualization-friendly, for example, halting the virtual CPU rather
than spinning.

You can observe the paravirt qspinlock behavior with the pv_kick and
pv_wait tracepoints under /sys/kernel/debug/tracing/:

  # echo 1 > /sys/kernel/debug/tracing/events/paravirt/enable
  # cat /sys/kernel/debug/tracing/trace
            TASK-PID     CPU#  |||||  TIMESTAMP  FUNCTION
               | |         |   |||||     |         |
             sh-100     [001] d..2.    28.312294: pv_wait: cpu 1 out of wfi
         <idle>-0       [000] d.h4.    28.322030: pv_kick: cpu 0 kick target cpu 1

This series is split from [1]. The newest discussion is at [2].

[1]: https://lore.kernel.org/linux-riscv/20231225125847.2778638-1-guoren@kernel.org/
[2]: https://lists.riscv.org/g/tech-prs/message/1211

Changelog:
v4:
 - Rebase onto v7.3-rc4.
 - Normalize the author identity to "GUO Ren (XuanTie)".
 - Minor commit log cleanups (fix line-wrap artifacts and typos).

v3:
https://lore.kernel.org/linux-riscv/20251201003041.695081-1-guoren@kernel.org/
 - Rebase on linux-6.18-rc7.
 - Simplify nopvspin usage.

v2:
https://lore.kernel.org/linux-riscv/20241227011011.2331381-1-guoren@kernel.org/
 - Add RFC tag.
 - Using new SBI_EXT_PVLOCK ID.
 - Add virt_spin_lock support.
 - Add nopvspin support.

v1:
https://lore.kernel.org/linux-riscv/20241222033917.1754495-1-guoren@kernel.org/

GUO Ren (XuanTie) (5):
  RISC-V: Add PARAVIRT_SPINLOCKS support
  RISC-V: paravirt: Add pvqspinlock KVM backend
  RISC-V: paravirt: Add pvqspinlock frontend
  RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait
  RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS

 .../admin-guide/kernel-parameters.txt         |  2 +-
 arch/riscv/Kconfig                            | 12 +++
 arch/riscv/include/asm/Kbuild                 |  1 -
 arch/riscv/include/asm/kvm_vcpu_sbi.h         |  1 +
 arch/riscv/include/asm/qspinlock.h            | 57 +++++++++++++
 arch/riscv/include/asm/qspinlock_paravirt.h   | 26 ++++++
 arch/riscv/include/asm/sbi.h                  |  5 ++
 arch/riscv/include/uapi/asm/kvm.h             |  1 +
 arch/riscv/kernel/Makefile                    |  2 +
 arch/riscv/kernel/qspinlock_paravirt.c        | 82 +++++++++++++++++++
 arch/riscv/kernel/setup.c                     |  5 ++
 .../kernel/trace_events_filter_paravirt.h     | 58 +++++++++++++
 arch/riscv/kvm/Makefile                       |  1 +
 arch/riscv/kvm/vcpu_sbi.c                     |  4 +
 arch/riscv/kvm/vcpu_sbi_pvlock.c              | 54 ++++++++++++
 15 files changed, 309 insertions(+), 2 deletions(-)
 create mode 100644 arch/riscv/include/asm/qspinlock.h
 create mode 100644 arch/riscv/include/asm/qspinlock_paravirt.h
 create mode 100644 arch/riscv/kernel/qspinlock_paravirt.c
 create mode 100644 arch/riscv/kernel/trace_events_filter_paravirt.h
 create mode 100644 arch/riscv/kvm/vcpu_sbi_pvlock.c

--
2.43.1

---
GUO Ren (XuanTie) (4):
      RISC-V: paravirt: Add pvqspinlock KVM backend
      RISC-V: paravirt: Add pvqspinlock frontend
      RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait
      RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS

 Documentation/admin-guide/kernel-parameters.txt  |  2 +-
 arch/riscv/Kconfig                               | 12 ++++
 arch/riscv/include/asm/Kbuild                    |  1 -
 arch/riscv/include/asm/kvm_vcpu_sbi.h            |  1 +
 arch/riscv/include/asm/qspinlock.h               | 57 ++++++++++++++++
 arch/riscv/include/asm/qspinlock_paravirt.h      | 26 ++++++++
 arch/riscv/include/asm/sbi.h                     |  5 ++
 arch/riscv/include/uapi/asm/kvm.h                |  1 +
 arch/riscv/kernel/Makefile                       |  2 +
 arch/riscv/kernel/qspinlock_paravirt.c           | 82 ++++++++++++++++++++++++
 arch/riscv/kernel/setup.c                        |  5 ++
 arch/riscv/kernel/trace_events_filter_paravirt.h | 58 +++++++++++++++++
 arch/riscv/kvm/Makefile                          |  1 +
 arch/riscv/kvm/vcpu_sbi.c                        |  4 ++
 arch/riscv/kvm/vcpu_sbi_pvlock.c                 | 54 ++++++++++++++++
 15 files changed, 309 insertions(+), 2 deletions(-)
---
base-commit: 93f51579e7df248780214094418f205253383cc5
change-id: 20260921-pvqspinlock-73ad0cfb45b1

Best regards,
--  
GUO Ren (XuanTie) <guoren@kernel.org>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH RFC v4 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend
  2026-09-21 12:27 [PATCH RFC v4 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support GUO Ren (XuanTie)
@ 2026-09-21 12:27 ` GUO Ren (XuanTie)
  2026-09-21 12:35   ` sashiko-bot
  2026-09-21 12:27 ` [PATCH RFC v4 2/4] RISC-V: paravirt: Add pvqspinlock frontend GUO Ren (XuanTie)
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: GUO Ren (XuanTie) @ 2026-09-21 12:27 UTC (permalink / raw)
  To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Fangyu Yu, CHEN Jiankang
  Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-doc,
	Leonardo Bras, GUO Ren (XuanTie)

Add the KVM backend for the SBI PVLOCK (paravirt qspinlock kick_cpu)
extension. kvm_sbi_ext_pvlock_kick_cpu() kicks the target vCPU out of
the halted state via kvm_vcpu_kick(), and yields to it with
kvm_vcpu_yield_to() when the target is already runnable.

Reviewed-by: Leonardo Bras <leobras@redhat.com>
Signed-off-by: GUO Ren (XuanTie) <guoren@kernel.org>
---
 arch/riscv/include/asm/kvm_vcpu_sbi.h |  1 +
 arch/riscv/include/asm/sbi.h          |  5 ++++
 arch/riscv/include/uapi/asm/kvm.h     |  1 +
 arch/riscv/kvm/Makefile               |  1 +
 arch/riscv/kvm/vcpu_sbi.c             |  4 +++
 arch/riscv/kvm/vcpu_sbi_pvlock.c      | 54 +++++++++++++++++++++++++++++++++++
 6 files changed, 66 insertions(+)

diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h
index f01a2860c751..cdc16e64ad19 100644
--- a/arch/riscv/include/asm/kvm_vcpu_sbi.h
+++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h
@@ -114,6 +114,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_mpxy;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_experimental;
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_vendor;
+extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pvlock;
 
 #ifdef CONFIG_RISCV_PMU_SBI
 extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pmu;
diff --git a/arch/riscv/include/asm/sbi.h b/arch/riscv/include/asm/sbi.h
index 5725e0ca4dda..724ab834ad85 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -38,6 +38,7 @@ enum sbi_ext_id {
 	SBI_EXT_FWFT = 0x46574654,
 	SBI_EXT_MPXY = 0x4D505859,
 	SBI_EXT_DBTR = 0x44425452,
+	SBI_EXT_PVLOCK = 0x50564C4B,
 
 	/* Experimentals extensions must lie within this range */
 	SBI_EXT_EXPERIMENTAL_START = 0x08000000,
@@ -534,6 +535,10 @@ union sbi_dbtr_shmem_entry {
 	struct sbi_dbtr_id_msg id;
 };
 
+enum sbi_ext_pvlock_fid {
+	SBI_EXT_PVLOCK_KICK_CPU = 0,
+};
+
 /* SBI spec version fields */
 #define SBI_SPEC_VERSION_DEFAULT	0x1
 #define SBI_SPEC_VERSION_MAJOR_SHIFT	24
diff --git a/arch/riscv/include/uapi/asm/kvm.h b/arch/riscv/include/uapi/asm/kvm.h
index 20d9959ca44f..110a0d62113f 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -228,6 +228,7 @@ enum KVM_RISCV_SBI_EXT_ID {
 	KVM_RISCV_SBI_EXT_SUSP,
 	KVM_RISCV_SBI_EXT_FWFT,
 	KVM_RISCV_SBI_EXT_MPXY,
+	KVM_RISCV_SBI_EXT_PVLOCK,
 	KVM_RISCV_SBI_EXT_MAX,
 };
 
diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile
index 296c2ba05089..404a4c5f8984 100644
--- a/arch/riscv/kvm/Makefile
+++ b/arch/riscv/kvm/Makefile
@@ -38,6 +38,7 @@ kvm-y += vcpu_sbi_sta.o
 kvm-y += vcpu_sbi_system.o
 kvm-$(CONFIG_RISCV_SBI_V01) += vcpu_sbi_v01.o
 kvm-y += vcpu_switch.o
+kvm-y += vcpu_sbi_pvlock.o
 kvm-y += vcpu_timer.o
 kvm-y += vcpu_vector.o
 kvm-y += vm.o
diff --git a/arch/riscv/kvm/vcpu_sbi.c b/arch/riscv/kvm/vcpu_sbi.c
index 1c4f874368fb..07f72e619fd5 100644
--- a/arch/riscv/kvm/vcpu_sbi.c
+++ b/arch/riscv/kvm/vcpu_sbi.c
@@ -94,6 +94,10 @@ static const struct kvm_riscv_sbi_extension_entry sbi_ext[] = {
 		.ext_idx = KVM_RISCV_SBI_EXT_VENDOR,
 		.ext_ptr = &vcpu_sbi_ext_vendor,
 	},
+	{
+		.ext_idx = KVM_RISCV_SBI_EXT_PVLOCK,
+		.ext_ptr = &vcpu_sbi_ext_pvlock,
+	},
 };
 
 static const struct kvm_riscv_sbi_extension_entry *
diff --git a/arch/riscv/kvm/vcpu_sbi_pvlock.c b/arch/riscv/kvm/vcpu_sbi_pvlock.c
new file mode 100644
index 000000000000..728e59f3f18f
--- /dev/null
+++ b/arch/riscv/kvm/vcpu_sbi_pvlock.c
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 GUO Ren (XuanTie) <guoren@kernel.org>
+ */
+
+#include <linux/errno.h>
+#include <linux/err.h>
+#include <linux/kvm_host.h>
+#include <asm/sbi.h>
+#include <asm/kvm_vcpu_sbi.h>
+
+static int kvm_sbi_ext_pvlock_kick_cpu(struct kvm_vcpu *vcpu)
+{
+	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
+	struct kvm *kvm = vcpu->kvm;
+	struct kvm_vcpu *target;
+
+	target = kvm_get_vcpu_by_id(kvm, cp->a0);
+	if (!target)
+		return SBI_ERR_INVALID_PARAM;
+
+	kvm_vcpu_kick(target);
+
+	if (READ_ONCE(target->ready))
+		kvm_vcpu_yield_to(target);
+
+	return SBI_SUCCESS;
+}
+
+static int kvm_sbi_ext_pvlock_handler(struct kvm_vcpu *vcpu, struct kvm_run *run,
+				      struct kvm_vcpu_sbi_return *retdata)
+{
+	int ret = 0;
+	struct kvm_cpu_context *cp = &vcpu->arch.guest_context;
+	unsigned long funcid = cp->a6;
+
+	switch (funcid) {
+	case SBI_EXT_PVLOCK_KICK_CPU:
+		ret = kvm_sbi_ext_pvlock_kick_cpu(vcpu);
+		break;
+	default:
+		ret = SBI_ERR_NOT_SUPPORTED;
+	}
+
+	retdata->err_val = ret;
+
+	return 0;
+}
+
+const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pvlock = {
+	.extid_start = SBI_EXT_PVLOCK,
+	.extid_end = SBI_EXT_PVLOCK,
+	.handler = kvm_sbi_ext_pvlock_handler,
+};

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC v4 2/4] RISC-V: paravirt: Add pvqspinlock frontend
  2026-09-21 12:27 [PATCH RFC v4 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support GUO Ren (XuanTie)
  2026-09-21 12:27 ` [PATCH RFC v4 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend GUO Ren (XuanTie)
@ 2026-09-21 12:27 ` GUO Ren (XuanTie)
  2026-09-21 12:41   ` sashiko-bot
  2026-09-21 12:27 ` [PATCH RFC v4 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait GUO Ren (XuanTie)
  2026-09-21 12:27 ` [PATCH RFC v4 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS GUO Ren (XuanTie)
  3 siblings, 1 reply; 9+ messages in thread
From: GUO Ren (XuanTie) @ 2026-09-21 12:27 UTC (permalink / raw)
  To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Fangyu Yu, CHEN Jiankang
  Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-doc,
	Leonardo Bras, GUO Ren (XuanTie)

Add a virtualization-friendly unfair qspinlock frontend that halts the
virtual CPU instead of spinning.

Use static_call to switch between:
  native_queued_spin_lock_slowpath()    __pv_queued_spin_lock_slowpath()
  native_queued_spin_unlock()           __pv_queued_spin_unlock()

Add the pv_wait and pv_kick implementations.

Reviewed-by: Leonardo Bras <leobras@redhat.com>
Signed-off-by: GUO Ren (XuanTie) <guoren@kernel.org>
---
 arch/riscv/Kconfig                          | 12 ++++++
 arch/riscv/include/asm/Kbuild               |  1 -
 arch/riscv/include/asm/qspinlock.h          | 33 ++++++++++++++
 arch/riscv/include/asm/qspinlock_paravirt.h | 26 +++++++++++
 arch/riscv/kernel/Makefile                  |  2 +
 arch/riscv/kernel/qspinlock_paravirt.c      | 67 +++++++++++++++++++++++++++++
 arch/riscv/kernel/setup.c                   |  5 +++
 7 files changed, 145 insertions(+), 1 deletion(-)

diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index d6c2dbf8455c..9af53ef5ee95 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -1165,6 +1165,18 @@ config PARAVIRT_TIME_ACCOUNTING
 
 	  If in doubt, say N here.
 
+config PARAVIRT_SPINLOCKS
+	bool "Paravirtualization layer for spinlocks"
+	depends on QUEUED_SPINLOCKS
+	default y
+	help
+	  Paravirtualized spinlocks allow a unfair qspinlock to replace the
+	  test-set kvm-guest virt spinlock implementation with something
+	  virtualization-friendly, for example, halt the virtual CPU rather
+	  than spinning.
+
+	  If you are unsure how to answer this question, answer Y.
+
 config RELOCATABLE
 	bool "Build a relocatable kernel"
 	select MODULE_SECTIONS if MODULES
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild
index 7721b63642f4..3d8800d4fe48 100644
--- a/arch/riscv/include/asm/Kbuild
+++ b/arch/riscv/include/asm/Kbuild
@@ -13,7 +13,6 @@ generic-y += spinlock_types.h
 generic-y += ticket_spinlock.h
 generic-y += qrwlock.h
 generic-y += qrwlock_types.h
-generic-y += qspinlock.h
 generic-y += ring_buffer.h
 generic-y += user.h
 generic-y += vmlinux.lds.h
diff --git a/arch/riscv/include/asm/qspinlock.h b/arch/riscv/include/asm/qspinlock.h
new file mode 100644
index 000000000000..330b714edc44
--- /dev/null
+++ b/arch/riscv/include/asm/qspinlock.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 GUO Ren (XuanTie) <guoren@kernel.org>
+ */
+
+#ifndef _ASM_RISCV_QSPINLOCK_H
+#define _ASM_RISCV_QSPINLOCK_H
+
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
+#include <asm/qspinlock_paravirt.h>
+
+/* How long a lock should spin before we consider blocking */
+#define SPIN_THRESHOLD		(1 << 15)
+
+void native_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
+void __pv_init_lock_hash(void);
+void __pv_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
+
+static inline void queued_spin_lock_slowpath(struct qspinlock *lock, u32 val)
+{
+	static_call(pv_queued_spin_lock_slowpath)(lock, val);
+}
+
+#define queued_spin_unlock	queued_spin_unlock
+static inline void queued_spin_unlock(struct qspinlock *lock)
+{
+	static_call(pv_queued_spin_unlock)(lock);
+}
+#endif /* CONFIG_PARAVIRT_SPINLOCKS */
+
+#include <asm-generic/qspinlock.h>
+
+#endif /* _ASM_RISCV_QSPINLOCK_H */
diff --git a/arch/riscv/include/asm/qspinlock_paravirt.h b/arch/riscv/include/asm/qspinlock_paravirt.h
new file mode 100644
index 000000000000..7261cd9b13b2
--- /dev/null
+++ b/arch/riscv/include/asm/qspinlock_paravirt.h
@@ -0,0 +1,26 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 GUO Ren (XuanTie) <guoren@kernel.org>
+ */
+
+#ifndef _ASM_RISCV_QSPINLOCK_PARAVIRT_H
+#define _ASM_RISCV_QSPINLOCK_PARAVIRT_H
+
+void pv_wait(u8 *ptr, u8 val);
+void pv_kick(int cpu);
+
+void dummy_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
+void dummy_queued_spin_unlock(struct qspinlock *lock);
+
+DECLARE_STATIC_CALL(pv_queued_spin_lock_slowpath, dummy_queued_spin_lock_slowpath);
+DECLARE_STATIC_CALL(pv_queued_spin_unlock, dummy_queued_spin_unlock);
+
+bool __init pv_qspinlock_init(void);
+
+void __pv_queued_spin_unlock_slowpath(struct qspinlock *lock, u8 locked);
+
+bool pv_is_native_spin_unlock(void);
+
+void __pv_queued_spin_unlock(struct qspinlock *lock);
+
+#endif /* _ASM_RISCV_QSPINLOCK_PARAVIRT_H */
diff --git a/arch/riscv/kernel/Makefile b/arch/riscv/kernel/Makefile
index ebe1c3588177..b9b0763dba32 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -130,3 +130,5 @@ obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.o
 obj-$(CONFIG_RISCV_USER_CFI) += usercfi.o
 
 obj-$(CONFIG_RISCV_ISA_SSQOSID) += qos.o
+
+obj-$(CONFIG_PARAVIRT_SPINLOCKS) += qspinlock_paravirt.o
diff --git a/arch/riscv/kernel/qspinlock_paravirt.c b/arch/riscv/kernel/qspinlock_paravirt.c
new file mode 100644
index 000000000000..c534447437fe
--- /dev/null
+++ b/arch/riscv/kernel/qspinlock_paravirt.c
@@ -0,0 +1,67 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2026 GUO Ren (XuanTie) <guoren@kernel.org>
+ */
+
+#include <linux/static_call.h>
+#include <asm/qspinlock_paravirt.h>
+#include <asm/sbi.h>
+
+void pv_kick(int cpu)
+{
+	sbi_ecall(SBI_EXT_PVLOCK, SBI_EXT_PVLOCK_KICK_CPU,
+		  cpuid_to_hartid_map(cpu), 0, 0, 0, 0, 0);
+}
+
+void pv_wait(u8 *ptr, u8 val)
+{
+	unsigned long flags;
+
+	if (in_nmi())
+		return;
+
+	local_irq_save(flags);
+	if (READ_ONCE(*ptr) != val)
+		goto out;
+
+	wait_for_interrupt();
+out:
+	local_irq_restore(flags);
+}
+
+static void native_queued_spin_unlock(struct qspinlock *lock)
+{
+	/*
+	 * unlock() needs release semantics:
+	 */
+	smp_store_release(&lock->locked, 0);
+}
+
+DEFINE_STATIC_CALL(pv_queued_spin_lock_slowpath, native_queued_spin_lock_slowpath);
+EXPORT_STATIC_CALL(pv_queued_spin_lock_slowpath);
+
+DEFINE_STATIC_CALL(pv_queued_spin_unlock, native_queued_spin_unlock);
+EXPORT_STATIC_CALL(pv_queued_spin_unlock);
+
+bool __init pv_qspinlock_init(void)
+{
+	if (num_possible_cpus() == 1)
+		return false;
+
+	if (!sbi_probe_extension(SBI_EXT_PVLOCK))
+		return false;
+
+	pr_info("PV qspinlocks enabled\n");
+	__pv_init_lock_hash();
+
+	static_call_update(pv_queued_spin_lock_slowpath, __pv_queued_spin_lock_slowpath);
+	static_call_update(pv_queued_spin_unlock, __pv_queued_spin_unlock);
+
+	return true;
+}
+
+bool pv_is_native_spin_unlock(void)
+{
+	return static_call_query(pv_queued_spin_unlock) ==
+	       native_queued_spin_unlock;
+}
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index a32344bb220d..ccfa92b7c81a 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -281,6 +281,11 @@ static void __init riscv_spinlock_init(void)
 		return;
 	}
 
+#ifdef CONFIG_PARAVIRT_SPINLOCKS
+	if (pv_qspinlock_init())
+		return;
+#endif
+
 	if (IS_ENABLED(CONFIG_RISCV_ISA_ZABHA) &&
 	    IS_ENABLED(CONFIG_RISCV_ISA_ZACAS) &&
 	    IS_ENABLED(CONFIG_TOOLCHAIN_HAS_ZACAS) &&

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC v4 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait
  2026-09-21 12:27 [PATCH RFC v4 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support GUO Ren (XuanTie)
  2026-09-21 12:27 ` [PATCH RFC v4 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend GUO Ren (XuanTie)
  2026-09-21 12:27 ` [PATCH RFC v4 2/4] RISC-V: paravirt: Add pvqspinlock frontend GUO Ren (XuanTie)
@ 2026-09-21 12:27 ` GUO Ren (XuanTie)
  2026-09-21 12:39   ` sashiko-bot
  2026-09-21 12:27 ` [PATCH RFC v4 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS GUO Ren (XuanTie)
  3 siblings, 1 reply; 9+ messages in thread
From: GUO Ren (XuanTie) @ 2026-09-21 12:27 UTC (permalink / raw)
  To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Fangyu Yu, CHEN Jiankang
  Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-doc,
	Leonardo Bras, GUO Ren (XuanTie)

Add tracepoints for pv_kick and pv_wait to observe the paravirt
qspinlock behavior:

  # cd /sys/kernel/debug/tracing
  # echo 1 > events/paravirt/enable
  # cat trace
  TASK-PID   CPU#  |||||  TIMESTAMP  FUNCTION
     | |       |   |||||     |         |
    sh-100   [001] d..2.  28.312294: pv_wait: cpu 1 out of wfi
  <idle>-0   [000] d.h4.  28.322030: pv_kick: cpu 0 kick target cpu 1

Reviewed-by: Leonardo Bras <leobras@redhat.com>
Signed-off-by: GUO Ren (XuanTie) <guoren@kernel.org>
---
 arch/riscv/kernel/qspinlock_paravirt.c           |  7 +++
 arch/riscv/kernel/trace_events_filter_paravirt.h | 58 ++++++++++++++++++++++++
 2 files changed, 65 insertions(+)

diff --git a/arch/riscv/kernel/qspinlock_paravirt.c b/arch/riscv/kernel/qspinlock_paravirt.c
index c534447437fe..04b13994e971 100644
--- a/arch/riscv/kernel/qspinlock_paravirt.c
+++ b/arch/riscv/kernel/qspinlock_paravirt.c
@@ -7,8 +7,13 @@
 #include <asm/qspinlock_paravirt.h>
 #include <asm/sbi.h>
 
+#define CREATE_TRACE_POINTS
+#include "trace_events_filter_paravirt.h"
+
 void pv_kick(int cpu)
 {
+	trace_pv_kick(smp_processor_id(), cpu);
+
 	sbi_ecall(SBI_EXT_PVLOCK, SBI_EXT_PVLOCK_KICK_CPU,
 		  cpuid_to_hartid_map(cpu), 0, 0, 0, 0, 0);
 }
@@ -25,6 +30,8 @@ void pv_wait(u8 *ptr, u8 val)
 		goto out;
 
 	wait_for_interrupt();
+
+	trace_pv_wait(smp_processor_id());
 out:
 	local_irq_restore(flags);
 }
diff --git a/arch/riscv/kernel/trace_events_filter_paravirt.h b/arch/riscv/kernel/trace_events_filter_paravirt.h
new file mode 100644
index 000000000000..8d57efda2c17
--- /dev/null
+++ b/arch/riscv/kernel/trace_events_filter_paravirt.h
@@ -0,0 +1,58 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (C) 2026 GUO Ren (XuanTie) <guoren@kernel.org>
+ */
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM paravirt
+
+#if !defined(_TRACE_PARAVIRT_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_PARAVIRT_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(pv_kick,
+	TP_PROTO(int cpu, int target),
+	TP_ARGS(cpu, target),
+
+	TP_STRUCT__entry(
+		__field(int, cpu)
+		__field(int, target)
+	),
+
+	TP_fast_assign(
+		__entry->cpu = cpu;
+		__entry->target = target;
+	),
+
+	TP_printk("cpu %d pv_kick target cpu %d",
+		__entry->cpu,
+		__entry->target
+	)
+);
+
+TRACE_EVENT(pv_wait,
+	TP_PROTO(int cpu),
+	TP_ARGS(cpu),
+
+	TP_STRUCT__entry(
+		__field(int, cpu)
+	),
+
+	TP_fast_assign(
+		__entry->cpu = cpu;
+	),
+
+	TP_printk("cpu %d out of wfi",
+		__entry->cpu
+	)
+);
+
+#endif /* _TRACE_PARAVIRT_H || TRACE_HEADER_MULTI_READ */
+
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH ../../../arch/riscv/kernel/
+#define TRACE_INCLUDE_FILE trace_events_filter_paravirt
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH RFC v4 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS
  2026-09-21 12:27 [PATCH RFC v4 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support GUO Ren (XuanTie)
                   ` (2 preceding siblings ...)
  2026-09-21 12:27 ` [PATCH RFC v4 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait GUO Ren (XuanTie)
@ 2026-09-21 12:27 ` GUO Ren (XuanTie)
  2026-09-21 12:41   ` sashiko-bot
  3 siblings, 1 reply; 9+ messages in thread
From: GUO Ren (XuanTie) @ 2026-09-21 12:27 UTC (permalink / raw)
  To: Anup Patel, Atish Patra, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	Fangyu Yu, CHEN Jiankang
  Cc: kvm, kvm-riscv, linux-riscv, linux-kernel, linux-doc,
	GUO Ren (XuanTie)

VM guests should fall back to a Test-and-Set spinlock when
PARAVIRT_SPINLOCKS is disabled, because fair locks suffer from severe
lock-holder preemption issues. The virt_spin_lock_key shortcuts
queued_spin_lock_slowpath(), allowing virt_spin_lock() to hijack it.
See commit 43b3f02899f7 ("locking/qspinlock/x86: Fix performance
regression under unaccelerated VMs").

Add a static key controlling whether virt_spin_lock() is called, and
add nopvspin support mirroring x86.

Signed-off-by: GUO Ren (XuanTie) <guoren@kernel.org>
---
 Documentation/admin-guide/kernel-parameters.txt |  2 +-
 arch/riscv/include/asm/qspinlock.h              | 24 ++++++++++++++++++++++++
 arch/riscv/kernel/qspinlock_paravirt.c          |  8 ++++++++
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 33cd30996e47..d32bb7db9f91 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4632,7 +4632,7 @@ Kernel parameters
 			as generic guest with no PV drivers. Currently support
 			XEN HVM, KVM, HYPER_V and VMWARE guest.
 
-	nopvspin	[X86,XEN,KVM,EARLY]
+	nopvspin	[X86,RISCV,XEN,KVM,EARLY]
 			Disables the qspinlock slow path using PV optimizations
 			which allow the hypervisor to 'idle' the guest on lock
 			contention.
diff --git a/arch/riscv/include/asm/qspinlock.h b/arch/riscv/include/asm/qspinlock.h
index 330b714edc44..9c7108baa40a 100644
--- a/arch/riscv/include/asm/qspinlock.h
+++ b/arch/riscv/include/asm/qspinlock.h
@@ -12,6 +12,8 @@
 /* How long a lock should spin before we consider blocking */
 #define SPIN_THRESHOLD		(1 << 15)
 
+extern bool nopvspin;
+
 void native_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
 void __pv_init_lock_hash(void);
 void __pv_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
@@ -29,5 +31,27 @@ static inline void queued_spin_unlock(struct qspinlock *lock)
 #endif /* CONFIG_PARAVIRT_SPINLOCKS */
 
 #include <asm-generic/qspinlock.h>
+#include <asm/jump_label.h>
+
+/*
+ * KVM guests fall back to a Test-and-Set spinlock because fair locks suffer
+ * from severe lock-holder-preemption issues. When virt_spin_lock_key is
+ * enabled, virt_spin_lock() shortcuts queued_spin_lock_slowpath() and hijacks
+ * the lock acquisition.
+ */
+DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);
+
+#define virt_spin_lock rv_virt_spin_lock
+static inline bool rv_virt_spin_lock(struct qspinlock *lock)
+{
+	if (!static_branch_likely(&virt_spin_lock_key))
+		return false;
+
+	do {
+		smp_cond_load_relaxed((s32 *)&lock->val, VAL == 0);
+	} while (atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL) != 0);
+
+	return true;
+}
 
 #endif /* _ASM_RISCV_QSPINLOCK_H */
diff --git a/arch/riscv/kernel/qspinlock_paravirt.c b/arch/riscv/kernel/qspinlock_paravirt.c
index 04b13994e971..28c6c78d7e84 100644
--- a/arch/riscv/kernel/qspinlock_paravirt.c
+++ b/arch/riscv/kernel/qspinlock_paravirt.c
@@ -50,6 +50,8 @@ EXPORT_STATIC_CALL(pv_queued_spin_lock_slowpath);
 DEFINE_STATIC_CALL(pv_queued_spin_unlock, native_queued_spin_unlock);
 EXPORT_STATIC_CALL(pv_queued_spin_unlock);
 
+DEFINE_STATIC_KEY_FALSE(virt_spin_lock_key);
+
 bool __init pv_qspinlock_init(void)
 {
 	if (num_possible_cpus() == 1)
@@ -58,6 +60,12 @@ bool __init pv_qspinlock_init(void)
 	if (!sbi_probe_extension(SBI_EXT_PVLOCK))
 		return false;
 
+	if (nopvspin) {
+		static_branch_enable(&virt_spin_lock_key);
+		pr_info("virt_spin_lock enabled by nopvspin\n");
+		return true;
+	}
+
 	pr_info("PV qspinlocks enabled\n");
 	__pv_init_lock_hash();
 

-- 
2.43.0


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v4 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend
  2026-09-21 12:27 ` [PATCH RFC v4 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend GUO Ren (XuanTie)
@ 2026-09-21 12:35   ` sashiko-bot
  0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-09-21 12:35 UTC (permalink / raw)
  To: GUO Ren (XuanTie); +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Critical] kvm: new SBI_EXT_PVLOCK extension is enabled by default breaking migration
--

commit f1e45d3725cd5aab3846041669bc52a712a0d928
Author: GUO Ren (XuanTie) <guoren@kernel.org>

RISC-V: paravirt: Add pvqspinlock KVM backend

Add the KVM backend for the SBI PVLOCK (paravirt qspinlock kick_cpu)
extension. kvm_sbi_ext_pvlock_kick_cpu() kicks the target vCPU out of
the halted state via kvm_vcpu_kick(), and yields to it with
kvm_vcpu_yield_to() when the target is already runnable.

> diff --git a/arch/riscv/kvm/vcpu_sbi_pvlock.c b/arch/riscv/kvm/vcpu_sbi_pvlock.c
> new file mode 100644
> index 0000000000000..728e59f3f18fb
> --- /dev/null
> +++ b/arch/riscv/kvm/vcpu_sbi_pvlock.c
[ ... ]
> +const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_pvlock = {
> +	.extid_start = SBI_EXT_PVLOCK,
> +	.extid_end = SBI_EXT_PVLOCK,
> +	.handler = kvm_sbi_ext_pvlock_handler,
> +};

[Severity: Critical]
Does this extension need to be disabled by default to prevent ABI breakage?

Since vcpu_sbi_ext_pvlock omits .default_disabled, it evaluates to false,
causing KVM to default the extension to KVM_RISCV_SBI_EXT_STATUS_ENABLED
during VM initialization.

Silently enabling new guest-visible KVM features breaks live migration.
Migrating the VM to an older host kernel without this feature will cause
the guest to crash when it attempts to use the extension.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260921-pvqspinlock-v4-0-409a22aed6ef@kernel.org?part=1

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v4 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait
  2026-09-21 12:27 ` [PATCH RFC v4 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait GUO Ren (XuanTie)
@ 2026-09-21 12:39   ` sashiko-bot
  0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-09-21 12:39 UTC (permalink / raw)
  To: GUO Ren (XuanTie); +Cc: kvm

Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] trace: incorrect TRACE_INCLUDE_PATH depth causes brittle include resolution
--

commit 2603329e3e16137c739dbffd2974c6bd447b6ee2
Author: GUO Ren (XuanTie) <guoren@kernel.org>

RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait

This commit adds tracepoints for paravirt qspinlock operations pv_kick and
pv_wait. These tracepoints allow observation of paravirt qspinlock behavior
via the paravirt trace event system.

> diff --git a/arch/riscv/kernel/trace_events_filter_paravirt.h b/arch/riscv/kernel/trace_events_filter_paravirt.h
> new file mode 100644
> index 0000000000000..8d57efda2c177
> --- /dev/null
> +++ b/arch/riscv/kernel/trace_events_filter_paravirt.h

[ ... ]

> +#endif /* _TRACE_PARAVIRT_H || TRACE_HEADER_MULTI_READ */
> +
> +#undef TRACE_INCLUDE_PATH
> +#undef TRACE_INCLUDE_FILE
> +#define TRACE_INCLUDE_PATH ../../../arch/riscv/kernel/

[Severity: Low]
Is this TRACE_INCLUDE_PATH definition too deep?

The three levels of parent directories (../../../) navigate outside the
kernel source tree relative to include/trace/define_trace.h. This currently
builds because the compiler falls back to searching the
-I$(srctree)/arch/riscv/include path, where the three directory levels happen
to perfectly cancel out the depth of the fallback path.

Could the include path be corrected to avoid compilation failures if the
include paths change or if built with compilers that evaluate fallbacks
differently?

> +#define TRACE_INCLUDE_FILE trace_events_filter_paravirt
> +
> +/* This part must be outside protection */
> +#include <trace/define_trace.h>

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260921-pvqspinlock-v4-0-409a22aed6ef@kernel.org?part=3

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v4 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS
  2026-09-21 12:27 ` [PATCH RFC v4 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS GUO Ren (XuanTie)
@ 2026-09-21 12:41   ` sashiko-bot
  0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-09-21 12:41 UTC (permalink / raw)
  To: GUO Ren (XuanTie); +Cc: kvm

Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] build: unresolved virt_spin_lock_key when PARAVIRT_SPINLOCKS is disabled
- [High] locking/pv: inverted nopvspin semantics disables TAS fallback on unaccelerated VMs
- [High] locking/pv: skipping ZICCRSE extension check exposes guest to LR/SC livelock
- [Low] locking/pv: casting atomic_t to raw pointer in smp_cond_load_relaxed
- [Low] locking/pv: static_branch_likely pessimizes native spinlock fastpath
--

commit 51ef25d6df1335ba98379605c62c0034ca0b9dfe
Author: GUO Ren (XuanTie) <guoren@kernel.org>

RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS

VM guests should fall back to a Test-and-Set spinlock when
PARAVIRT_SPINLOCKS is disabled, because fair locks suffer from severe
lock-holder preemption issues. The virt_spin_lock_key shortcuts
queued_spin_lock_slowpath(), allowing virt_spin_lock() to hijack it.

> diff --git a/arch/riscv/include/asm/qspinlock.h b/arch/riscv/include/asm/qspinlock.h
> index 330b714edc447..9c7108baa40a1 100644
> --- a/arch/riscv/include/asm/qspinlock.h
> +++ b/arch/riscv/include/asm/qspinlock.h
[ ... ]
> @@ -29,5 +31,27 @@ static inline void queued_spin_unlock(struct qspinlock *lock)
>  #endif /* CONFIG_PARAVIRT_SPINLOCKS */
>  
>  #include <asm-generic/qspinlock.h>
> +#include <asm/jump_label.h>
> +
> +/*
> + * KVM guests fall back to a Test-and-Set spinlock because fair locks suffer
> + * from severe lock-holder-preemption issues. When virt_spin_lock_key is
> + * enabled, virt_spin_lock() shortcuts queued_spin_lock_slowpath() and hijacks
> + * the lock acquisition.
> + */
> +DECLARE_STATIC_KEY_FALSE(virt_spin_lock_key);

[Severity: High]
Is it possible for the kernel to fail to link due to an undefined symbol here?

virt_spin_lock_key is unconditionally declared and used by the inline function
rv_virt_spin_lock(). However, its definition resides in
arch/riscv/kernel/qspinlock_paravirt.c, which is only compiled when
CONFIG_PARAVIRT_SPINLOCKS is enabled. Does this break the build when
CONFIG_QUEUED_SPINLOCKS=y but CONFIG_PARAVIRT_SPINLOCKS=n?

> +
> +#define virt_spin_lock rv_virt_spin_lock
> +static inline bool rv_virt_spin_lock(struct qspinlock *lock)
> +{
> +	if (!static_branch_likely(&virt_spin_lock_key))
> +		return false;

[Severity: Low]
Does using likely() here force the compiler to treat the bare-metal default
path (when the key is disabled) as out-of-line?

Since virt_spin_lock_key is false by default on bare-metal systems, wouldn't
static_branch_likely() require an unconditional jump in the native queued
spinlock fastpath, degrading performance? Should this be
static_branch_unlikely() instead?

> +
> +	do {
> +		smp_cond_load_relaxed((s32 *)&lock->val, VAL == 0);

[Severity: Low]
Is it safe to cast &lock->val (an atomic_t) to a raw pointer like (s32 *)?

This bypasses the atomic_t abstraction. Should atomic_cond_read_relaxed()
be used here instead?

> +	} while (atomic_cmpxchg(&lock->val, 0, _Q_LOCKED_VAL) != 0);
> +
> +	return true;
> +}
>  
>  #endif /* _ASM_RISCV_QSPINLOCK_H */
> diff --git a/arch/riscv/kernel/qspinlock_paravirt.c b/arch/riscv/kernel/qspinlock_paravirt.c
> index 04b13994e971c..28c6c78d7e84c 100644
> --- a/arch/riscv/kernel/qspinlock_paravirt.c
> +++ b/arch/riscv/kernel/qspinlock_paravirt.c
[ ... ]
> @@ -58,6 +60,12 @@ bool __init pv_qspinlock_init(void)
>  	if (!sbi_probe_extension(SBI_EXT_PVLOCK))
>  		return false;
>  
> +	if (nopvspin) {
> +		static_branch_enable(&virt_spin_lock_key);
> +		pr_info("virt_spin_lock enabled by nopvspin\n");
> +		return true;
> +	}

[Severity: High]
Do the nopvspin semantics here invert the expected behavior?

If an unaccelerated VM boots without SBI_EXT_PVLOCK, pv_qspinlock_init()
returns early before enabling virt_spin_lock_key, defeating the TAS fallback.

Furthermore, if nopvspin is passed, it statically enables the key, whereas on
x86, nopvspin explicitly disables PV optimizations and forces native queued
spinlocks.

[Severity: High]
Can this early return expose guests to LR/SC livelocks?

If a VM uses nopvspin, returning true here causes riscv_spinlock_init() in
arch/riscv/kernel/setup.c to completely bypass the hardware extension checks
like ZABHA, ZACAS, or ZICCRSE.

Because rv_virt_spin_lock() relies on an LR/SC atomic_cmpxchg loop, will it
livelock under heavy contention if the underlying hardware lacks the ZICCRSE
extension, which provides forward progress guarantees?

> +
>  	pr_info("PV qspinlocks enabled\n");
>  	__pv_init_lock_hash();

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260921-pvqspinlock-v4-0-409a22aed6ef@kernel.org?part=4

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH RFC v4 2/4] RISC-V: paravirt: Add pvqspinlock frontend
  2026-09-21 12:27 ` [PATCH RFC v4 2/4] RISC-V: paravirt: Add pvqspinlock frontend GUO Ren (XuanTie)
@ 2026-09-21 12:41   ` sashiko-bot
  0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-09-21 12:41 UTC (permalink / raw)
  To: GUO Ren (XuanTie); +Cc: kvm

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] riscv: out-of-line static_call in queued_spin_unlock() degrades performance
- [High] riscv: missing headers in qspinlock_paravirt cause build failures
--

commit c07167cc8d5368121bd2aa429e157f2496f5c63f
Author: GUO Ren (XuanTie) <guoren@kernel.org>

RISC-V: paravirt: Add pvqspinlock frontend

Add a virtualization-friendly unfair qspinlock frontend that halts the
virtual CPU instead of spinning.

> diff --git a/arch/riscv/include/asm/qspinlock.h b/arch/riscv/include/asm/qspinlock.h
> new file mode 100644
> index 0000000000000..330b714edc447
> --- /dev/null
> +++ b/arch/riscv/include/asm/qspinlock.h

[ ... ]

> +#define queued_spin_unlock	queued_spin_unlock
> +static inline void queued_spin_unlock(struct qspinlock *lock)
> +{
> +	static_call(pv_queued_spin_unlock)(lock);
> +}

[Severity: High]
Does replacing the inline smp_store_release() with a static_call() regress
native bare-metal performance?

Because RISC-V does not yet support inline static calls, this change replaces
the fast path native smp_store_release() instruction with an out-of-line
function call or indirect branch across the kernel for every spin_unlock
operation when CONFIG_PARAVIRT_SPINLOCKS is enabled.

> diff --git a/arch/riscv/include/asm/qspinlock_paravirt.h b/arch/riscv/include/asm/qspinlock_paravirt.h
> new file mode 100644
> index 0000000000000..7261cd9b13b2e
> --- /dev/null
> +++ b/arch/riscv/include/asm/qspinlock_paravirt.h

[ ... ]

> +void dummy_queued_spin_lock_slowpath(struct qspinlock *lock, u32 val);
> +void dummy_queued_spin_unlock(struct qspinlock *lock);
> +
> +DECLARE_STATIC_CALL(pv_queued_spin_lock_slowpath, dummy_queued_spin_lock_slowpath);

[Severity: High]
Can this cause a build failure due to an undefined macro?

DECLARE_STATIC_CALL requires <linux/static_call_types.h>, which does not
appear to be included in this file.

> +DECLARE_STATIC_CALL(pv_queued_spin_unlock, dummy_queued_spin_unlock);

[ ... ]

> diff --git a/arch/riscv/kernel/qspinlock_paravirt.c b/arch/riscv/kernel/qspinlock_paravirt.c
> new file mode 100644
> index 0000000000000..c534447437fec
> --- /dev/null
> +++ b/arch/riscv/kernel/qspinlock_paravirt.c
> @@ -0,0 +1,67 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * Copyright (C) 2026 GUO Ren (XuanTie) <guoren@kernel.org>
> + */
> +
> +#include <linux/static_call.h>
> +#include <asm/qspinlock_paravirt.h>
> +#include <asm/sbi.h>
> +
> +void pv_kick(int cpu)
> +{
> +	sbi_ecall(SBI_EXT_PVLOCK, SBI_EXT_PVLOCK_KICK_CPU,
> +		  cpuid_to_hartid_map(cpu), 0, 0, 0, 0, 0);

[Severity: High]
Will this cause an implicit declaration error when compiling?

The cpuid_to_hartid_map() function requires <asm/smp.h>, which is missing
from the includes in this file.

> +}

[ ... ]

> +static void native_queued_spin_unlock(struct qspinlock *lock)
> +{
> +	/*
> +	 * unlock() needs release semantics:
> +	 */
> +	smp_store_release(&lock->locked, 0);
> +}

[Severity: High]
By forcing this into an out-of-line static function, does this prevent the
compiler from inlining the native fast path entirely?

> +
> +DEFINE_STATIC_CALL(pv_queued_spin_lock_slowpath, native_queued_spin_lock_slowpath);

[Severity: High]
Will this result in an undeclared identifier error for
native_queued_spin_lock_slowpath?

The native_queued_spin_lock_slowpath symbol requires <asm/qspinlock.h>,
which is missing from the includes in this file.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260921-pvqspinlock-v4-0-409a22aed6ef@kernel.org?part=2

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2026-09-21 12:41 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-21 12:27 [PATCH RFC v4 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support GUO Ren (XuanTie)
2026-09-21 12:27 ` [PATCH RFC v4 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend GUO Ren (XuanTie)
2026-09-21 12:35   ` sashiko-bot
2026-09-21 12:27 ` [PATCH RFC v4 2/4] RISC-V: paravirt: Add pvqspinlock frontend GUO Ren (XuanTie)
2026-09-21 12:41   ` sashiko-bot
2026-09-21 12:27 ` [PATCH RFC v4 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait GUO Ren (XuanTie)
2026-09-21 12:39   ` sashiko-bot
2026-09-21 12:27 ` [PATCH RFC v4 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS GUO Ren (XuanTie)
2026-09-21 12:41   ` sashiko-bot

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