* [PATCH v3 0/6] printk: nbcon: deprecate boot_delay in favour of printk_delay
From: Andrew Murray @ 2026-07-12 10:20 UTC (permalink / raw)
To: Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
Jonathan Corbet, Shuah Khan, Russell King, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Andrew Morton, Greg Kroah-Hartman, Sebastian Andrzej Siewior,
Clark Williams
Cc: linux-kernel, linux-doc, linux-arm-kernel, linux-rpi-kernel,
linux-rt-devel, Andrew Murray
The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay
sysctl are two distinct mechanisms for providing similar functionality
which add a delay prior to each printed printk message.
boot_delay provides a kernel parameter for delaying printk output from
kernel start through to boot (SYSTEM_RUNNING), whereas printk_delay is
configurable only via sysctl and thus is only used post boot.
However, since the introduction of nbcon and the legacy printer thread
for PREEMPT_RT kernels, printk records are now emited to the console
asynchronously to the caller of printk. Thus, any printk delay added by
boot_delay/printk_delay continues to slow down the calling process but
may not have any impact to the rate in which records are emited to the
console, especially for slow consoles.
To address these issues, let's deprecate boot_delay, extend printk_delay
to be useable from kernel start and ensure that delays occur at the point
where console messages are printed rather than queued.
Please note that this patchset results in delays occuring after a message
is printed rather than, as it is now, before.
Signed-off-by: Andrew Murray <amurray@thegoodpenguin.co.uk>
---
Please see the following related work for additional context:
- https://lore.kernel.org/all/20260503214214.3475670-1-rdunlap@infradead.org/
- https://lore.kernel.org/all/20260505-printk_delay-v1-1-5dba51d7f17c@thegoodpenguin.co.uk/
---
Changes in v1:
- Rebased onto v7.2-rc2
- Moved emitted field from nbcon_write_context to nbcon_context
- Fixed comparison of char field that used > operator
- Used unsigned int and bounds checking for printk/boot delay
- Moved delays prior to allowing handover
- Added additional information into commit messages
- Link to v2: https://lore.kernel.org/lkml/20260630-deprecate_boot_delay-v2-0-f9883d36aa4b@thegoodpenguin.co.uk
Changes in v2:
- Rebased onto v7.2-rc1
- Correctly handle negative values for printk_delay_msec (patch 2)
- Add missing newline in pr_warn (patch 2)
- Improved patch descriptions for (patches 2 and 3)
- Use new emitted flag in nbcon_context/nbcon_write_context in place of backlog && wctxt.len checks (patch 3)
- Use unsigned char for unsafe_takeover field instead of bool in nbcon_write_context (patch 3)
- Move printk_delay_msec and printk_delay from printk.h to internal.h (patch 3)
- Revert regression added in v1 to __nbcon_atomic_flush_pending_con (patch 3)
- Move printk_delay later in console_emit_next_record ensuring delay is always after emit (across nbcon/legacy) (patch 3)
- Fixed typo in documentation s/boot_delay/printk_delay/g in printk_delay= section (patch 4)
- Link to v1: https://lore.kernel.org/r/20260601-deprecate_boot_delay-v1-0-c34c187142a6@thegoodpenguin.co.uk
---
Andrew Murray (6):
printk: sysctl: use unsigned int for printk_delay
printk: add bounds checking to boot_delay
printk: remove BOOT_PRINTK_DELAY config option
printk: deprecate boot_delay in favour of printk_delay
printk: nbcon: move printk_delay to console emiting code
Documentation/kernel-parameters: add/update printk_delay/boot_delay
Documentation/admin-guide/kernel-parameters.txt | 31 +++++++--
arch/arm/configs/bcm2835_defconfig | 1 -
include/linux/console.h | 5 +-
include/linux/printk.h | 1 -
kernel/printk/internal.h | 6 ++
kernel/printk/nbcon.c | 13 ++++
kernel/printk/printk.c | 89 ++++++++++++++++---------
kernel/printk/sysctl.c | 4 +-
lib/Kconfig.debug | 18 -----
9 files changed, 108 insertions(+), 60 deletions(-)
---
base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
change-id: 20260711-printkcleanup-cbe3fda4a2bc
Best regards,
--
Andrew Murray <amurray@thegoodpenguin.co.uk>
^ permalink raw reply
* [PATCH v3 1/6] printk: sysctl: use unsigned int for printk_delay
From: Andrew Murray @ 2026-07-12 10:20 UTC (permalink / raw)
To: Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
Jonathan Corbet, Shuah Khan, Russell King, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Andrew Morton, Greg Kroah-Hartman, Sebastian Andrzej Siewior,
Clark Williams
Cc: linux-kernel, linux-doc, linux-arm-kernel, linux-rpi-kernel,
linux-rt-devel, Andrew Murray
In-Reply-To: <20260712-printkcleanup-v3-0-574547b8f71b@thegoodpenguin.co.uk>
As the printk_delay sysctl represents a duration in milliseconds,
let's set its type to be unsigned int.
Signed-off-by: Andrew Murray <amurray@thegoodpenguin.co.uk>
---
include/linux/printk.h | 2 +-
kernel/printk/printk.c | 4 ++--
kernel/printk/sysctl.c | 4 ++--
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/include/linux/printk.h b/include/linux/printk.h
index f594c1266bfd411f2238b45374e8a71222f0407c..ea52dc72b73b64898f82a0319b01c27323b18dee 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -188,7 +188,7 @@ extern int __printk_ratelimit(const char *func);
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
unsigned int interval_msec);
-extern int printk_delay_msec;
+extern unsigned int printk_delay_msec;
extern int dmesg_restrict;
extern void wake_up_klogd(void);
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 2fe9a963c823a41e7df10c29939a2abb55462859..31aabdf8248cc39c54ee11685d4a37deac1c174c 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2117,14 +2117,14 @@ static u8 *__printk_recursion_counter(void)
local_irq_restore(flags); \
} while (0)
-int printk_delay_msec __read_mostly;
+unsigned int printk_delay_msec __read_mostly;
static inline void printk_delay(int level)
{
boot_delay_msec(level);
if (unlikely(printk_delay_msec)) {
- int m = printk_delay_msec;
+ unsigned int m = printk_delay_msec;
while (m--) {
mdelay(1);
diff --git a/kernel/printk/sysctl.c b/kernel/printk/sysctl.c
index f15732e93c2e9c0865c42e4af9cb6458d4402c0a..56c3db63b3f8c6c5fddc4e4de1f41c6102f0f4b1 100644
--- a/kernel/printk/sysctl.c
+++ b/kernel/printk/sysctl.c
@@ -44,9 +44,9 @@ static const struct ctl_table printk_sysctls[] = {
{
.procname = "printk_delay",
.data = &printk_delay_msec,
- .maxlen = sizeof(int),
+ .maxlen = sizeof(unsigned int),
.mode = 0644,
- .proc_handler = proc_dointvec_minmax,
+ .proc_handler = proc_douintvec_minmax,
.extra1 = SYSCTL_ZERO,
.extra2 = (void *)&ten_thousand,
},
--
2.34.1
^ permalink raw reply related
* [PATCH v3 2/6] printk: add bounds checking to boot_delay
From: Andrew Murray @ 2026-07-12 10:20 UTC (permalink / raw)
To: Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
Jonathan Corbet, Shuah Khan, Russell King, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Andrew Morton, Greg Kroah-Hartman, Sebastian Andrzej Siewior,
Clark Williams
Cc: linux-kernel, linux-doc, linux-arm-kernel, linux-rpi-kernel,
linux-rt-devel, Andrew Murray
In-Reply-To: <20260712-printkcleanup-v3-0-574547b8f71b@thegoodpenguin.co.uk>
As the boot_delay kernel parameter represents a duration in
milliseconds, let's set its type to be unsigned int and add
bounds checking.
Please note that the existing pr_debug will only be displayed
when boot_delay is non-zero:
pr_debug("printk_delay: %u, preset_lpj: %ld, lpj: %lu, "
"HZ: %d, loops_per_msec: %llu\n",
printk_delay_msec, preset_lpj, lpj, HZ, loops_per_msec);
Signed-off-by: Andrew Murray <amurray@thegoodpenguin.co.uk>
---
kernel/printk/printk.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 31aabdf8248cc39c54ee11685d4a37deac1c174c..8be562c9be277670ba3209ed1f810fc87175848a 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1291,19 +1291,22 @@ static bool suppress_message_printing(int level)
#ifdef CONFIG_BOOT_PRINTK_DELAY
-static int boot_delay; /* msecs delay after each printk during bootup */
+static unsigned int boot_delay; /* msecs delay after each printk during bootup */
static unsigned long long loops_per_msec; /* based on boot_delay */
static int __init boot_delay_setup(char *str)
{
unsigned long lpj;
+ int boot_delay_val;
lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */
loops_per_msec = (unsigned long long)lpj / 1000 * HZ;
- get_option(&str, &boot_delay);
- if (boot_delay > 10 * 1000)
- boot_delay = 0;
+ get_option(&str, &boot_delay_val);
+ if (boot_delay_val < 0 || boot_delay_val > 10 * 1000)
+ return 0;
+
+ boot_delay = (unsigned int)boot_delay_val;
pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, "
"HZ: %d, loops_per_msec: %llu\n",
--
2.34.1
^ permalink raw reply related
* [PATCH v3 3/6] printk: remove BOOT_PRINTK_DELAY config option
From: Andrew Murray @ 2026-07-12 10:20 UTC (permalink / raw)
To: Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
Jonathan Corbet, Shuah Khan, Russell King, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Andrew Morton, Greg Kroah-Hartman, Sebastian Andrzej Siewior,
Clark Williams
Cc: linux-kernel, linux-doc, linux-arm-kernel, linux-rpi-kernel,
linux-rt-devel, Andrew Murray
In-Reply-To: <20260712-printkcleanup-v3-0-574547b8f71b@thegoodpenguin.co.uk>
The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl
are two distinct mechanisms for providing similar functionality which add a
delay prior to each printed printk message.
In preparation of combining them into a single configurable feature, let's
first remove the kconfig option BOOT_PRINTK_DELAY.
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Andrew Murray <amurray@thegoodpenguin.co.uk>
---
Documentation/admin-guide/kernel-parameters.txt | 2 +-
arch/arm/configs/bcm2835_defconfig | 1 -
kernel/printk/printk.c | 2 +-
lib/Kconfig.debug | 18 ------------------
4 files changed, 2 insertions(+), 21 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index b5493a7f8f22812833308b22f2cc35b0a42e55b2..2884103b93bca7b76cd3a93946276074cf62d0a1 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -651,7 +651,7 @@ Kernel parameters
boot_delay= [KNL,EARLY]
Milliseconds to delay each printk during boot.
- Only works if CONFIG_BOOT_PRINTK_DELAY is enabled,
+ Only works if GENERIC_CALIBRATE_DELAY is enabled,
and you may also have to specify "lpj=". Boot_delay
values larger than 10 seconds (10000) are assumed
erroneous and ignored.
diff --git a/arch/arm/configs/bcm2835_defconfig b/arch/arm/configs/bcm2835_defconfig
index 4a8ac09843d73280cc42dbbf63fe3cc9f31dacd2..51a1e94d5aa6c22202778082b877a202a6b9c04d 100644
--- a/arch/arm/configs/bcm2835_defconfig
+++ b/arch/arm/configs/bcm2835_defconfig
@@ -174,7 +174,6 @@ CONFIG_NLS_UTF8=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=32
CONFIG_PRINTK_TIME=y
-CONFIG_BOOT_PRINTK_DELAY=y
CONFIG_DYNAMIC_DEBUG=y
CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
# CONFIG_ENABLE_MUST_CHECK is not set
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 8be562c9be277670ba3209ed1f810fc87175848a..28e6dff2faa7d4294c1b2ebe2844ce5d4dc0e05a 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1289,7 +1289,7 @@ static bool suppress_message_printing(int level)
return (level >= console_loglevel && !ignore_loglevel);
}
-#ifdef CONFIG_BOOT_PRINTK_DELAY
+#ifdef CONFIG_GENERIC_CALIBRATE_DELAY
static unsigned int boot_delay; /* msecs delay after each printk during bootup */
static unsigned long long loops_per_msec; /* based on boot_delay */
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 1244dcac2294ad99fda37fa6767c9e76f16a4d14..b552ea51cd53b79cf5d58b8c4deff409b1982862 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -99,24 +99,6 @@ config MESSAGE_LOGLEVEL_DEFAULT
by default. To change that, use loglevel=<x> in the kernel bootargs,
or pick a different CONSOLE_LOGLEVEL_DEFAULT configuration value.
-config BOOT_PRINTK_DELAY
- bool "Delay each boot printk message by N milliseconds"
- depends on DEBUG_KERNEL && PRINTK && GENERIC_CALIBRATE_DELAY
- help
- This build option allows you to read kernel boot messages
- by inserting a short delay after each one. The delay is
- specified in milliseconds on the kernel command line,
- using "boot_delay=N".
-
- It is likely that you would also need to use "lpj=M" to preset
- the "loops per jiffy" value.
- See a previous boot log for the "lpj" value to use for your
- system, and then set "lpj=M" before setting "boot_delay=N".
- NOTE: Using this option may adversely affect SMP systems.
- I.e., processors other than the first one may not boot up.
- BOOT_PRINTK_DELAY also may cause LOCKUP_DETECTOR to detect
- what it believes to be lockup conditions.
-
config DYNAMIC_DEBUG
bool "Enable dynamic printk() support"
default n
--
2.34.1
^ permalink raw reply related
* [PATCH v3 4/6] printk: deprecate boot_delay in favour of printk_delay
From: Andrew Murray @ 2026-07-12 10:20 UTC (permalink / raw)
To: Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
Jonathan Corbet, Shuah Khan, Russell King, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Andrew Morton, Greg Kroah-Hartman, Sebastian Andrzej Siewior,
Clark Williams
Cc: linux-kernel, linux-doc, linux-arm-kernel, linux-rpi-kernel,
linux-rt-devel, Andrew Murray
In-Reply-To: <20260712-printkcleanup-v3-0-574547b8f71b@thegoodpenguin.co.uk>
The boot_delay (BOOT_PRINTK_DELAY) kernel parameter and printk_delay sysctl
are two distinct mechanisms for providing similar functionality which add a
delay prior to each printed printk message.
boot_delay provides a kernel parameter for delaying printk output from
kernel start through to boot (SYSTEM_RUNNING), whereas printk_delay is
configurable only via sysctl and thus is only used post boot.
Let's deprecate the boot_delay feature in favour of printk_delay. In order
to preserve functionality, we'll also extend printk_delay such that it can
additionally configured via an early kernel parameter.
Behavior change:
The delay enabled by both "boot_delay" and "printk_delay" continues
working even in SYSTEM_RUNNING state. It must be explicitly stopped
by setting printk_delay=0 via sysctl.
The delay is skipped when the message is suppressed in all system
states. It used to skipped only for the boot_delay.
Signed-off-by: Andrew Murray <amurray@thegoodpenguin.co.uk>
---
kernel/printk/printk.c | 81 +++++++++++++++++++++++++++++++-------------------
1 file changed, 51 insertions(+), 30 deletions(-)
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 28e6dff2faa7d4294c1b2ebe2844ce5d4dc0e05a..4517266e9ca112e0dcb0163a99dd0e8d50931848 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -1291,43 +1291,28 @@ static bool suppress_message_printing(int level)
#ifdef CONFIG_GENERIC_CALIBRATE_DELAY
-static unsigned int boot_delay; /* msecs delay after each printk during bootup */
static unsigned long long loops_per_msec; /* based on boot_delay */
-static int __init boot_delay_setup(char *str)
+static void __init printk_delay_calculate(void)
{
unsigned long lpj;
- int boot_delay_val;
lpj = preset_lpj ? preset_lpj : 1000000; /* some guess */
loops_per_msec = (unsigned long long)lpj / 1000 * HZ;
- get_option(&str, &boot_delay_val);
- if (boot_delay_val < 0 || boot_delay_val > 10 * 1000)
- return 0;
-
- boot_delay = (unsigned int)boot_delay_val;
-
- pr_debug("boot_delay: %u, preset_lpj: %ld, lpj: %lu, "
+ pr_debug("printk_delay: %u, preset_lpj: %ld, lpj: %lu, "
"HZ: %d, loops_per_msec: %llu\n",
- boot_delay, preset_lpj, lpj, HZ, loops_per_msec);
- return 0;
+ printk_delay_msec, preset_lpj, lpj, HZ, loops_per_msec);
}
-early_param("boot_delay", boot_delay_setup);
-static void boot_delay_msec(int level)
+static void early_boot_delay_msec(void)
{
unsigned long long k;
unsigned long timeout;
- bool suppress = !is_printk_force_console() &&
- suppress_message_printing(level);
-
- if ((boot_delay == 0 || system_state >= SYSTEM_RUNNING) || suppress)
- return;
- k = (unsigned long long)loops_per_msec * boot_delay;
+ k = (unsigned long long)loops_per_msec * printk_delay_msec;
- timeout = jiffies + msecs_to_jiffies(boot_delay);
+ timeout = jiffies + msecs_to_jiffies(printk_delay_msec);
while (k) {
k--;
cpu_relax();
@@ -1342,11 +1327,37 @@ static void boot_delay_msec(int level)
}
}
#else
-static inline void boot_delay_msec(int level)
+static inline void __init printk_delay_calculate(void)
+{
+}
+
+static inline void early_boot_delay_msec(void)
{
}
#endif
+static int __init printk_delay_setup(char *str)
+{
+ int printk_delay_val = 0;
+
+ get_option(&str, &printk_delay_val);
+ if (printk_delay_val < 0 || printk_delay_val > 10 * 1000)
+ return 0;
+
+ printk_delay_msec = (unsigned int)printk_delay_val;
+ printk_delay_calculate();
+
+ return 0;
+}
+early_param("printk_delay", printk_delay_setup);
+
+static int __init boot_delay_setup(char *str)
+{
+ pr_warn("boot_delay will soon be deprecated, please use printk_delay instead\n");
+ return printk_delay_setup(str);
+}
+early_param("boot_delay", boot_delay_setup);
+
static bool printk_time = IS_ENABLED(CONFIG_PRINTK_TIME);
module_param_named(time, printk_time, bool, S_IRUGO | S_IWUSR);
@@ -2122,18 +2133,28 @@ static u8 *__printk_recursion_counter(void)
unsigned int printk_delay_msec __read_mostly;
+static inline void late_boot_delay_msec(void)
+{
+ unsigned int m = printk_delay_msec;
+
+ while (m--) {
+ mdelay(1);
+ touch_nmi_watchdog();
+ }
+}
+
static inline void printk_delay(int level)
{
- boot_delay_msec(level);
+ bool suppress = !is_printk_force_console() &&
+ suppress_message_printing(level);
- if (unlikely(printk_delay_msec)) {
- unsigned int m = printk_delay_msec;
+ if (likely(!printk_delay_msec) || suppress)
+ return;
- while (m--) {
- mdelay(1);
- touch_nmi_watchdog();
- }
- }
+ if (system_state < SYSTEM_RUNNING)
+ early_boot_delay_msec();
+ else
+ late_boot_delay_msec();
}
#define CALLER_ID_MASK 0x80000000
--
2.34.1
^ permalink raw reply related
* [PATCH v3 5/6] printk: nbcon: move printk_delay to console emiting code
From: Andrew Murray @ 2026-07-12 10:20 UTC (permalink / raw)
To: Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
Jonathan Corbet, Shuah Khan, Russell King, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Andrew Morton, Greg Kroah-Hartman, Sebastian Andrzej Siewior,
Clark Williams
Cc: linux-kernel, linux-doc, linux-arm-kernel, linux-rpi-kernel,
linux-rt-devel, Andrew Murray
In-Reply-To: <20260712-printkcleanup-v3-0-574547b8f71b@thegoodpenguin.co.uk>
The printk_delay and boot_delay features are helpful for debugging
as kernel output can be slowed down during boot allowing messages to
be seen before scrolling off the screen, or to correlate timing between
some physical event and console output.
However, since the introduction of nbcon and the legacy printer thread
for PREEMPT_RT kernels, printk records are now emited to the console
asynchronously to the caller of printk. Thus, any printk delay added by
boot_delay/printk_delay continues to slow down the calling process but
may not have any impact to the rate in which records are emited to the
console.
Let's address this by moving the printk delay from the calling code
to the console emiting code instead. Whilst this ensures that delays
are still observed (especially for slower consoles), it doesn't improve
the use-case of using boot_delay/printk_delay to correlate timings
between physical events and console output.
Behavior change:
Please note that printk delays now occur after messages are emitted
rather than before.
Please also note that the printk delays occur within the printk_safe
(irqs off) context.
Signed-off-by: Andrew Murray <amurray@thegoodpenguin.co.uk>
---
include/linux/console.h | 5 ++++-
include/linux/printk.h | 1 -
kernel/printk/internal.h | 6 ++++++
kernel/printk/nbcon.c | 13 +++++++++++++
kernel/printk/printk.c | 17 +++++++++--------
5 files changed, 32 insertions(+), 10 deletions(-)
diff --git a/include/linux/console.h b/include/linux/console.h
index d624200cfc1708bf73925892a466efe0c95c5586..0f7a69bd1a42af38208fdb28971114f76f99a968 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -266,6 +266,8 @@ struct printk_buffers;
* might cause a system freeze when the console
* is used later.
* @backlog: Ringbuffer has pending records
+ * @emitted: The context attempted to emit the message. Might
+ * be incomplete.
* @pbufs: Pointer to the text buffer for this context
* @seq: The sequence number to print for this context
*/
@@ -278,6 +280,7 @@ struct nbcon_context {
/* members set by emit */
unsigned int backlog : 1;
+ unsigned char emitted : 1;
/* members set by acquire */
struct printk_buffers *pbufs;
@@ -298,7 +301,7 @@ struct nbcon_write_context {
struct nbcon_context __private ctxt;
char *outbuf;
unsigned int len;
- bool unsafe_takeover;
+ unsigned char unsafe_takeover : 1;
#ifdef CONFIG_PRINTK_EXECUTION_CTX
int cpu;
pid_t pid;
diff --git a/include/linux/printk.h b/include/linux/printk.h
index ea52dc72b73b64898f82a0319b01c27323b18dee..8885e11367d50ea1cd7642249852d011e589adb4 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -188,7 +188,6 @@ extern int __printk_ratelimit(const char *func);
extern bool printk_timed_ratelimit(unsigned long *caller_jiffies,
unsigned int interval_msec);
-extern unsigned int printk_delay_msec;
extern int dmesg_restrict;
extern void wake_up_klogd(void);
diff --git a/kernel/printk/internal.h b/kernel/printk/internal.h
index 85fbf1801cbe070ad96d253bccdf775a11bf945a..c3586f8b8360208902bbbd4607413997bcbd5fb9 100644
--- a/kernel/printk/internal.h
+++ b/kernel/printk/internal.h
@@ -33,6 +33,8 @@ int devkmsg_sysctl_set_loglvl(const struct ctl_table *table, int write,
# define force_legacy_kthread() (false)
#endif
+extern unsigned int printk_delay_msec;
+
#ifdef CONFIG_PRINTK
#ifdef CONFIG_PRINTK_CALLER
@@ -131,6 +133,8 @@ static inline void nbcon_kthread_wake(struct console *con)
rcuwait_wake_up(&con->rcuwait); /* LMM(nbcon_kthread_wake:A) */
}
+void printk_delay(bool use_atomic);
+
#else
#define PRINTK_PREFIX_MAX 0
@@ -162,6 +166,8 @@ static inline bool nbcon_legacy_emit_next_record(struct console *con, bool *hand
static inline void nbcon_kthread_wake(struct console *con) { }
static inline void nbcon_kthreads_wake(void) { }
+static inline void printk_delay(bool use_atomic) { }
+
#endif /* CONFIG_PRINTK */
extern bool have_boot_console;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index 4b03b019cd5ee25d68e9ace84392045e91241a7f..c8427906b1c54fb00d005ef87f7280e89fae2579 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1069,6 +1069,8 @@ static bool nbcon_emit_next_record(struct nbcon_write_context *wctxt, bool use_a
else
con->write_thread(con, wctxt);
+ ctxt->emitted = 1;
+
if (!wctxt->outbuf) {
/*
* Ownership was lost and reacquired by the driver. Handle it
@@ -1267,11 +1269,16 @@ static int nbcon_kthread_func(void *__console)
con_flags = console_srcu_read_flags(con);
+ ctxt->emitted = 0;
+
if (console_is_usable(con, con_flags, false))
backlog = nbcon_emit_one(&wctxt, false);
console_srcu_read_unlock(cookie);
+ if (backlog && ctxt->emitted)
+ printk_delay(false);
+
cond_resched();
} while (backlog);
@@ -1525,6 +1532,8 @@ bool nbcon_legacy_emit_next_record(struct console *con, bool *handover,
}
progress = nbcon_emit_one(&wctxt, use_atomic);
+ if (progress && ctxt->emitted)
+ printk_delay(use_atomic);
if (use_atomic) {
start_critical_timings();
@@ -1584,6 +1593,8 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
if (!nbcon_context_try_acquire(ctxt, false))
return -EPERM;
+ ctxt->emitted = 0;
+
/*
* nbcon_emit_next_record() returns false when
* the console was handed over or taken over.
@@ -1600,6 +1611,8 @@ static int __nbcon_atomic_flush_pending_con(struct console *con, u64 stop_seq)
if (nbcon_seq_read(con) < stop_seq)
err = -ENOENT;
break;
+ } else if (ctxt->emitted) {
+ printk_delay(true);
}
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index 4517266e9ca112e0dcb0163a99dd0e8d50931848..5df09e56cf8abc2d0555b6950eed4e483ba56d4b 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2143,18 +2143,17 @@ static inline void late_boot_delay_msec(void)
}
}
-static inline void printk_delay(int level)
+void printk_delay(bool use_atomic)
{
- bool suppress = !is_printk_force_console() &&
- suppress_message_printing(level);
-
- if (likely(!printk_delay_msec) || suppress)
+ if (likely(!printk_delay_msec))
return;
if (system_state < SYSTEM_RUNNING)
early_boot_delay_msec();
- else
+ else if (use_atomic)
late_boot_delay_msec();
+ else
+ msleep(printk_delay_msec);
}
#define CALLER_ID_MASK 0x80000000
@@ -2474,8 +2473,6 @@ asmlinkage int vprintk_emit(int facility, int level,
ft.legacy_direct = false;
}
- printk_delay(level);
-
printed_len = vprintk_store(facility, level, dev_info, fmt, args);
if (ft.nbcon_atomic)
@@ -3185,6 +3182,8 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
*/
con->write(con, outbuf, pmsg.outbuf_len);
+ printk_delay(true);
+
con->seq = pmsg.seq + 1;
} else {
/*
@@ -3206,6 +3205,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
printk_legacy_allow_spinlock_enter();
con->write(con, outbuf, pmsg.outbuf_len);
printk_legacy_allow_spinlock_exit();
+ printk_delay(true);
start_critical_timings();
@@ -3214,6 +3214,7 @@ static bool console_emit_next_record(struct console *con, bool *handover, int co
*handover = console_lock_spinning_disable_and_check(cookie);
printk_safe_exit_irqrestore(flags);
}
+
skip:
return true;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v3 6/6] Documentation/kernel-parameters: add/update printk_delay/boot_delay
From: Andrew Murray @ 2026-07-12 10:20 UTC (permalink / raw)
To: Petr Mladek, Steven Rostedt, John Ogness, Sergey Senozhatsky,
Jonathan Corbet, Shuah Khan, Russell King, Florian Fainelli,
Broadcom internal kernel review list, Ray Jui, Scott Branden,
Andrew Morton, Greg Kroah-Hartman, Sebastian Andrzej Siewior,
Clark Williams
Cc: linux-kernel, linux-doc, linux-arm-kernel, linux-rpi-kernel,
linux-rt-devel, Andrew Murray
In-Reply-To: <20260712-printkcleanup-v3-0-574547b8f71b@thegoodpenguin.co.uk>
boot_delay has been deprecated in favour of an extended printk_delay,
let's update kernel-parameters to reflect the addition of printk_delay
and the deprecation of boot_delay.
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Andrew Murray <amurray@thegoodpenguin.co.uk>
---
Documentation/admin-guide/kernel-parameters.txt | 31 +++++++++++++++++++++----
1 file changed, 26 insertions(+), 5 deletions(-)
diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 2884103b93bca7b76cd3a93946276074cf62d0a1..1118feda87b1b04543b1da0bd52c090b1fddaeac 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -650,11 +650,19 @@ Kernel parameters
See Documentation/block/cmdline-partition.rst
boot_delay= [KNL,EARLY]
- Milliseconds to delay each printk during boot.
- Only works if GENERIC_CALIBRATE_DELAY is enabled,
- and you may also have to specify "lpj=". Boot_delay
- values larger than 10 seconds (10000) are assumed
- erroneous and ignored.
+ Milliseconds to delay each printk during and post boot.
+ Boot time delays only work if GENERIC_CALIBRATE_DELAY
+ is enabled.
+
+ Once booted the delay can be removed or adjusted via
+ the printk_delay sysctl.
+
+ Please note that you may also have to specify "lpj=".
+ Boot_delay values larger than 10 seconds (10000) are
+ assumed erroneous and ignored.
+
+ This will soon be deprecated, please use printk_delay
+ instead.
Format: integer
bootconfig [KNL,EARLY]
@@ -5468,6 +5476,19 @@ Kernel parameters
printk.time= Show timing data prefixed to each printk message line
Format: <bool> (1/Y/y=enable, 0/N/n=disable)
+ printk_delay= [KNL,EARLY]
+ Milliseconds to delay each printk during and post boot.
+ Boot time delays only work if GENERIC_CALIBRATE_DELAY
+ is enabled.
+
+ Once booted the delay can be removed or adjusted via
+ the printk_delay sysctl.
+
+ Please note that you may also have to specify "lpj=".
+ printk_delay values larger than 10 seconds (10000) are
+ assumed erroneous and ignored.
+ Format: integer
+
proc_mem.force_override= [KNL]
Format: {always | ptrace | never}
Traditionally /proc/pid/mem allows memory permissions to be
--
2.34.1
^ permalink raw reply related
* Re: Bad wrapping in some tables
From: Rito Rhymes @ 2026-07-12 10:45 UTC (permalink / raw)
To: Jonathan Corbet, Rito Rhymes, Daniel Lundberg Pedersen, linux-doc,
linux-media
In-Reply-To: <87bjcen9j1.fsf@trenco.lwn.net>
> > Reason 2: the real culprit here is this:
> >
> > Table mobile responsiveness in general in the Linux kernel
> > documentation is systemically pathological.
>
> I honestly have to question how important that is to us. How many
> people are really trying to make use of the kernel documentation on
> small-screen devices? This is the kind of information you need when
> you have editor and terminal windows open.
To clarify, when I say mobile responsive, I'm using that as a term of
art for narrow viewports within the tablet / mobile window size range,
I'm not specifically or exclusively referring to mobile devices, and I'm
operating knowing that desktop is the primary medium here. The fixes
should all be improving desktop experience at these narrow sizes; mobile
devices also being improved but not as the primary focus.
> I tend to use relatively narrow browser windows so that I can fit more
> of them on the screen
^ (Your response in the thread for Mauro's body width change)
You are one of the beneficiaries, among many others with similar
habits on desktop that make use of narrow windows.
I'm testing a few things out to see what's a reasonably simple path
forward.
^ permalink raw reply
* [Issue] maintainer-handbooks: html: list has duplicates
From: Manuel Ebner @ 2026-07-12 10:45 UTC (permalink / raw)
To: Jonathan Corbet, Shuah Khan; +Cc: linux-kernel, linux-doc, workflows
Hi,
I was reading documentation when I stumbled across this. There's a lot of
repetition in the list at: https://docs.kernel.org/process/maintainer-handbooks.html
See below.
Thanks
Manuel
> [...]
> For maintainers, consider documenting additional requirements and expectations if submissions
> routinely overlook specific submission criteria. See Maintainer Entry Profile.
>
> process/maintainer-soc
> process/maintainer-soc-clean-dts
> process/maintainer-soc-clean-dts
> Audit Subsystem
> process/maintainer-tip
> process/maintainer-tip
> mm/damon/maintainer-profile
> process/maintainer-tip
> doc-guide/maintainer-profile
> process/maintainer-tip
> process/maintainer-tip
> process/maintainer-soc-clean-dts
> process/maintainer-tip
> process/maintainer-tip
> process/maintainer-tip
> filesystems/nfs/nfsd-maintainer-entry-profile
> process/maintainer-kvm-x86
> nvdimm/maintainer-entry-profile
> nvdimm/maintainer-entry-profile
> nvdimm/maintainer-entry-profile
> process/maintainer-tip
> driver-api/media/maintainer-entry-profile
> process/maintainer-netdev
> process/maintainer-netdev
> process/maintainer-tip
> process/maintainer-tip
> process/maintainer-tip
> process/maintainer-tip
> arch/riscv/patch-acceptance
> Rust
> Rust [Pin-Init]
> process/maintainer-tip
> Security Subsystem
> Selinux Security Module
> driver-api/vfio-pci-device-specific-driver-acceptance
> process/maintainer-tip
> filesystems/xfs/xfs-maintainer-entry-profile
^ permalink raw reply
* Re: Bad wrapping in some tables
From: Rito Rhymes @ 2026-07-12 11:19 UTC (permalink / raw)
To: Mauro Carvalho Chehab, Hans Verkuil
Cc: Rito Rhymes, Jonathan Corbet, Daniel Lundberg Pedersen, linux-doc,
linux-media
In-Reply-To: <20260710104220.2b165f2d@foz.lan>
> Breaking up literals is more important on PDF output, if one wants to
> print the documentation.
Could you clarify what you mean by PDF output here? Are you referring to
printing the HTML page through the browser, or to the PDF generated by
the Sphinx build process?
Are there any known problems or constraints we should account for
printing? I assume you may mean that long unbroken literals can make
tables wider than the printable page and hide outer columns, that and
horizontal scroll overflow in general may be clipped when printing,
making wrapping preferable for that output.
That makes sense for print, but it is not necessarily the preferable
behavior for navigating the normal HTML page, where contained horizontal
scroll overflow can preserve the page and table structure. I do not
think the print constraint should override the primary HTML
presentation.
I would like to account for both. If this concerns browser printing, we
may be able to apply the necessary wrapping selectively through
`@media print`.
Rito
^ permalink raw reply
* Re: [Issue] maintainer-handbooks: html: list has duplicates
From: Manuel Ebner @ 2026-07-12 11:56 UTC (permalink / raw)
To: manuelebner; +Cc: corbet, linux-doc, linux-kernel, skhan, workflows
In-Reply-To: <98a558a87a07ab641f47c66c372ee7ed0735f4f5.camel@mailbox.org>
There are only two patches which can cause that:
commit 8eae6da5f56c ("docs: auto-generate maintainer entry profile links")
commit bda185c30593 ("docs: maintainers_include: Only show main entry for profiles")
Therefore adding Mauro to recipients.
^ permalink raw reply
* Re: [Issue] maintainer-handbooks: html: list has duplicates
From: Manuel Ebner @ 2026-07-12 11:58 UTC (permalink / raw)
To: Mauro Carvalho Chehab, manuelebner
Cc: corbet, linux-doc, linux-kernel, skhan, workflows
In-Reply-To: <98a558a87a07ab641f47c66c372ee7ed0735f4f5.camel@mailbox.org>
There are only two patches which can cause that:
commit 8eae6da5f56c ("docs: auto-generate maintainer entry profile links")
commit bda185c30593 ("docs: maintainers_include: Only show main entry for profiles")
Therefore adding Mauro to recipients.
^ permalink raw reply
* Re: [PATCH v2 0/5] binfmt_misc: bpf-backed binary type handlers
From: Christian Brauner @ 2026-07-12 12:32 UTC (permalink / raw)
To: Farid Zakaria
Cc: Christian Brauner, Alexei Starovoitov, Daniel Borkmann,
Martin KaFai Lau, Shuah Khan, Andrii Nakryiko, Kees Cook,
Alexander Viro, Jan Kara, Jonathan Corbet, Jann Horn,
John Ericson, linux-fsdevel, linux-mm, linux-kernel, bpf,
linux-doc, linux-kselftest
In-Reply-To: <20260711-binfmt-misc-bpf-v2-v2-0-d6591ceaf207@gmail.com>
> This is a continuation of Christian's bpf-backed binfmt_misc POC [1], which he offered
> to hand off to me. I am carrying it forward. The kernel design is his and is
> unchanged. This series rebases it onto his binfmt_misc locking/cleanup series [2]
> and adds selftests (+ fixed from the one's shared), and therefore does
> not apply to mainline alone.
>
> As for motivation for this whole change, Christian did a great VL;MR;
> write-up [1].
>
> TL;DR: binfmt_misc can match a binary and hand it to a fixed interpreter,
> but it can't match programmatically or compute the interpreter per binary.
> The Nix community would love to support relocatable binaries, where the
> correct loader can only be found relative to the binary itself.
> This adds a 'B' handler type: a binfmt_misc_ops struct_ops program that
> inspects the binary and picks the interpreter with one new kfunc,
> bpf_binprm_set_interp().
>
> bpftool struct_ops register nix_origin.bpf.o /sys/fs/bpf
> echo ':nix-origin:B:nix_origin::::' > /proc/sys/fs/binfmt_misc/register
Thanks! So I've spent some more time working on this because I had some
future ideas that I needed to make sure could be accomodated by this
(currently on vacation but hey...). So the version I have givex this a
better design and has future extensibility in mind:
- The single sleepable load op is split into two ops:
struct binfmt_misc_ops {
bool (*match)(struct linux_binprm *bprm);
int (*load)(struct linux_binprm *bprm);
char name[BINFMT_MISC_OPS_NAME_MAX];
};
The non-sleepable match program runs from the RCU entry lookup
walk itself, exactly like magic and extension matching: same
registration order, same first-match-wins semantics, and it can
only rely on the prefetched bprm->buf. It must be free of side
effects since the walk may be restarted.
The sleepable load program runs once the walk has committed to the
entry and does the file reading and the interpreter selection. Both
ops are mandatory, the struct_ops plumbing enforces the sleepability
of each, and since bpf_binprm_set_interp() is KF_SLEEPABLE a match
program cannot select an interpreter by construction.
- A match is a commitment. A failing load program fails the exec instead
of falling through to later entries. -ENOEXEC keeps its usual meaning
and hands the binary to the remaining binary formats, for a handler
that discovers it cannot serve the binary after all.
This kills the part of v1 I disliked the most: the skip cursor and the
leave-and-rescan loop in load_misc_binary() are gone. The walk is
never left and re-entered, and 'B' entries need no special semantics
against concurrent (un)registration anymore.
Your v2 changelog note about keeping the bpf retry loop in the
__free() style is moot as a consequence. The loop no longer exists.
- The load return convention flipped: 0 now means success after the
program called bpf_binprm_set_interp(). Returning 0 without having
selected an interpreter or returning a positive value is treated as
-ENOEXEC, other negative errnos fail the exec.
So the "return bpf_binprm_set_interp(...) ?: 1" idiom from the v1-era
programs becomes plain "return bpf_binprm_set_interp(...)".
- The handler name moved from the offset field to the interpreter field
that field consistently names whoever supplies the interpreter, a path
for static entries, a handler for 'B' entries. Offset, magic, and mask
must be empty:
echo ':nix-origin:B::::nix_origin:' > register
- 'C' is allowed now, v1 rejected it. It behaves exactly as for a static
entry. The setuid transition stays gated by vfsuid_has_mapping() in
the caller's user namespace. Which makes 'B' handlers usable for a
per-binary loader over setuid binaries. 'F' stays rejected as there
is no fixed interpreter to pre-open (I have other ideas how we'll do
something like it later.).
Nothing changed in the exec patch, the fs kfuncs patch, the kfunc
itself, or the registry/namespacing model.
I can send v3 in a bit if that's ok.
--
Christian Brauner <brauner@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 01/19] dt-bindings: crypto: add Rambus CryptoManager Hub
From: Conor Dooley @ 2026-07-12 13:15 UTC (permalink / raw)
To: Ousherovitch, Alex
Cc: Conor Dooley, Krishnamoorthy, Saravanakrishnan, Albert Ou,
Conor Dooley, David S. Miller, Herbert Xu, Jonathan Corbet,
Krzysztof Kozlowski, Palmer Dabbelt, Paul Walmsley, Rob Herring,
Shuah Khan, Alexandre Ghiti, devicetree@vger.kernel.org,
Wittenauer, Joel, linux-api@vger.kernel.org,
linux-crypto@vger.kernel.org, linux-doc@vger.kernel.org,
linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
linux-riscv@lists.infradead.org, Shuah Khan, Nguyen, Thi
In-Reply-To: <SA3PR04MB9001E7DC9B2D4788EDCE2390D7FD2@SA3PR04MB9001.namprd04.prod.outlook.com>
[-- Attachment #1: Type: text/plain, Size: 3761 bytes --]
On Fri, Jul 10, 2026 at 11:14:11PM +0000, Ousherovitch, Alex wrote:
> On Fri, Jul 10, 2026 at 1:59 AM, Conor Dooley <conor.dooley@microchip.com> wrote:
>
> > This company no longer exists, you should probably introduce a rambus
> > vendor prefix instead.
Please fix your quoting, you need to retain context beyond what I said
so that people who get 100s of mails per day (me) remember what it was
in response to.
>
> Cryptography Research, Inc. does still exist -- it's now a wholly-owned
> subsidiary of Rambus (our co-maintainer is @cryptography.com). The
> prefix names the IP originator, which is consistent with existing
> subsidiary/acquired-vendor prefixes in the tree (e.g. al = Annapurna
> Labs under Amazon, mstar noted as acquired by MediaTek, fsl, cavium,
> xlnx). We'd prefer to keep "cri" on that basis, and can annotate the
I'm not sure that these examples actually aid your cause.
al has been replaced by amazon, fsl is not used for new devices, new xlnx
devices use amd (only example for now is the riscv stuff I think),
cavium has had nothing added in donkey's years etc. mstar I don't see
anything new in years either.
> description as "Cryptography Research, Inc. (a Rambus company)" to make
> the ownership explicit. Happy to switch if you feel strongly.
>
> > This property seems like it could be replaced by having a reg entry
> > for each mailbox.
>
> Agreed -- v3 will make each mailbox a subnode with its own reg window
> and drop cri,mbx-instances.
>
> > This looks like it should be deducible from a device-specific
> > compatible. [slots/strides]
>
> These aren't fixed per silicon -- they're the per-mailbox layout of the
> VCQ rings in host DMA memory, chosen at platform integration and
> programmed by the driver into the mailbox QUEUE/SLOTS/STRIDE registers.
> They can differ per mailbox on the same silicon, so a compatible can't
I'm not sure. Unless there's more than one instance, this definitely
sounds like something that you can determine from the compatible.
Generally these kinds of accelerators tend not to have multiple
instances though, so each platform will have a different compatible,
and the driver can store an array of mailbox configurations.
> encode them. v3 will keep them as optional, defaulted properties on the
> per-mailbox subnodes.
>
> > This whole subnode thing seems like it is only required because you
> > don't have device-specific compatibles [cores].
>
> Core presence is actually discoverable at runtime from the CORE_ENABLE
> register, so v3 will drop the per-core child nodes entirely and probe
> for enabled cores -- no per-variant compatible needed.
No, per-variant compatibles (for the devices/socs that this IP is
integrated into) are a requirement. While it would have been handy for
detecting capabilities, it's a requirement for other reasons:
differences between integrations be that functional or enforcing the
correct constraints on properties, issues only present on select
devices, etc.
On that note, I see there's no clocks or resets properties added by your
patch. While the IP may not have a reset (although I suspect it
probably does) there's no way it functions without a clock.
Cheers,
Conor.
>
> > this could probably be handled via reg-names? [affinity]
>
> Yes -- v3 will express affinity per mailbox (a "role" of a specific core
> type for a dedicated mailbox, or "generic" for the round-robin pool),
> which is the subnode analog of your reg-names idea. One caveat: this
> cleanly covers 1:1 core-to-mailbox dedication plus a shared pool; a
> mailbox dedicated to several specific cores would need multiple role
> tokens.
>
> Thanks -- this restructures nicely.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH] docs/zh_CN: add docs-next checkout workaround
From: Weijie Yuan @ 2026-07-12 13:42 UTC (permalink / raw)
To: Dongliang Mu
Cc: Alex Shi, Yanteng Si, Jonathan Corbet, Shuah Khan, linux-kernel,
linux-doc
In-Reply-To: <8f01e453-6a4b-4f35-b533-55d89c1a9ae4@hust.edu.cn>
On Sun, Jul 12, 2026 at 04:35:21PM +0800, Dongliang Mu wrote:
> > GIT_TRACE=1 \
> > GIT_TRACE_CURL=1 \
> > GIT_CURL_VERBOSE=1 \
> > git clone https://mirror.nju.edu.cn/git/kernel-doc-zh.git/
> >
> > [...many verbose outputs]
> > remote: Enumerating objects: 11675982, done.
> > remote: Counting objects: 100% (11675982/11675982), done.
> > remote: Compressing objects: 100% (2008049/2008049), done.
> > 13:24:10.505880 http.c:994 == Info: HTTP/2 stream 5 was not closed cleanly: INTERNAL_ERROR (err 2)
> > 13:24:10.505973 http.c:994 == Info: Connection #0 to host mirror.nju.edu.cn left intact
> > error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: INTERNAL_ERROR (err 2)
> > error: 6191 bytes of body are still expected
> > fetch-pack: unexpected disconnect while reading sideband packet
> > fatal: early EOF
> > fatal: fetch-pack: invalid index-pack output
>
> It seems like the same issue with our mirror site. I've forward this email
> thread to NJU mirror maintainers.
Very much appreciated. They might obtain more useful information from
their server logs.
>
>
> > From the output, it seems that there was an error in the mirror of NJU's
> > nginx, the Git HTTP backend behind nginx, or the upstream connection
> > between them, but I'm not 100% sure.
> >
> > I will conduct several more tests immediately to troubleshoot the
> > problem, to see where exactly the problem lies.
> >
> > In addition, cloning with a cloud server in Hong Kong:
> >
> > Cloning into 'kernel-doc-zh'...
> > remote: Enumerating objects: 11675982, done.
> > remote: Counting objects: 100% (11675982/11675982), done.
> > remote: Compressing objects: 100% (2008049/2008049), done.
> > error: RPC failed; curl 92 HTTP/2 stream 5 was not closed cleanly: INTERNAL_ERROR (err 2)
> > error: 3965 bytes of body are still expected
> > fetch-pack: unexpected disconnect while reading sideband packet
> > fatal: early EOF
> > fatal: fetch-pack: invalid index-pack output
>
>
> I tried the NJU mirror in my laptop, and successfully clone the repository
> from NJU mirror. There must exist some unknown reason to lead to this
> failure.
Ah, I'm starting to doubt on my side now...
Anyway, I'll check again.
Thanks!
^ permalink raw reply
* Re: [PATCH v12 00/29] KVM: arm64: Implement support for SME
From: Fuad Tabba @ 2026-07-12 14:03 UTC (permalink / raw)
To: Mark Brown
Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
Oliver Upton, Dave Martin, Mark Rutland, Ben Horgan,
Jean-Philippe Brucker, linux-arm-kernel, kvmarm, linux-kernel,
kvm, linux-doc, linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <20260709-kvm-arm64-sme-v12-0-d0301d79ef58@kernel.org>
Hi Mark,
On Thu, 9 Jul 2026 at 19:40, Mark Brown <broonie@kernel.org> wrote:
>
> [ Note: I've spoken with both Mark Rutland and James Morse both of whom
> might potentially have some overlapping changes, they've both agreed
> that they'll deal with any rebasing if it's a question of this getting
> in or something else. ]
>
> I've removed the RFC tag from this version of the series, but the items
> that I'm looking for feedback on remains the same:
>
> - The userspace ABI, in particular:
> - The vector length used for the SVE registers, access to the SVE
> registers and access to ZA and (if available) ZT0 depending on
> the current state of PSTATE.{SM,ZA}.
> - The use of a single finalisation for both SVE and SME.
> - There was some review from the qemu people who seemed OK with the
> structure, and there's some initial patches from them at:
> https://patchew.org/QEMU/20260216034432.23912-1-richard.henderson@linaro.org/
The state-dependent Z/P view and SVCR.ZA gating make sense to me, and
lossless: the inaccessible state is only reachable via an SM/ZA
transition, which zeroes the affected registers.
Single finalisation via KVM_ARM_VCPU_VEC makes sense too: splitting it
would leave the SVE registers writable while their VL could still
move.
Unrelated: on the get-reg-list restructuring you mention deferring to
a separate series: since ZA, ZT0 and SME_VLS are the
migration-critical SME state, it'd be good if that series also covered
a save/restore round-trip for them, not just get-reg-list enumeration.
Cheers,
/fuad
> This series implements support for SME use in non-protected KVM guests.
> Much of this is very similar to SVE, the main additional challenge that
> SME presents is that it introduces a new vector length similar to the
> SVE vector length and two new controls which change the registers seen
> by guests:
>
> - PSTATE.ZA enables the ZA matrix register and, if SME2 is supported,
> the ZT0 LUT register.
> - PSTATE.SM enables streaming mode, a new floating point mode which
> uses the SVE register set with the separately configured SME vector
> length. In streaming mode implementation of the FFR register is
> optional.
>
> It is also permitted to build systems which support SME without SVE, in
> this case when not in streaming mode no SVE registers or instructions
> are available. Further, there is no requirement that there be any
> overlap in the set of vector lengths supported by SVE and SME in a
> system, this is expected to be a common situation in practical systems.
>
> Since there is a new vector length to configure we introduce a new
> feature parallel to the existing SVE one with a new pseudo register for
> the streaming mode vector length. Due to the overlap with SVE caused by
> streaming mode rather than finalising SME as a separate feature we use
> the existing SVE finalisation to also finalise SME, a new define
> KVM_ARM_VCPU_VEC is provided to help make user code clearer. Finalising
> SVE and SME separately would introduce complication with register access
> since finalising SVE makes the SVE registers writeable by userspace and
> doing multiple finalisations results in an error being reported.
> Dealing with a state where the SVE registers are writeable due to one of
> SVE or SME being finalised but may have their VL changed by the other
> being finalised seems like needless complexity with minimal practical
> utility, it seems clearer to just express directly that only one
> finalisation can be done in the ABI.
>
> Access to the floating point registers follows the architecture:
>
> - When both SVE and SME are present:
> - If PSTATE.SM == 0 the vector length used for the Z and P registers
> is the SVE vector length.
> - If PSTATE.SM == 1 the vector length used for the Z and P registers
> is the SME vector length.
> - If only SME is present:
> - If PSTATE.SM == 0 the Z and P registers are inaccessible and the
> floating point state accessed via the encodings for the V registers.
> - If PSTATE.SM == 1 the vector length used for the Z and P registers
> - The SME specific ZA and ZT0 registers are only accessible if SVCR.ZA is 1.
>
> The VMM must understand this, in particular when loading state SVCR
> should be configured before other state. It should be noted that while
> the architecture refers to PSTATE.SM and PSTATE.ZA these PSTATE bits are
> not preserved in SPSR_ELx, they are only accessible via SVCR.
>
> There are a large number of subfeatures for SME, most of which only
> offer additional instructions but some of which (SME2 and FA64) add
> architectural state. These are configured via the ID registers as per
> usual.
>
> Protected KVM is supported, with the implementation maintaining the
> existing restriction that the hypervisor will refuse to run if streaming
> mode or ZA is enabled. This both simplfies the code and avoids the need
> to allocate storage for host ZA and ZT0 state, there seems to be little
> practical use case for supporting this and the memory usage would be
> non-trivial. SME is not made available to protected guests, only normal
> guests.
>
> The new KVM_ARM_VCPU_VEC feature and ZA and ZT0 registers have not been
> added to the get-reg-list selftest, the idea of supporting additional
> features there without restructuring the program to generate all
> possible feature combinations has been rejected. I will post a separate
> series which does that restructuring.
>
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
> Changes in v12:
> - Resend with commit rather than tag object specified as the base.
> - Link to v11: https://patch.msgid.link/20260709-kvm-arm64-sme-v11-0-32799f66db9d@kernel.org
>
> Changes in v11:
> - Rebase onto v7.2-rc2.
> - Rework VL enumeration.
> - Refactor ZCR and SMCR value generation for the host into helper
> functions.
> - Add handling of FEAT_IDST for hidden system registers.
> - Ensure we manage traps correctly for emulated EL2.
> - Always allocate space for ZT0 if the hardware supports it.
> - Tighten the register enumeration ABI to reflect current VM state.
> - Sanitise SMIDR_EL1.
> - Fix generation of invalid values in set_id_regs.
> - Various smaller fixups, including from Jean-Phillipe's review.
> - Link to v10: https://patch.msgid.link/20260306-kvm-arm64-sme-v10-0-43f7683a0fb7@kernel.org
>
> Changes in v10:
> - Define and use a SME_VQ_INVALID for the case where there is no
> virtuablisable SME VL.
> - Fix handling of SMCR_EL2 accesses.
> - Correct VNCR constant for SMPRI_EL2.
> - Correct trapping for SMPRI_EL1.
> - Reject userspace access to FFR when in streaming mode without FA64.
> - Constrain the VL set by sme_cond_update_smcr() to fit within LEN.
> - Reject userspace access to ZA and ZT0 when SVCR.SM is 0.
> - Use -EACCESS for inaccessible SME registers.
> - Remove some unused functions.
> - Further bugfixes from review.
> - Commit log typo fixes.
>
> - Link to v9: https://patch.msgid.link/20251223-kvm-arm64-sme-v9-0-8be3867cb883@kernel.org
>
> Changes in v9:
> - Rebase onto v6.19-rc1.
> - ABI document clarifications.
> - Add changes dropping asserts on single bit wide bitfields in set_id_regs.
> - Link to v8: https://lore.kernel.org/r/20250902-kvm-arm64-sme-v8-0-2cb2199c656c@kernel.org
>
> Changes in v8:
> - Small fixes in ABI documentation.
> - Link to v7: https://lore.kernel.org/r/20250822-kvm-arm64-sme-v7-0-7a65d82b8b10@kernel.org
>
> Changes in v7:
> - Rebase onto v6.17-rc1.
> - Handle SMIDR_EL1 as a VM wide ID register and use this in feat_sme_smps().
> - Expose affinity fields in SMIDR_EL1.
> - Remove SMPRI_EL1 from vcpu_sysreg, the value is always 0 currently.
> - Prevent userspace writes to SMPRIMAP_EL2.
> - Link to v6: https://lore.kernel.org/r/20250625-kvm-arm64-sme-v6-0-114cff4ffe04@kernel.org
>
> Changes in v6:
> - Rebase onto v6.16-rc3.
> - Link to v5: https://lore.kernel.org/r/20250417-kvm-arm64-sme-v5-0-f469a2d5f574@kernel.org
>
> Changes in v5:
> - Rebase onto v6.15-rc2.
> - Add pKVM guest support.
> - Always restore SVCR.
> - Link to v4: https://lore.kernel.org/r/20250214-kvm-arm64-sme-v4-0-d64a681adcc2@kernel.org
>
> Changes in v4:
> - Rebase onto v6.14-rc2 and Mark Rutland's fixes.
> - Expose SME to nested guests.
> - Additional cleanups and test fixes following on from the rebase.
> - Flush register state on VMM PSTATE.{SM,ZA}.
> - Link to v3: https://lore.kernel.org/r/20241220-kvm-arm64-sme-v3-0-05b018c1ffeb@kernel.org
>
> Changes in v3:
> - Rebase onto v6.12-rc2.
> - Link to v2: https://lore.kernel.org/r/20231222-kvm-arm64-sme-v2-0-da226cb180bb@kernel.org
>
> Changes in v2:
> - Rebase onto v6.7-rc3.
> - Configure subfeatures based on host system only.
> - Complete nVHE support.
> - There was some snafu with sending v1 out, it didn't make it to the
> lists but in case it hit people's inboxes I'm sending as v2.
>
> ---
> Mark Brown (29):
> arm64/sysreg: Define full value read/modify/write helpers
> arm64/fpsimd: Update FA64 and ZT0 enables when loading SME state
> arm64/fpsimd: Decide to save ZT0 and streaming mode FFR at bind time
> arm64/sve: Factor virtualizable VL discovery out of SVE specific code
> arm64/fpsimd: Determine maximum virtualisable SME vector length
> KVM: arm64: Handle FEAT_IDST for guest accesses to hidden registers
> KVM: arm64: Pull ctxt_has_ helpers to start of sysreg-sr.h
> KVM: arm64: Rename SVE finalization constants to be more general
> KVM: arm64: Define internal features for SME
> KVM: arm64: Rename sve_state_reg_region
> KVM: arm64: Store vector lengths in an array
> KVM: arm64: Factor SVE code out of fpsimd_lazy_switch_to_host()
> KVM: arm64: Document the KVM ABI for SME
> KVM: arm64: Implement SME vector length configuration
> KVM: arm64: Support SME control registers
> KVM: arm64: Support TPIDR2_EL0
> KVM: arm64: Support SME identification registers for guests
> KVM: arm64: Support SME priority registers
> KVM: arm64: Support userspace access to streaming mode Z and P registers
> KVM: arm64: Flush register state on writes to SVCR.SM and SVCR.ZA
> KVM: arm64: Expose SME specific state to userspace
> KVM: arm64: Context switch SME state for guests
> KVM: arm64: Handle SME exceptions
> KVM: arm64: Expose SME to nested guests
> KVM: arm64: Provide interface for configuring and enabling SME for guests
> KVM: arm64: selftests: Remove spurious check for single bit safe values
> KVM: arm64: selftests: Skip impossible invalid value tests
> KVM: arm64: selftests: Add SME system registers to get-reg-list
> KVM: arm64: selftests: Add SME to set_id_regs test
>
> Documentation/virt/kvm/api.rst | 124 +++++---
> arch/arm64/include/asm/fpsimd.h | 17 +-
> arch/arm64/include/asm/kvm_emulate.h | 16 +
> arch/arm64/include/asm/kvm_host.h | 113 ++++++-
> arch/arm64/include/asm/kvm_hyp.h | 2 +-
> arch/arm64/include/asm/kvm_nested.h | 2 +
> arch/arm64/include/asm/kvm_pkvm.h | 2 +-
> arch/arm64/include/asm/sysreg.h | 8 +
> arch/arm64/include/asm/vncr_mapping.h | 2 +
> arch/arm64/include/uapi/asm/kvm.h | 34 +++
> arch/arm64/kernel/cpufeature.c | 2 -
> arch/arm64/kernel/fpsimd.c | 134 ++++----
> arch/arm64/kvm/arm.c | 10 +
> arch/arm64/kvm/config.c | 12 +-
> arch/arm64/kvm/emulate-nested.c | 6 +-
> arch/arm64/kvm/fpsimd.c | 27 +-
> arch/arm64/kvm/guest.c | 369 ++++++++++++++++++++---
> arch/arm64/kvm/handle_exit.c | 14 +
> arch/arm64/kvm/hyp/include/hyp/switch.h | 234 +++++++++++---
> arch/arm64/kvm/hyp/include/hyp/sysreg-sr.h | 96 +++---
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 129 ++++++--
> arch/arm64/kvm/hyp/nvhe/pkvm.c | 90 ++++--
> arch/arm64/kvm/hyp/nvhe/switch.c | 2 +
> arch/arm64/kvm/hyp/nvhe/sys_regs.c | 6 +
> arch/arm64/kvm/hyp/vhe/switch.c | 17 +-
> arch/arm64/kvm/hyp/vhe/sysreg-sr.c | 7 +
> arch/arm64/kvm/inject_fault.c | 15 +
> arch/arm64/kvm/nested.c | 8 +-
> arch/arm64/kvm/reset.c | 159 +++++++---
> arch/arm64/kvm/sys_regs.c | 152 +++++++++-
> include/uapi/linux/kvm.h | 1 +
> tools/testing/selftests/kvm/arm64/get-reg-list.c | 15 +-
> tools/testing/selftests/kvm/arm64/set_id_regs.c | 96 +++++-
> 33 files changed, 1554 insertions(+), 367 deletions(-)
> ---
> base-commit: 8cdeaa50eae8dad34885515f62559ee83e7e8dda
> change-id: 20230301-kvm-arm64-sme-06a1246d3636
>
> Best regards,
> --
> Mark Brown <broonie@kernel.org>
>
^ permalink raw reply
* Re: [PATCH v12 04/29] arm64/sve: Factor virtualizable VL discovery out of SVE specific code
From: Fuad Tabba @ 2026-07-12 14:12 UTC (permalink / raw)
To: Mark Brown
Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
Oliver Upton, Dave Martin, Mark Rutland, Ben Horgan,
Jean-Philippe Brucker, linux-arm-kernel, kvmarm, linux-kernel,
kvm, linux-doc, linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <20260709-kvm-arm64-sme-v12-4-d0301d79ef58@kernel.org>
Hi Mark,
On Thu, 9 Jul 2026 at 19:40, Mark Brown <broonie@kernel.org> wrote:
>
> In preparation for reuising it for SME pull the code for discovering the
> maximum virtualizable vector length out of sve_setup() into a separate
> function.
>
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
> arch/arm64/kernel/fpsimd.c | 41 ++++++++++++++++++++++++-----------------
> 1 file changed, 24 insertions(+), 17 deletions(-)
>
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index dc1ad10e39a2..5c156e2a47ea 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -1114,6 +1114,29 @@ int vec_verify_vq_map(enum vec_type type)
> return 0;
> }
>
> +static int vec_virtualisable_vl(struct vl_info *info)
> +{
> + DECLARE_BITMAP(partial_only_map, SVE_VQ_MAX);
> + unsigned long b_min_partial, b_max_virt;
> +
> + bitmap_andnot(partial_only_map, info->vq_partial_map, info->vq_map,
> + SVE_VQ_MAX);
> + b_min_partial = find_last_bit(partial_only_map, SVE_VQ_MAX);
> +
> + /* All implemented VLs are virtualisable */
> + if (b_min_partial >= SVE_VQ_MAX)
> + return info->max_vl;
> +
> + b_max_virt = find_next_bit(info->vq_map, SVE_VQ_MAX, b_min_partial);
> +
> + /* No implemented VLs are virtualisable */
> + if (b_max_virt >= SVE_VQ_MAX)
> + return 0;
nit: this is a reimplementation rather than a straight move, the
no-virtualisable case returns 0 (and drops the WARN_ON) where
sve_setup() returned SVE_VQ_MIN. No change for SVE (that case isn't
architecturally possible), and 0 is correct for the SME case this
helper now also serves. Might be worth a word in the changelog, since
"pull ... into a separate function" reads as pure code motion.
Reviewed-by: Fuad Tabba <fuad.tabba@linux.dev>
Cheers,
/fuad
> +
> + /* At least one virtualisable VL exists */
> + return sve_vl_from_vq(__bit_to_vq(b_max_virt));
> +}
> +
> void cpu_enable_sve(const struct arm64_cpu_capabilities *__always_unused p)
> {
> write_sysreg(read_sysreg(CPACR_EL1) | CPACR_EL1_ZEN_EL1EN, CPACR_EL1);
> @@ -1125,8 +1148,6 @@ void cpu_enable_sve(const struct arm64_cpu_capabilities *__always_unused p)
> void __init sve_setup(void)
> {
> struct vl_info *info = &vl_info[ARM64_VEC_SVE];
> - DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> - unsigned long b;
> int max_bit;
>
> if (!system_supports_sve())
> @@ -1149,21 +1170,7 @@ void __init sve_setup(void)
> */
> set_sve_default_vl(find_supported_vector_length(ARM64_VEC_SVE, 64));
>
> - bitmap_andnot(tmp_map, info->vq_partial_map, info->vq_map,
> - SVE_VQ_MAX);
> -
> - b = find_last_bit(tmp_map, SVE_VQ_MAX);
> - if (b >= SVE_VQ_MAX)
> - /* No non-virtualisable VLs found */
> - info->max_virtualisable_vl = SVE_VQ_MAX;
> - else if (WARN_ON(b == SVE_VQ_MAX - 1))
> - /* No virtualisable VLs? This is architecturally forbidden. */
> - info->max_virtualisable_vl = SVE_VQ_MIN;
> - else /* b + 1 < SVE_VQ_MAX */
> - info->max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b + 1));
> -
> - if (info->max_virtualisable_vl > info->max_vl)
> - info->max_virtualisable_vl = info->max_vl;
> + info->max_virtualisable_vl = vec_virtualisable_vl(info);
>
> pr_info("%s: maximum available vector length %u bytes per vector\n",
> info->name, info->max_vl);
>
> --
> 2.47.3
>
^ permalink raw reply
* Re: [Issue] maintainer-handbooks: html: list has duplicates
From: Mauro Carvalho Chehab @ 2026-07-12 14:39 UTC (permalink / raw)
To: Manuel Ebner; +Cc: corbet, linux-doc, linux-kernel, skhan, workflows
In-Reply-To: <20260712115900.481835-1-manuelebner@mailbox.org>
On Sun, 12 Jul 2026 13:58:59 +0200
Manuel Ebner <manuelebner@mailbox.org> wrote:
> There are only two patches which can cause that:
>
> commit 8eae6da5f56c ("docs: auto-generate maintainer entry profile links")
> commit bda185c30593 ("docs: maintainers_include: Only show main entry for profiles")
>
> Therefore adding Mauro to recipients.
That's weird: I'm pretty sure I tested it. Also, entries were supposed
to be sorted.
I'll work on a fixup patch. Thanks for reporting it!
Thanks,
Mauro
^ permalink raw reply
* Re: [PATCH v12 22/29] KVM: arm64: Context switch SME state for guests
From: Fuad Tabba @ 2026-07-12 14:40 UTC (permalink / raw)
To: Mark Brown
Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
Oliver Upton, Dave Martin, Mark Rutland, Ben Horgan,
Jean-Philippe Brucker, linux-arm-kernel, kvmarm, linux-kernel,
kvm, linux-doc, linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <20260709-kvm-arm64-sme-v12-22-d0301d79ef58@kernel.org>
Hi Mark,
On Thu, 9 Jul 2026 at 19:41, Mark Brown <broonie@kernel.org> wrote:
>
> If the guest has SME state we need to context switch that state, provide
> support for that for normal guests.
>
> SME has three sets of registers, ZA, ZT (only present for SME2) and also
> streaming SVE which replaces the standard floating point registers when
> active. The first two are fairly straightforward, they are accessible only
> when PSTATE.ZA is set and we can reuse the assembly from the host to save
> and load them from a single contiguous buffer. When PSTATE.ZA is not set
> then these registers are inaccessible, when the guest enables PSTATE.ZA
> all bits will be set to 0 by that and nothing is required on restore.
>
> Streaming mode is slightly more complicated, when enabled via PSTATE.SM it
> provides a version of the SVE registers using the SME vector length and may
> optionally omit the FFR register. SME may also be present without SVE. The
> register state is stored in sve_state as for non-streaming SVE mode, we
> make an initial selection of registers to update based on the guest SVE
> support and then override this when loading SVCR if streaming mode is
> enabled.
>
> A further complication is that when the hardware is in streaming mode
> guest operations that are invalid in in streaming mode will generate SME
> exceptions. There are also subfeature exceptions for SME2 controlled via
> SMCR which generate distinct exception codes. In many situations these
> exceptions are routed directly to the lower ELs with no opportunity for
> the hypervisor to intercept. So that guests do not see unexpected
> exception types due to the actual hardware configuration not being what
> the guest configured we update the SMCRs and SVCR even if the guest does
> not own the registers.
>
> Since in order to avoid duplication with SME we now restore the register
> state outside of the SVE specific restore function we need to move the
> restore of the effective VL for nested guests to a separate restore
> function run after loading the floating point register state, along with
> the similar handling required for SME.
>
> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
> arch/arm64/include/asm/fpsimd.h | 10 ++
> arch/arm64/include/asm/kvm_host.h | 25 +++--
> arch/arm64/kvm/fpsimd.c | 26 +++--
> arch/arm64/kvm/hyp/include/hyp/switch.h | 173 ++++++++++++++++++++++++++++++--
> arch/arm64/kvm/hyp/nvhe/hyp-main.c | 127 +++++++++++++++++++----
> 5 files changed, 319 insertions(+), 42 deletions(-)
>
> diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> index c3da16fdb158..9806b75e5e4c 100644
> --- a/arch/arm64/include/asm/fpsimd.h
> +++ b/arch/arm64/include/asm/fpsimd.h
> @@ -431,6 +431,15 @@ static inline void sve_user_enable(void)
> write_sysreg_s(__new, (reg)); \
> } while (0)
>
> +#define sme_cond_update_smcr_vq(val, reg) \
> + do { \
> + u64 __smcr = read_sysreg_s((reg)); \
> + u64 __new = __smcr & ~SMCR_ELx_LEN_MASK; \
> + __new |= (val) & SMCR_ELx_LEN_MASK; \
> + if (__smcr != __new) \
> + write_sysreg_s(__new, (reg)); \
> + } while (0)
> +
> /*
> * Probing and setup functions.
> * Calls to these functions must be serialised with one another.
> @@ -549,6 +558,7 @@ static inline void sve_user_disable(void) { BUILD_BUG(); }
> static inline void sve_user_enable(void) { BUILD_BUG(); }
>
> #define sve_cond_update_zcr_vq(val, reg) do { } while (0)
> +#define sme_cond_update_smcr_vq(val, reg) do { } while (0)
>
> static inline void vec_init_vq_map(enum vec_type t) { }
> static inline void vec_update_vq_map(enum vec_type t) { }
> diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
> index b78c039cb5ec..26ad8962b65d 100644
> --- a/arch/arm64/include/asm/kvm_host.h
> +++ b/arch/arm64/include/asm/kvm_host.h
> @@ -1126,6 +1126,9 @@ struct kvm_vcpu_arch {
> #define vcpu_sve_zcr_elx(vcpu) \
> (unlikely(is_hyp_ctxt(vcpu)) ? ZCR_EL2 : ZCR_EL1)
>
> +#define vcpu_sme_smcr_elx(vcpu) \
> + (unlikely(is_hyp_ctxt(vcpu)) ? SMCR_EL2 : SMCR_EL1)
> +
> #define sve_state_size_from_vl(sve_max_vl) ({ \
> size_t __size_ret; \
> unsigned int __vq; \
> @@ -1140,10 +1143,20 @@ struct kvm_vcpu_arch {
> __size_ret; \
> })
>
> -#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl(vcpu_sve_max_vl(vcpu))
> +#define vcpu_sve_state_size(vcpu) sve_state_size_from_vl(vcpu_max_vl(vcpu))
>
> #define vcpu_sme_state(vcpu) (kern_hyp_va((vcpu)->arch.sme_state))
>
> +/*
> + * Always provide space for ZT0 to avoid ordering requirements with ID
> + * register writes and vector finalization.
> + */
> +#define vcpu_sme_state_size(vcpu) ({ \
> + unsigned long __vl; \
> + __vl = (vcpu)->arch.max_vl[ARM64_VEC_SME]; \
> + sme_state_size_from_vl(__vl, system_supports_sme2()); \
> +})
> +
> #define sme_state_size_from_vl(vl, sme2) ({ \
> size_t __size_ret; \
> unsigned int __vq; \
> @@ -1160,16 +1173,6 @@ struct kvm_vcpu_arch {
> __size_ret; \
> })
>
> -/*
> - * Always provide space for ZT0 to avoid ordering requirements with ID
> - * register writes and vector finalization.
> - */
> -#define vcpu_sme_state_size(vcpu) ({ \
> - unsigned long __vl; \
> - __vl = (vcpu)->arch.max_vl[ARM64_VEC_SME]; \
> - sme_state_size_from_vl(__vl, system_supports_sme2()); \
> -})
> -
> #define KVM_GUESTDBG_VALID_MASK (KVM_GUESTDBG_ENABLE | \
> KVM_GUESTDBG_USE_SW_BP | \
> KVM_GUESTDBG_USE_HW | \
> diff --git a/arch/arm64/kvm/fpsimd.c b/arch/arm64/kvm/fpsimd.c
> index 567dd43970c5..bb0bf8d81522 100644
> --- a/arch/arm64/kvm/fpsimd.c
> +++ b/arch/arm64/kvm/fpsimd.c
> @@ -83,19 +83,24 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
> WARN_ON_ONCE(!irqs_disabled());
>
> if (guest_owns_fp_regs()) {
> - /*
> - * Currently we do not support SME guests so SVCR is
> - * always 0 and we just need a variable to point to.
> - */
> fp_state.st = &vcpu->arch.ctxt.fp_regs;
> fp_state.sve_state = vcpu->arch.sve_state;
> fp_state.zcr = vcpu_sve_max_vq(vcpu) - 1;
> - fp_state.smcr = 0;
> - fp_state.sme_state = NULL;
> + fp_state.smcr = vcpu_sme_max_vq(vcpu) - 1;
> + fp_state.sme_state = vcpu->arch.sme_state;
> fp_state.svcr = __ctxt_sys_reg(&vcpu->arch.ctxt, SVCR);
> fp_state.fpmr = __ctxt_sys_reg(&vcpu->arch.ctxt, FPMR);
> fp_state.fp_type = &vcpu->arch.fp_type;
>
> + if (kvm_has_fa64(vcpu->kvm))
> + fp_state.smcr |= SMCR_ELx_FA64;
> + if (kvm_has_sme2(vcpu->kvm))
> + fp_state.smcr |= SMCR_ELx_EZT0;
> +
> + /*
> + * For SME only guests fpsimd_save() will override the
> + * state selection if we are in streaming mode.
> + */
> if (vcpu_has_sve(vcpu))
> fp_state.to_save = FP_STATE_SVE;
> else
> @@ -104,6 +109,15 @@ void kvm_arch_vcpu_ctxsync_fp(struct kvm_vcpu *vcpu)
> fpsimd_bind_state_to_cpu(&fp_state);
>
> clear_thread_flag(TIF_FOREIGN_FPSTATE);
> + } else {
> + /*
> + * We might have enabled SME to configure traps but
> + * insist the host doesn't run the hypervisor with SME
> + * enabled, ensure it's disabled again.
> + */
> + if (system_supports_sme()) {
> + sme_smstop();
> + }
> }
> }
>
> diff --git a/arch/arm64/kvm/hyp/include/hyp/switch.h b/arch/arm64/kvm/hyp/include/hyp/switch.h
> index e444f0a94dcf..7c913da9babb 100644
> --- a/arch/arm64/kvm/hyp/include/hyp/switch.h
> +++ b/arch/arm64/kvm/hyp/include/hyp/switch.h
> @@ -462,6 +462,28 @@ static inline bool kvm_hyp_handle_mops(struct kvm_vcpu *vcpu, u64 *exit_code)
> return true;
> }
>
> +static inline void __hyp_sme_restore_guest(struct kvm_vcpu *vcpu,
> + bool *restore_sve,
> + bool *restore_ffr)
> +{
> + /*
> + * The vCPU's saved SVE state layout always matches the max VL of the
> + * vCPU. Start off with the max VL so we can load the SVE state.
> + */
> + sme_cond_update_smcr_vq(vcpu_sme_max_vq(vcpu) - 1, SYS_SMCR_EL2);
> +
> + if (vcpu_in_streaming_mode(vcpu)) {
> + *restore_sve = true;
> + *restore_ffr = vcpu_has_fa64(vcpu);
> + }
> +
> + if (vcpu_za_enabled(vcpu))
> + sme_load_state(kern_hyp_va(vcpu->arch.sme_state),
> + vcpu_has_sme2(vcpu));
> +
> + write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sme_smcr_elx(vcpu)), SYS_SMCR);
> +}
> +
> static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
> {
> u64 zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
> @@ -471,20 +493,34 @@ static inline void __hyp_sve_restore_guest(struct kvm_vcpu *vcpu)
> * vCPU. Start off with the max VL so we can load the SVE state.
> */
> sve_cond_update_zcr_vq(zcr_el2, SYS_ZCR_EL2);
> - sve_load_state(kern_hyp_va(vcpu->arch.sve_state), true);
> - fpsimd_load_common(&vcpu->arch.ctxt.fp_regs);
> + write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)), SYS_ZCR);
> +}
> +
> +static inline void __hyp_nv_restore_guest_vls(struct kvm_vcpu *vcpu)
> +{
> + if (!is_nested_ctxt(vcpu))
> + return;
>
> /*
> * The effective VL for a VM could differ from the max VL when running a
> * nested guest, as the guest hypervisor could select a smaller VL. Slap
> * that into hardware before wrapping up.
> */
> - if (is_nested_ctxt(vcpu)) {
> +
> + if (vcpu_has_sve(vcpu)) {
> + u64 zcr_el2 = vcpu_sve_max_vq(vcpu) - 1;
> +
> zcr_el2 = min(zcr_el2, __vcpu_sys_reg(vcpu, ZCR_EL2));
> sve_cond_update_zcr_vq(zcr_el2, SYS_ZCR_EL2);
> }
>
> - write_sysreg_el1(__vcpu_sys_reg(vcpu, vcpu_sve_zcr_elx(vcpu)), SYS_ZCR);
> + if (vcpu_has_sme(vcpu)) {
> + u64 max_len = vcpu_sme_max_vq(vcpu) - 1;
> + u64 smcr_len = SYS_FIELD_GET(SMCR_ELx, LEN,
> + __vcpu_sys_reg(vcpu, SMCR_EL2));
> +
> + sme_cond_update_smcr_vq(min(smcr_len, max_len), SYS_SMCR_EL2);
> + }
> }
>
> static inline void __hyp_sve_save_host(void)
> @@ -498,10 +534,48 @@ static inline void __hyp_sve_save_host(void)
> fpsimd_save_common(&hctxt->fp_regs);
> }
>
> +static inline void kvm_sme_configure_traps(struct kvm_vcpu *vcpu)
> +{
> + u64 smcr_el1, smcr_el2, guest_el2_len, svcr;
> +
> + if (!vcpu_has_sme(vcpu))
> + return;
> +
> + smcr_el2 = vcpu_sme_max_vq(vcpu) - 1;
> +
> + /* A guest hypervisor may restrict the effective max VL. */
> + if (is_nested_ctxt(vcpu)) {
> + guest_el2_len = SYS_FIELD_GET(SMCR_ELx, LEN,
> + __vcpu_sys_reg(vcpu, SMCR_EL2));
> + smcr_el2 = min(smcr_el2, guest_el2_len);
> + }
> +
> + if (vcpu_has_fa64(vcpu))
> + smcr_el2 |= SMCR_ELx_FA64;
> + if (vcpu_has_sme2(vcpu))
> + smcr_el2 |= SMCR_ELx_EZT0;
I ran Sashiko locally (my PR wasn't applied, so it still didn't run).
It flagged this:
For a nested guest this folds in the LEN restriction from the guest
hypervisor's SMCR_EL2 just above, but not FA64/EZT0. vcpu_has_fa64()
and vcpu_has_sme2() are VM-level capabilities (kvm_has_fa64/sme2 on
vcpu->kvm), so an L1 that clears SMCR_EL2.FA64 or .EZT0 to deny them to
L2 is overridden here: the physical SMCR_EL2 gets the bits set from the
VM cap regardless.
FA64 (IsFullA64Enabled()) and EZT0 (CheckSMEZT0Enabled()) are both
hierarchical AND-enables that gate EL1/EL0, so the effective SMCR_EL2
for L2 needs L1's SMCR_EL2.{FA64,EZT0} ANDed in, the same way LEN is
min()'d. Something like gating each OR on the guest's SMCR_EL2 bit when
is_nested_ctxt(vcpu).
> +
> + write_sysreg_el2(smcr_el2, SYS_SMCR);
> +
> + smcr_el1 = __vcpu_sys_reg(vcpu, vcpu_sme_smcr_elx(vcpu));
> + write_sysreg_el1(smcr_el1, SYS_SMCR);
> +
> + svcr = __vcpu_sys_reg(vcpu, SVCR);
> + write_sysreg_s(svcr, SYS_SVCR);
> +}
> +
> static inline void fpsimd_lazy_switch_to_guest(struct kvm_vcpu *vcpu)
> {
> u64 zcr_el1, zcr_el2;
>
> + /*
> + * We always load the SME control registers that affect traps
> + * since if they are not configured as expected by the guest
> + * then it may have exceptions that it does not expect
> + * directly delivered.
> + */
> + kvm_sme_configure_traps(vcpu);
> +
> if (!guest_owns_fp_regs())
> return;
>
> @@ -555,8 +629,57 @@ static inline void sve_lazy_switch_to_host(struct kvm_vcpu *vcpu)
> }
> }
>
> +static inline void sme_lazy_switch_to_host(struct kvm_vcpu *vcpu)
> +{
> + u64 smcr_el1, smcr_el2;
> +
> + if (!vcpu_has_sme(vcpu))
> + return;
> +
> + /*
> + * __deactivate_cptr_traps() disabled traps, but there hasn't
> + * necessarily been a context synchronization event yet.
> + */
> + isb();
> +
> + smcr_el1 = read_sysreg_el1(SYS_SMCR);
> + __vcpu_assign_sys_reg(vcpu, vcpu_sme_smcr_elx(vcpu), smcr_el1);
> +
> + smcr_el2 = 0;
> + if (system_supports_fa64())
> + smcr_el2 |= SMCR_ELx_FA64;
> + if (system_supports_sme2())
> + smcr_el2 |= SMCR_ELx_EZT0;
> +
> + /*
> + * The guest's state is always saved using the guest's max VL.
> + * Ensure that the host has the guest's max VL active such
> + * that the host can save the guest's state lazily, but don't
> + * artificially restrict the host to the guest's max VL.
> + */
> + if (has_vhe()) {
> + smcr_el2 |= vcpu_sme_max_vq(vcpu) - 1;
> + write_sysreg_el2(smcr_el2, SYS_SMCR);
> + } else {
> + smcr_el1 = smcr_el2;
> + smcr_el2 |= sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SME]) - 1;
> + write_sysreg_el2(smcr_el2, SYS_SMCR);
> +
> + smcr_el1 |= vcpu_sme_max_vq(vcpu) - 1;
> + write_sysreg_el1(smcr_el1, SYS_SMCR);
> + }
> +
> + __vcpu_assign_sys_reg(vcpu, SVCR, read_sysreg_s(SYS_SVCR));
> +}
> +
> static inline void fpsimd_lazy_switch_to_host(struct kvm_vcpu *vcpu)
> {
> + /*
> + * We always load the control registers for the guest so we
> + * always restore state for the host.
> + */
> + sme_lazy_switch_to_host(vcpu);
> +
> if (!guest_owns_fp_regs())
> return;
>
> @@ -567,6 +690,16 @@ static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu)
> {
> struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
>
> + /*
> + * The hypervisor refuses to run if streaming mode or ZA is
> + * enabled, we only need to save SMCR_EL1 for SME. For pKVM
> + * we will restore this, reset SMCR_EL2 to a fixed value and
> + * disable streaming mode and ZA to avoid any state being
> + * leaked.
> + */
> + if (system_supports_sme())
> + ctxt_sys_reg(hctxt, SMCR_EL1) = read_sysreg_el1(SYS_SMCR);
> +
> /*
> * Non-protected kvm relies on the host restoring its sve state.
> * Protected kvm restores the host's sve state as not to reveal that
> @@ -591,14 +724,17 @@ static void kvm_hyp_save_fpsimd_host(struct kvm_vcpu *vcpu)
> */
> static inline bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
> {
> - bool sve_guest;
> - u8 esr_ec;
> + bool restore_sve, restore_ffr;
> + bool sve_guest, sme_guest;
> + u8 esr_ec, esr_iss_smtc;
>
> if (!system_supports_fpsimd())
> return false;
>
> sve_guest = vcpu_has_sve(vcpu);
> + sme_guest = vcpu_has_sme(vcpu);
> esr_ec = kvm_vcpu_trap_get_class(vcpu);
> + esr_iss_smtc = ESR_ELx_SME_ISS_SMTC((kvm_vcpu_get_esr(vcpu)));
>
> /* Only handle traps the vCPU can support here: */
> switch (esr_ec) {
> @@ -617,6 +753,15 @@ static inline bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
> if (guest_hyp_sve_traps_enabled(vcpu))
> return false;
> break;
> + case ESR_ELx_EC_SME:
> + if (!sme_guest)
> + return false;
> + if (guest_hyp_sme_traps_enabled(vcpu))
> + return false;
> + if (!kvm_has_sme2(kern_hyp_va(vcpu->kvm)) &&
> + (esr_iss_smtc == ESR_ELx_SME_ISS_SMTC_ZT_DISABLED))
> + return false;
> + break;
> default:
> return false;
> }
> @@ -632,10 +777,22 @@ static inline bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
> kvm_hyp_save_fpsimd_host(vcpu);
>
> /* Restore the guest state */
> +
> + /* These may be overridden for a SME guest */
> + restore_sve = sve_guest;
> + restore_ffr = sve_guest;
> +
> if (sve_guest)
> __hyp_sve_restore_guest(vcpu);
> - else
> + if (sme_guest)
> + __hyp_sme_restore_guest(vcpu, &restore_sve, &restore_ffr);
> +
> + if (restore_sve) {
> + sve_load_state(kern_hyp_va(vcpu->arch.sve_state), restore_ffr);
> + fpsimd_load_common(&vcpu->arch.ctxt.fp_regs);
> + } else {
> fpsimd_load_state(&vcpu->arch.ctxt.fp_regs);
> + }
>
> if (kvm_has_fpmr(kern_hyp_va(vcpu->kvm)))
> write_sysreg_s(__vcpu_sys_reg(vcpu, FPMR), SYS_FPMR);
> @@ -644,6 +801,8 @@ static inline bool kvm_hyp_handle_fpsimd(struct kvm_vcpu *vcpu, u64 *exit_code)
> if (!(read_sysreg(hcr_el2) & HCR_RW))
> write_sysreg(__vcpu_sys_reg(vcpu, FPEXC32_EL2), fpexc32_el2);
>
> + __hyp_nv_restore_guest_vls(vcpu);
> +
> *host_data_ptr(fp_owner) = FP_STATE_GUEST_OWNED;
>
> /*
> diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> index 14e24e257dcc..0f6e3479a7e4 100644
> --- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> +++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
> @@ -31,16 +31,28 @@ void __kvm_hyp_host_forward_smc(struct kvm_cpu_context *host_ctxt);
>
> static void __hyp_sve_save_guest(struct kvm_vcpu *vcpu)
> {
> - __vcpu_assign_sys_reg(vcpu, ZCR_EL1, read_sysreg_el1(SYS_ZCR));
> - /*
> - * On saving/restoring guest sve state, always use the maximum VL for
> - * the guest. The layout of the data when saving the sve state depends
> - * on the VL, so use a consistent (i.e., the maximum) guest VL.
> - */
> - sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
> - sve_save_state(kern_hyp_va(vcpu->arch.sve_state), true);
> + bool save_ffr = !vcpu_in_streaming_mode(vcpu) || vcpu_has_fa64(vcpu);
> +
> + if (vcpu_has_sve(vcpu)) {
> + __vcpu_assign_sys_reg(vcpu, ZCR_EL1, read_sysreg_el1(SYS_ZCR));
> +
> + /*
> + * On saving/restoring guest sve state, always use the
> + * maximum VL for the guest. The layout of the data
> + * when saving the sve state depends on the VL, so use
> + * a consistent (i.e., the maximum) guest VL.
> + */
> + sve_cond_update_zcr_vq(vcpu_sve_max_vq(vcpu) - 1, SYS_ZCR_EL2);
> + }
> +
> + /* Ensure ZCR/SMCR updates for VL are seen */
> + isb();
> + sve_save_state(kern_hyp_va(vcpu->arch.sve_state), save_ffr);
> fpsimd_save_common(&vcpu->arch.ctxt.fp_regs);
> - write_sysreg_s(sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SVE]) - 1, SYS_ZCR_EL2);
> +
> + if (system_supports_sve())
> + write_sysreg_s(sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SVE]) - 1,
> + SYS_ZCR_EL2);
> }
>
> static void __hyp_sve_restore_host(void)
> @@ -63,9 +75,76 @@ static void __hyp_sve_restore_host(void)
> write_sysreg_el1(ctxt_sys_reg(hctxt, ZCR_EL1), SYS_ZCR);
> }
>
> -static void fpsimd_sve_flush(void)
> +static void __hyp_sme_save_guest(struct kvm_vcpu *vcpu)
> {
> - *host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
> + unsigned long smcr_el2;
> +
> + __vcpu_assign_sys_reg(vcpu, SMCR_EL1, read_sysreg_el1(SYS_SMCR));
> + __vcpu_assign_sys_reg(vcpu, SVCR, read_sysreg_s(SYS_SVCR));
> +
> + /*
> + * On saving/restoring guest sve state, always use the maximum VL for
> + * the guest. The layout of the data when saving the sve state depends
> + * on the VL, so use a consistent (i.e., the maximum) guest VL.
> + *
> + * We restore the FA64 and SME2 enables for the host since we
> + * will always restore the host configuration so if host and
> + * guest VLs are the same we might suppress an update.
> + */
> + smcr_el2 = vcpu_sme_max_vq(vcpu) - 1;
> + if (system_supports_fa64())
> + smcr_el2 |= SMCR_ELx_FA64;
> + if (system_supports_sme2())
> + smcr_el2 |= SMCR_ELx_EZT0;
> + sysreg_cond_update_s(SYS_SMCR_EL2, smcr_el2);
> +
> + if (vcpu_za_enabled(vcpu)) {
> + isb();
> + sme_save_state(vcpu_sme_state(vcpu), vcpu_has_sme2(vcpu));
> + }
> +}
> +
> +static void __hyp_sme_restore_host(void)
> +{
> + struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
> + u64 smcr_el2;
> +
> + /*
> + * The hypervisor refuses to run if we are in streaming mode
> + * or have ZA enabled so there is no SME specific state to
> + * restore other than the system registers.
> + *
> + * Note that this constrains the PE to the maximum shared VL
> + * that was discovered, if we wish to use larger VLs this will
> + * need to be revisited.
> + */
> + smcr_el2 = sve_vq_from_vl(kvm_host_max_vl[ARM64_VEC_SME]) - 1;
> + if (system_supports_fa64())
> + smcr_el2 |= SMCR_ELx_FA64;
> + if (system_supports_sme2())
> + smcr_el2 |= SMCR_ELx_EZT0;
> + sysreg_cond_update_s(SYS_SMCR_EL2, smcr_el2);
> +
> + write_sysreg_el1(ctxt_sys_reg(hctxt, SMCR_EL1), SYS_SMCR);
> + sme_smstop();
> +}
> +
> +static void fpsimd_sve_flush(struct kvm_vcpu *vcpu)
> +{
> + /*
> + * If the guest has SME then we need to restore the trap
> + * controls in SMCR and mode in SVCR in order to ensure that
> + * traps generated directly to EL1 have the correct types,
> + * otherwise we can defer until we load the guest state.
> + */
> + if (vcpu_has_sme(vcpu)) {
> + kvm_hyp_save_fpsimd_host(vcpu);
> + kvm_sme_configure_traps(vcpu);
> +
> + *host_data_ptr(fp_owner) = FP_STATE_FREE;
> + } else {
> + *host_data_ptr(fp_owner) = FP_STATE_HOST_OWNED;
> + }
> }
>
> static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
> @@ -73,8 +152,15 @@ static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
> struct kvm_cpu_context *hctxt = host_data_ptr(host_ctxt);
> bool has_fpmr;
>
> - if (!guest_owns_fp_regs())
> + if (!guest_owns_fp_regs()) {
> + /*
> + * We always at least partially configure SME for the
> + * guest due to traps.
> + */
> + if (system_supports_sme())
> + __hyp_sme_restore_host();
> return;
> + }
>
> /*
> * Traps have been disabled by __deactivate_cptr_traps(), but there
> @@ -82,7 +168,10 @@ static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
> */
> isb();
>
> - if (vcpu_has_sve(vcpu))
> + if (vcpu_has_sme(vcpu))
> + __hyp_sme_save_guest(vcpu);
> +
> + if (vcpu_has_sve(vcpu) || vcpu_in_streaming_mode(vcpu))
> __hyp_sve_save_guest(vcpu);
> else
> fpsimd_save_state(&vcpu->arch.ctxt.fp_regs);
> @@ -91,6 +180,9 @@ static void fpsimd_sve_sync(struct kvm_vcpu *vcpu)
> if (has_fpmr)
> __vcpu_assign_sys_reg(vcpu, FPMR, read_sysreg_s(SYS_FPMR));
>
> + if (system_supports_sme())
> + __hyp_sme_restore_host();
> +
> if (system_supports_sve())
> __hyp_sve_restore_host();
> else
> @@ -128,7 +220,7 @@ static void flush_hyp_vcpu(struct pkvm_hyp_vcpu *hyp_vcpu)
> {
> struct kvm_vcpu *host_vcpu = hyp_vcpu->host_vcpu;
>
> - fpsimd_sve_flush();
> + fpsimd_sve_flush(host_vcpu);
sync_hyp_vcpu() runs fpsimd_sve_sync() on &hyp_vcpu->vcpu, but flush
passes host_vcpu, so the two sides operate on different vCPUs. That
asymmetry alone looks wrong: flush and sync should cover the same
state.
Concretely it means kvm_sme_configure_traps() programs a protected
guest's SVCR/SMCR from host-owned values, so the host can e.g. set
SVCR.SM and fault the guest. Keying flush off &hyp_vcpu->vcpu like
sync fixes both.
Cheers,
/fuad
> flush_debug_state(hyp_vcpu);
>
> hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt;
> @@ -223,10 +315,9 @@ static void handle___kvm_vcpu_run(struct kvm_cpu_context *host_ctxt)
> struct pkvm_hyp_vcpu *hyp_vcpu = pkvm_get_loaded_hyp_vcpu();
>
> /*
> - * KVM (and pKVM) doesn't support SME guests for now, and
> - * ensures that SME features aren't enabled in pstate when
> - * loading a vcpu. Therefore, if SME features enabled the host
> - * is misbehaving.
> + * KVM (and pKVM) refuses to run if PSTATE.{SM,ZA} are
> + * enabled. Therefore, if SME features enabled the
> + * host is misbehaving.
> */
> if (unlikely(system_supports_sme() && read_sysreg_s(SYS_SVCR))) {
> ret = -EINVAL;
>
> --
> 2.47.3
>
^ permalink raw reply
* [PATCH 2/2] docs: maintainers_include.py: output subsystem name if available
From: Mauro Carvalho Chehab @ 2026-07-12 14:59 UTC (permalink / raw)
To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
Cc: Mauro Carvalho Chehab, linux-kernel, Shuah Khan, Manuel Ebner
In-Reply-To: <cover.1783868309.git.mchehab+huawei@kernel.org>
If the subsystem name is available (which should always be true,
except if the parser has an issue), outputs the subsystem's name
at the profile entry.
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/sphinx/maintainers_include.py | 2 ++
1 file changed, 2 insertions(+)
diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index 7df73f66e13c..1596630a74ca 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -345,6 +345,8 @@ class MaintainersProfile(Include):
elif entry.startswith("`"):
new_entry = f"- {name}: {entry}\n"
self.warning(f"{profile}: Invalid 'P' tag: {entry}\n")
+ elif name:
+ new_entry = f"- {name}: {entry}\n"
else:
new_entry = f"- {entry}\n"
--
2.55.0
^ permalink raw reply related
* [PATCH 1/2] docs: maintainers_include: don't output duplicated profile entries
From: Mauro Carvalho Chehab @ 2026-07-12 14:59 UTC (permalink / raw)
To: Jonathan Corbet, Linux Doc Mailing List, Mauro Carvalho Chehab
Cc: Mauro Carvalho Chehab, linux-kernel, Shuah Khan, Manuel Ebner
In-Reply-To: <cover.1783868309.git.mchehab+huawei@kernel.org>
Add a logic to prevent having duplicated maintainer's profile entries
at the rst output.
Reported-by: Manuel Ebner <manuelebner@mailbox.org>
Closes: https://lore.kernel.org/linux-doc/98a558a87a07ab641f47c66c372ee7ed0735f4f5.camel@mailbox.org/
Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>
---
Documentation/sphinx/maintainers_include.py | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/Documentation/sphinx/maintainers_include.py b/Documentation/sphinx/maintainers_include.py
index dc9f9e188ffa..7df73f66e13c 100755
--- a/Documentation/sphinx/maintainers_include.py
+++ b/Documentation/sphinx/maintainers_include.py
@@ -336,16 +336,24 @@ class MaintainersProfile(Include):
# Produce a list with all maintainer profiles, sorted by subsystem name
#
output = ""
- for profile, entry in sorted(maint_parser.profile_entries.items()):
+ entries = set()
+ for profile, entry in maint_parser.profile_entries.items():
name = profile.title()
if entry.startswith("http"):
- output += f"- `{name} <{entry}>`_\n"
+ new_entry = f"- `{name} <{entry}>`_\n"
elif entry.startswith("`"):
- output += f"- {name}: {entry}\n"
+ new_entry = f"- {name}: {entry}\n"
self.warning(f"{profile}: Invalid 'P' tag: {entry}\n")
else:
- output += f"- {entry}\n"
+ new_entry = f"- {entry}\n"
+
+ if new_entry not in entries:
+ entries.add(new_entry)
+
+ for entry in sorted(entries):
+ output += entry
+
#
# Create a hidden TOC table with all profiles. That allows adding
--
2.55.0
^ permalink raw reply related
* [PATCH 0/2] A couple of fixes for maintainers_include.py
From: Mauro Carvalho Chehab @ 2026-07-12 14:59 UTC (permalink / raw)
To: Jonathan Corbet, Mauro Carvalho Chehab
Cc: Mauro Carvalho Chehab, linux-doc, linux-kernel, Shuah Khan,
Manuel Ebner
Hi Jon,
It follows a couple fixes for maintainers_include when generating
maintainer's profile entries.
Regards,
Mauro
Mauro Carvalho Chehab (2):
docs: maintainers_include: don't output duplicated profile entries
docs: maintainers_include.py: output subsystem name if available
Documentation/sphinx/maintainers_include.py | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)
--
2.55.0
^ permalink raw reply
* Re: [PATCH 1/6] dt-bindings: iio: adc: Add AD7768
From: David Lechner @ 2026-07-12 16:07 UTC (permalink / raw)
To: Jonathan Cameron
Cc: Janani Sunil, Nuno Sá, Michael Hennerich, Andy Shevchenko,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, Olivier Moysan,
Philipp Zabel, Linus Walleij, Bartosz Golaszewski,
Jonathan Corbet, Shuah Khan, linux, linux-iio, devicetree,
linux-kernel, linux-gpio, linux-doc, jananisunil.dev
In-Reply-To: <20260712023918.119fbecd@jic23-huawei>
On 7/11/26 8:39 PM, Jonathan Cameron wrote:
> On Sat, 11 Jul 2026 09:40:32 -0500
> David Lechner <dlechner@baylibre.com> wrote:
>
>> On 7/9/26 7:33 PM, Jonathan Cameron wrote:
>>>>> + adi,common-mode-output:
>>>>> + $ref: /schemas/types.yaml#/definitions/string
>>>>> + enum:
>>>>> + - avdd-avss-half
>>>>> + - 1.65V
>>>>> + - 2.5V
>>>>> + - 2.14V
>>>>> + description:
>>>>> + Common mode voltage output selection.
>>>>
>>>> Why not using standard regulator provider bindings for this?
>>>
>>> Interesting question. If that was done there would need to be
>>> a consumer which means explicit modelling of any analog circuit.
>>> We do that in a few cases but so far (and yup this is a driver thing
>>> in a dt-binding) I don't think we have any way to consumer data when
>>> a backend is involved.
>>
>> There is also the regulator-always-on property, so strictly speaking,
>> a consumer is not required.
>
> Makes some sense I guess.
>
> How would the voltage be controlled? Set min and max to same value?
yes
>
> J
>>
>>>
>>>>
>>>>> +
>>>>> + adi,vcm-power-down:
>>>>> + type: boolean
>>>>> + description: Power down the common mode output buffer
>>>>
>>>> Is the buffer separate from the output? In that case I would expect
>>>> buffer to be in the property name, otherwise this should just be
>>>> part of the enum options above (and the default one at that).
>>>>
>>
>
^ permalink raw reply
* Re: [PATCH v4 5/8] riscv_cbqri: resctrl: Add cache allocation via capacity block mask
From: Drew Fustini @ 2026-07-12 19:15 UTC (permalink / raw)
To: Reinette Chatre
Cc: Adrien Ricciardi, Alexandre Ghiti, Atish Kumar Patra, Atish Patra,
Babu Moger, Ben Horgan, Borislav Petkov, Chen Pei, Conor Dooley,
Conor Dooley, Dave Hansen, Dave Martin, Fenghua Yu, Gong Shuai,
Gong Shuai, guo.wenjia23, James Morse, Kornel Dulęba,
Krzysztof Kozlowski, liu.qingtao2, Liu Zhiwei, Palmer Dabbelt,
Paul Walmsley, Peter Newman, Radim Krčmář,
Rob Herring, Samuel Holland, Sebastian Andrzej Siewior, Tony Luck,
Vasudevan Srinivasan, Ved Shanbhogue, Weiwei Li, yunhui cui,
linux-kernel, linux-riscv, x86, devicetree, linux-rt-devel,
linux-doc
In-Reply-To: <3e7070fa-16f3-453e-9f0e-9c1a2ef38f9f@intel.com>
On Tue, Jul 07, 2026 at 11:17:14AM -0700, Reinette Chatre wrote:
> Hi Drew,
Thanks for reviewing and your suggestions.
> On 7/6/26 4:06 PM, Drew Fustini wrote:
>
> ...
>
> > diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
> > new file mode 100644
> > index 000000000000..cb12a868561b
> > --- /dev/null
> > +++ b/drivers/resctrl/cbqri_resctrl.c
>
> ...
>
> > +
> > +/*
> > + * fs/resctrl unconditionally references the symbols below before checking
> > + * mon_capable. They are stubs for features CBQRI does not yet support.
> > + */
>
> resctrl should not access monitoring related arch functions if the arch
> does not support monitoring. Could you please highlight which ones are causing
> problems? From what I can tell, the first one below, resctrl_arch_is_evt_configurable(),
> is indeed only called via resctrl_l3_mon_resource_init() if the L3 resource is
> mon_capable.
You are right, none of the monitoring stubs run for the allocation-only
CBQRI implementation in this series. The stubs exist only so fs/resctrl
resolves the symbols at link time. I'll drop the comment.
> > +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)
>
> Similarly, this should only be called when reading monitoring data which should only be
> possible if the resource is capable of monitoring.
Agreed, same as above.
> > +/*
> > + * 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 level whose controllers disagree
> > + * is dropped, since resctrl exposes a single set of caps per rid, but the
> > + * other level is still picked. The first matching controller wins.
> > + */
>
> It works but I find it to be a potentially confusing approach (just a personal opinion!).
Good point. I'll restructure it to pick per cache level instead of per
controller, which removes the separate dropped[] array and the
overloaded NULL that made it confusing.
> > +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;
>
> Please also initialize domain->hdr.rid that is referenced by the often-used
> domain_header_is_valid() helper.
Okay, I will set 'domain->hdr.rid = res->rid'.
> > +
> > + 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);
>
> The domain list became an RCU list when resctrl started supporting MPAM.
> commit fb700810d30b ("x86/resctrl: Separate arch and fs resctrl locks") contains
> a great description of the motivation and the different accesses that the list
> should support. Historically resctrl always accessed the list with CPU hotplug lock
> held for which above is ok but there are some planned changes as part of a fix
> that accesses the list via an RCU read-side critical section. Even with this addition
> there is no immediate impact to this enabling since it is related to the
> MBA software controller but I think it is best for archs and resctrl to agree on
> how the domain list can be accessed safely.
>
> For reference to the upcoming resctrl usage see
> https://lore.kernel.org/lkml/4c88e01e29df638d9ecad71b2ee3b411e24067bd.1783377598.git.reinette.chatre@intel.com/
>
> > +
> > + resctrl_online_ctrl_domain(res, domain);
>
> With the transition to RCU list the domain should only be added to the list after it is
> fully initialized.
Thanks for the explanation. I will adopt the RCU list convention. Fully
initialize the domain, online it, and then publish it.
> > +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);
>
> (also related to switch to RCU list, remove domain from list before
> starting to offline it)
Will do, thanks.
> > + kfree(container_of(domain, struct cbqri_resctrl_dom,
> > + resctrl_ctrl_dom));
> > + }
> > + }
> > +}
>
> How CPUs are associated with control domains are not clear to me. Above appears to
> be consequence of how platform driver initializes so I will comment more there (patch #8).
> Just for above, it is unexpected that a CPU needs to be tested against cpu_mask
> of all control domains. Would a direct query that uses the CPU's cache ID not be
> quicker? Also, above creates impression that a CPU may belong to multiple control
> domains which should not happen.
Thanks for the suggestion. I will change it to lookup the domain up directly by
the cache id.
> > +/*
> > + * 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);
> > +
> > + /*
> > + * Hold cbqri_controllers_lock across the walk so a controller
> > + * registered after boot cannot corrupt it. The register path takes
> > + * it as a leaf and never cbqri_domain_list_lock, so this nesting
> > + * cannot invert.
> > + */
> > + guard(mutex)(&cbqri_controllers_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;
>
> What will happen if @cpu was offline when cbqri_capacity_probe() ran? From what
> I can tell @cpu will not be in ctrl->cache.cpu_mask in this scenario?
Yes, this is a problem. I will drop the probe-time cpu_mask and associate cpus
with domains the way you suggest, from the cpu's own cache id at hotplug time.
Thanks,
Drew
^ permalink raw reply
* [PATCH v2 0/1] fixes for maintainers_include
From: Mauro Carvalho Chehab @ 2026-07-12 19:33 UTC (permalink / raw)
To: Jonathan Corbet, Mauro Carvalho Chehab
Cc: Mauro Carvalho Chehab, linux-doc, linux-kernel, Shuah Khan,
Manuel Ebner
Hi Jon,
This v2 replaces v1 series:
[PATCH 0/2] A couple of fixes for maintainers_include.py
It basically fixes an issue reported by Manuel that entries
are printed duplicated.
In reality, the output maintainer entries are not properly
named per subsystem, so they appear to be duplicated.
Fixing the name output solves the issue and keeps the list
alphabetically sorted, as expected.
Mauro Carvalho Chehab (1):
docs: maintainers_include: fix entry names
Documentation/sphinx/maintainers_include.py | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
--
2.55.0
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox