* [RFC PATCH V3 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support
@ 2025-12-01 0:30 guoren
2025-12-01 0:30 ` [RFC PATCH V3 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend guoren
` (3 more replies)
0 siblings, 4 replies; 5+ messages in thread
From: guoren @ 2025-12-01 0:30 UTC (permalink / raw)
To: paul.walmsley, palmer, guoren, leobras, ajones, anup, atish.patra,
corbet
Cc: linux-riscv, linux-kernel, kvm-riscv, kvm, linux-doc
From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org>
Paravirtualized spinlocks allow a unfair qspinlock to replace the
ticket-lock or native fair qspinlock implementation with something
virtualization-friendly, for example, halt the virtual CPU rather
than spinning.
You could observe the paravirt qspinlock internal work situation with
/sys/kernel/debug/tracing/trace:
ls /sys/kernel/debug/tracing/events/paravirt/
enable filter pv_kick pv_wait
echo 1 > /sys/kernel/debug/tracing/events/paravirt/enable
cat /sys/kernel/debug/tracing/trace
entries-in-buffer/entries-written: 33927/33927 #P:12
_-----=> irqs-off/BH-disabled
/ _----=> need-resched
| / _---=> hardirq/softirq
|| / _--=> preempt-depth
||| / _-=> migrate-disable
|||| / delay
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
sh-100 [001] d..2. 30.982631: pv_wait: cpu 1 out of wfi
<idle>-0 [000] d.h4. 30.993289: pv_kick: cpu 0 kick target cpu 1
sh-100 [002] d..2. 44.987573: pv_wait: cpu 2 out of wfi
<idle>-0 [000] d.h4. 44.989000: pv_kick: cpu 0 kick target cpu 2
<idle>-0 [003] d.s3. 51.593978: pv_kick: cpu 3 kick target cpu 4
rcu_sched-15 [004] d..2. 51.595192: pv_wait: cpu 4 out of wfi
lock_torture_wr-115 [004] ...2. 52.656482: pv_kick: cpu 4 kick target cpu 2
lock_torture_wr-113 [002] d..2. 52.659146: pv_wait: cpu 2 out of wfi
lock_torture_wr-114 [008] d..2. 52.659507: pv_wait: cpu 8 out of wfi
lock_torture_wr-114 [008] d..2. 52.663503: pv_wait: cpu 8 out of wfi
lock_torture_wr-113 [002] ...2. 52.666128: pv_kick: cpu 2 kick target cpu 8
lock_torture_wr-114 [008] d..2. 52.667261: pv_wait: cpu 8 out of wfi
lock_torture_wr-114 [009] .n.2. 53.141515: pv_kick: cpu 9 kick target cpu 11
lock_torture_wr-113 [002] d..2. 53.143339: pv_wait: cpu 2 out of wfi
lock_torture_wr-116 [007] d..2. 53.143412: pv_wait: cpu 7 out of wfi
lock_torture_wr-118 [000] d..2. 53.143457: pv_wait: cpu 0 out of wfi
lock_torture_wr-115 [008] d..2. 53.143481: pv_wait: cpu 8 out of wfi
lock_torture_wr-117 [011] d..2. 53.143522: pv_wait: cpu 11 out of wfi
lock_torture_wr-117 [011] ...2. 53.143987: pv_kick: cpu 11 kick target cpu 8
lock_torture_wr-115 [008] ...2. 53.144269: pv_kick: cpu 8 kick target cpu 7
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:
v3:
- 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 (Alibaba DAMO Academy) (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
.../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 | 59 +++++++++++++
arch/riscv/include/asm/qspinlock_paravirt.h | 28 +++++++
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 | 84 +++++++++++++++++++
arch/riscv/kernel/setup.c | 5 ++
.../kernel/trace_events_filter_paravirt.h | 60 +++++++++++++
arch/riscv/kvm/Makefile | 1 +
arch/riscv/kvm/vcpu_sbi.c | 4 +
arch/riscv/kvm/vcpu_sbi_pvlock.c | 57 +++++++++++++
15 files changed, 320 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.40.1
^ permalink raw reply [flat|nested] 5+ messages in thread
* [RFC PATCH V3 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend
2025-12-01 0:30 [RFC PATCH V3 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support guoren
@ 2025-12-01 0:30 ` guoren
2025-12-01 0:30 ` [RFC PATCH V3 2/4] RISC-V: paravirt: Add pvqspinlock frontend guoren
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: guoren @ 2025-12-01 0:30 UTC (permalink / raw)
To: paul.walmsley, palmer, guoren, leobras, ajones, anup, atish.patra,
corbet
Cc: linux-riscv, linux-kernel, kvm-riscv, kvm, linux-doc
From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org>
Add the files functions needed to support the SBI PVLOCK (paravirt
qspinlock kick_cpu) extension. Implement kvm_sbi_ext_pvlock_kick_-
cpu(), and we only need to call the kvm_vcpu_kick() and bring
target_vcpu from the halt state.
Reviewed-by: Leonardo Bras <leobras@redhat.com>
Signed-off-by: Guo Ren (Alibaba DAMO Academy) <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 | 57 +++++++++++++++++++++++++++
6 files changed, 69 insertions(+)
create mode 100644 arch/riscv/kvm/vcpu_sbi_pvlock.c
diff --git a/arch/riscv/include/asm/kvm_vcpu_sbi.h b/arch/riscv/include/asm/kvm_vcpu_sbi.h
index 3497489e04db..d0df83ecd9fd 100644
--- a/arch/riscv/include/asm/kvm_vcpu_sbi.h
+++ b/arch/riscv/include/asm/kvm_vcpu_sbi.h
@@ -107,6 +107,7 @@ extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_sta;
extern const struct kvm_vcpu_sbi_extension vcpu_sbi_ext_fwft;
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 ccc77a89b1e2..dd0734e1ebb6 100644
--- a/arch/riscv/include/asm/sbi.h
+++ b/arch/riscv/include/asm/sbi.h
@@ -37,6 +37,7 @@ enum sbi_ext_id {
SBI_EXT_NACL = 0x4E41434C,
SBI_EXT_FWFT = 0x46574654,
SBI_EXT_MPXY = 0x4D505859,
+ SBI_EXT_PVLOCK = 0x50564C4B,
/* Experimentals extensions must lie within this range */
SBI_EXT_EXPERIMENTAL_START = 0x08000000,
@@ -505,6 +506,10 @@ enum sbi_mpxy_rpmi_attribute_id {
#define SBI_MPXY_CHAN_CAP_SEND_WITHOUT_RESP BIT(4)
#define SBI_MPXY_CHAN_CAP_GET_NOTIFICATIONS BIT(5)
+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 759a4852c09a..9d447995de84 100644
--- a/arch/riscv/include/uapi/asm/kvm.h
+++ b/arch/riscv/include/uapi/asm/kvm.h
@@ -211,6 +211,7 @@ enum KVM_RISCV_SBI_EXT_ID {
KVM_RISCV_SBI_EXT_STA,
KVM_RISCV_SBI_EXT_SUSP,
KVM_RISCV_SBI_EXT_FWFT,
+ KVM_RISCV_SBI_EXT_PVLOCK,
KVM_RISCV_SBI_EXT_MAX,
};
diff --git a/arch/riscv/kvm/Makefile b/arch/riscv/kvm/Makefile
index 07197395750e..40ddb7c06ffe 100644
--- a/arch/riscv/kvm/Makefile
+++ b/arch/riscv/kvm/Makefile
@@ -35,6 +35,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 1b13623380e1..dd74f789f44c 100644
--- a/arch/riscv/kvm/vcpu_sbi.c
+++ b/arch/riscv/kvm/vcpu_sbi.c
@@ -90,6 +90,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..aeb48c3fca50
--- /dev/null
+++ b/arch/riscv/kvm/vcpu_sbi_pvlock.c
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c), 2025 Alibaba Damo Academy
+ *
+ * Authors:
+ * Guo Ren <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.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH V3 2/4] RISC-V: paravirt: Add pvqspinlock frontend
2025-12-01 0:30 [RFC PATCH V3 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support guoren
2025-12-01 0:30 ` [RFC PATCH V3 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend guoren
@ 2025-12-01 0:30 ` guoren
2025-12-01 0:30 ` [RFC PATCH V3 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait guoren
2025-12-01 0:30 ` [RFC PATCH V3 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS guoren
3 siblings, 0 replies; 5+ messages in thread
From: guoren @ 2025-12-01 0:30 UTC (permalink / raw)
To: paul.walmsley, palmer, guoren, leobras, ajones, anup, atish.patra,
corbet
Cc: linux-riscv, linux-kernel, kvm-riscv, kvm, linux-doc
From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org>
Add an unfair qspinlock virtualization-friendly frontend, by halting the
virtual CPU rather than spinning.
Using 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 & pv_kick implementations.
Reviewed-by: Leonardo Bras <leobras@redhat.com>
Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
---
arch/riscv/Kconfig | 12 ++++
arch/riscv/include/asm/Kbuild | 1 -
arch/riscv/include/asm/qspinlock.h | 35 +++++++++++
arch/riscv/include/asm/qspinlock_paravirt.h | 28 +++++++++
arch/riscv/kernel/Makefile | 2 +
arch/riscv/kernel/qspinlock_paravirt.c | 69 +++++++++++++++++++++
arch/riscv/kernel/setup.c | 5 ++
7 files changed, 151 insertions(+), 1 deletion(-)
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
diff --git a/arch/riscv/Kconfig b/arch/riscv/Kconfig
index fadec20b87a8..7d29370e6318 100644
--- a/arch/riscv/Kconfig
+++ b/arch/riscv/Kconfig
@@ -1111,6 +1111,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"
depends on !XIP_KERNEL
diff --git a/arch/riscv/include/asm/Kbuild b/arch/riscv/include/asm/Kbuild
index bd5fc9403295..1258bd239b49 100644
--- a/arch/riscv/include/asm/Kbuild
+++ b/arch/riscv/include/asm/Kbuild
@@ -13,6 +13,5 @@ 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 += 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..b39f23415ec1
--- /dev/null
+++ b/arch/riscv/include/asm/qspinlock.h
@@ -0,0 +1,35 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c), 2025 Alibaba Damo Academy
+ * Authors:
+ * Guo Ren <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..ded8c5a399bb
--- /dev/null
+++ b/arch/riscv/include/asm/qspinlock_paravirt.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c), 2025 Alibaba Damo Academy
+ * Authors:
+ * Guo Ren <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 f60fce69b725..6ea874bcd447 100644
--- a/arch/riscv/kernel/Makefile
+++ b/arch/riscv/kernel/Makefile
@@ -125,3 +125,5 @@ obj-$(CONFIG_ACPI) += acpi.o
obj-$(CONFIG_ACPI_NUMA) += acpi_numa.o
obj-$(CONFIG_GENERIC_CPU_VULNERABILITIES) += bugs.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..299dddaa14b8
--- /dev/null
+++ b/arch/riscv/kernel/qspinlock_paravirt.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c), 2025 Alibaba Damo Academy
+ * Authors:
+ * Guo Ren <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);
+ return;
+}
+
+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)
+{
+ 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)
+{
+ if (static_call_query(pv_queued_spin_unlock) == native_queued_spin_unlock)
+ return true;
+ else
+ return false;
+}
diff --git a/arch/riscv/kernel/setup.c b/arch/riscv/kernel/setup.c
index b5bc5fc65cea..0df27501e28d 100644
--- a/arch/riscv/kernel/setup.c
+++ b/arch/riscv/kernel/setup.c
@@ -288,6 +288,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.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH V3 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait
2025-12-01 0:30 [RFC PATCH V3 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support guoren
2025-12-01 0:30 ` [RFC PATCH V3 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend guoren
2025-12-01 0:30 ` [RFC PATCH V3 2/4] RISC-V: paravirt: Add pvqspinlock frontend guoren
@ 2025-12-01 0:30 ` guoren
2025-12-01 0:30 ` [RFC PATCH V3 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS guoren
3 siblings, 0 replies; 5+ messages in thread
From: guoren @ 2025-12-01 0:30 UTC (permalink / raw)
To: paul.walmsley, palmer, guoren, leobras, ajones, anup, atish.patra,
corbet
Cc: linux-riscv, linux-kernel, kvm-riscv, kvm, linux-doc
From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org>
Add trace point for pv_kick&wait, here is the output:
ls /sys/kernel/debug/tracing/events/paravirt/
enable filter pv_kick pv_wait
cat /sys/kernel/debug/tracing/trace
entries-in-buffer/entries-written: 33927/33927 #P:12
_-----=> irqs-off/BH-disabled
/ _----=> need-resched
| / _---=> hardirq/softirq
|| / _--=> preempt-depth
||| / _-=> migrate-disable
|||| / delay
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
sh-100 [001] d..2. 30.982631: pv_wait: cpu 1 out of wfi
<idle>-0 [000] d.h4. 30.993289: pv_kick: cpu 0 kick target cpu 1
sh-100 [002] d..2. 44.987573: pv_wait: cpu 2 out of wfi
<idle>-0 [000] d.h4. 44.989000: pv_kick: cpu 0 kick target cpu 2
<idle>-0 [003] d.s3. 51.593978: pv_kick: cpu 3 kick target cpu 4
rcu_sched-15 [004] d..2. 51.595192: pv_wait: cpu 4 out of wfi
lock_torture_wr-115 [004] ...2. 52.656482: pv_kick: cpu 4 kick target cpu 2
lock_torture_wr-113 [002] d..2. 52.659146: pv_wait: cpu 2 out of wfi
lock_torture_wr-114 [008] d..2. 52.659507: pv_wait: cpu 8 out of wfi
lock_torture_wr-114 [008] d..2. 52.663503: pv_wait: cpu 8 out of wfi
lock_torture_wr-113 [002] ...2. 52.666128: pv_kick: cpu 2 kick target cpu 8
lock_torture_wr-114 [008] d..2. 52.667261: pv_wait: cpu 8 out of wfi
lock_torture_wr-114 [009] .n.2. 53.141515: pv_kick: cpu 9 kick target cpu 11
lock_torture_wr-113 [002] d..2. 53.143339: pv_wait: cpu 2 out of wfi
lock_torture_wr-116 [007] d..2. 53.143412: pv_wait: cpu 7 out of wfi
lock_torture_wr-118 [000] d..2. 53.143457: pv_wait: cpu 0 out of wfi
lock_torture_wr-115 [008] d..2. 53.143481: pv_wait: cpu 8 out of wfi
lock_torture_wr-117 [011] d..2. 53.143522: pv_wait: cpu 11 out of wfi
lock_torture_wr-117 [011] ...2. 53.143987: pv_kick: cpu 11 kick target cpu 8
lock_torture_wr-115 [008] ...2. 53.144269: pv_kick: cpu 8 kick target cpu 7
Reviewed-by: Leonardo Bras <leobras@redhat.com>
Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
---
arch/riscv/kernel/qspinlock_paravirt.c | 7 +++
.../kernel/trace_events_filter_paravirt.h | 60 +++++++++++++++++++
2 files changed, 67 insertions(+)
create mode 100644 arch/riscv/kernel/trace_events_filter_paravirt.h
diff --git a/arch/riscv/kernel/qspinlock_paravirt.c b/arch/riscv/kernel/qspinlock_paravirt.c
index 299dddaa14b8..cae991139abe 100644
--- a/arch/riscv/kernel/qspinlock_paravirt.c
+++ b/arch/riscv/kernel/qspinlock_paravirt.c
@@ -9,8 +9,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);
return;
@@ -28,6 +33,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..db5e702a1f12
--- /dev/null
+++ b/arch/riscv/kernel/trace_events_filter_paravirt.h
@@ -0,0 +1,60 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c), 2025 Alibaba Damo Academy
+ * Authors:
+ * Guo Ren <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.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [RFC PATCH V3 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS
2025-12-01 0:30 [RFC PATCH V3 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support guoren
` (2 preceding siblings ...)
2025-12-01 0:30 ` [RFC PATCH V3 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait guoren
@ 2025-12-01 0:30 ` guoren
3 siblings, 0 replies; 5+ messages in thread
From: guoren @ 2025-12-01 0:30 UTC (permalink / raw)
To: paul.walmsley, palmer, guoren, leobras, ajones, anup, atish.patra,
corbet
Cc: linux-riscv, linux-kernel, kvm-riscv, kvm, linux-doc
From: "Guo Ren (Alibaba DAMO Academy)" <guoren@kernel.org>
The VM guests should fall back to a Test-and-Set spinlock when
PARAVIRT_SPINLOCKS disabled, because fair locks have horrible lock
'holder' preemption issues. The virt_spin_lock_key would shortcut for
the queued_spin_lock_- slowpath() function that allow virt_spin_lock
to hijack it. ref: 43b3f02899f7 ("locking/qspinlock/x86: Fix
performance regression under unaccelerated VMs").
Add a static key controlling whether virt_spin_lock() should be
called or not. Add nopvspin support as x86.
Signed-off-by: Guo Ren (Alibaba DAMO Academy) <guoren@kernel.org>
---
.../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 6c42061ca20e..9e895e9ca655 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -4393,7 +4393,7 @@
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 b39f23415ec1..70ad7679fce0 100644
--- a/arch/riscv/include/asm/qspinlock.h
+++ b/arch/riscv/include/asm/qspinlock.h
@@ -14,6 +14,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);
@@ -31,5 +33,27 @@ static inline void queued_spin_unlock(struct qspinlock *lock)
#endif /* CONFIG_PARAVIRT_SPINLOCKS */
#include <asm-generic/qspinlock.h>
+#include <asm/jump_label.h>
+
+/*
+ * The KVM guests fall back to a Test-and-Set spinlock, because fair locks
+ * have horrible lock 'holder' preemption issues. The test_and_set_spinlock_key
+ * would shortcut for the queued_spin_lock_slowpath() function that allow
+ * virt_spin_lock to hijack it.
+ */
+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 cae991139abe..b89f13d0d6e8 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.40.1
^ permalink raw reply related [flat|nested] 5+ messages in thread
end of thread, other threads:[~2025-12-01 0:31 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-01 0:30 [RFC PATCH V3 0/4] RISC-V: Add PARAVIRT_SPINLOCKS support guoren
2025-12-01 0:30 ` [RFC PATCH V3 1/4] RISC-V: paravirt: Add pvqspinlock KVM backend guoren
2025-12-01 0:30 ` [RFC PATCH V3 2/4] RISC-V: paravirt: Add pvqspinlock frontend guoren
2025-12-01 0:30 ` [RFC PATCH V3 3/4] RISC-V: paravirt: pvqspinlock: Add trace point for pv_kick/wait guoren
2025-12-01 0:30 ` [RFC PATCH V3 4/4] RISC-V: paravirt: Support nopvspin to disable PARAVIRT_SPINLOCKS guoren
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).