Linux Documentation
 help / color / mirror / Atom feed
* Re: [PATCH v2] docs: pt_BR: translate process/license-rules.rst
From: Jonathan Corbet @ 2026-05-15 14:24 UTC (permalink / raw)
  To: Daniel Pereira; +Cc: linux-doc, Daniel Pereira
In-Reply-To: <20260503160352.160135-1-danielmaraboo@gmail.com>

Daniel Pereira <danielmaraboo@gmail.com> writes:

> Translate the license-rules.rst document into Brazilian Portuguese.
> This document provides guidelines on how licenses should be identified
> and handled within the kernel source code.
>
> Additionally, update the pt_BR/process/index.rst to include the new
> translation in the documentation tree.
>
> Signed-off-by: Daniel Pereira <danielmaraboo@gmail.com>
>
> ---
> v2:
>   - Fixed docutils warning: "Line block ends without a blank line" on line 72.
>   - Removed stray '|' character from the translation file to fix the build.
> ---
>  Documentation/translations/pt_BR/index.rst    |   1 +
>  .../pt_BR/process/license-rules.rst           | 483 ++++++++++++++++++
>  2 files changed, 484 insertions(+)
>  create mode 100644 Documentation/translations/pt_BR/process/license-rules.rst

Applied, thanks.

jon

^ permalink raw reply

* Re: [PATCH] docs: pt_BR: update minimal software requirements in changes.rst
From: Jonathan Corbet @ 2026-05-15 14:21 UTC (permalink / raw)
  To: Daniel Pereira; +Cc: linux-doc, Daniel Pereira
In-Reply-To: <20260505194143.32009-1-danielmaraboo@gmail.com>

Daniel Pereira <danielmaraboo@gmail.com> writes:

> Update the Brazilian Portuguese translation of changes.rst to align with
> the latest English version.
>
> Key changes include:
> - Updated minimum versions for Rust (1.85.0), bindgen (0.71.1), and
>   pahole (1.22).
> - Fixed ReST syntax for internal references (:ref:) and external links.
> - Corrected formatting for tool names and config options using inline
>   code backticks.
> - Synchronized technical descriptions for udev, kmod, and NFS-utils.
>
> Signed-off-by: Daniel Pereira <danielmaraboo@gmail.com>
> ---
>  .../translations/pt_BR/process/changes.rst    | 52 +++++++++----------
>  1 file changed, 26 insertions(+), 26 deletions(-)

This doesn't build...?

> Documentation/translations/pt_BR/process/changes.rst:37:
> ERROR: Malformed table.  Text in column margin in table line 7.
> 
> ====================== ===============
>         ======================================== Programa Versão mínima
>         Comando para verificar a versão ======================
>         =============== ======================================== GNU C 8.1
>         gcc --version Clang/LLVM (optional) 15.0.0 clang --version Rust
>         (optional) 1.85.0 rustc --version bindgen (optional) 0.71.1 bindgen
>         --version GNU make 4.0 make --version bash 4.2 bash --version
>         binutils 2.30 ld -v flex 2.5.35 flex --version gdb 7.2 gdb
>         --version bison 2.0 bison --version pahole 1.22 pahole --version
>         util-linux 2.10o mount --version kmod 13 kmod -V e2fsprogs 1.41.4
>         e2fsck -V jfsutils 1.1.3 fsck.jfs -V xfsprogs 2.6.0 xfs_db -V
>         squashfs-tools 4.0 mksquashfs -version btrfs-progs 0.18 btrfs
>         --version pcmciautils 004 pccardctl -V quota-tools 3.09 quota -V
>         PPP 2.4.0 pppd --version nfs-utils 1.0.5 showmount --version procps
>         3.2.0 ps --version udev 081 udevadm --version grub 0.93 grub
>         --version || grub-install --version mcelog 0.6 mcelog --version
>         iptables 1.4.2 iptables -V openssl & libcrypto 1.0.0 openssl
>         version bc 1.06.95 bc --version Sphinx\ [#f1]_ 3.4.3 sphinx-build
>         --version GNU tar 1.28 tar --version gtags (opcional) 6.6.5 gtags
>         --version mkimage (opcional) 2017.01 mkimage --version Python 3.9.x
>         python3 --version GNU AWK (opcional) 5.1.0 gawk --version
>         ====================== ===============
>         ======================================== [docutils]
>         /stuff/k/git/kernel/Documentation/translations/pt_BR/process/changes.rst:71:
>         WARNING: Footnote [#] is not referenced. [ref.footnote]
> 

jon

^ permalink raw reply

* Re: [PATCH] kdoc: xforms: move context attrs to function_xforms list
From: Jonathan Corbet @ 2026-05-15 14:20 UTC (permalink / raw)
  To: Randy Dunlap, linux-kernel
  Cc: Randy Dunlap, Shuah Khan, linux-doc, Mauro Carvalho Chehab
In-Reply-To: <20260505221548.163751-1-rdunlap@infradead.org>

Randy Dunlap <rdunlap@infradead.org> writes:

> The context analysis macros are function attributes that should be
> in the function_xforms list. Somewhere along the way they were
> inserted into the struct_xforms list instead. This causes docs build
> warnings to continue to be emitted for context macros.
>
> Move the context analysis macros to the function_xforms list where
> they should be to eliminate these warnings.
>
> Documentation/core-api/kref:328: ../include/linux/kref.h:72: WARNING: Invalid C declaration: Expected end of definition. [error at 96]
>   int kref_put_mutex (struct kref *kref, void (*release)(struct kref *kref), struct mutex *mutex) __cond_acquires(true# mutex)
> Documentation/core-api/kref:328: ../include/linux/kref.h:94: WARNING: Invalid C declaration: Expected end of definition. [error at 92]
>   int kref_put_lock (struct kref *kref, void (*release)(struct kref *kref), spinlock_t *lock) __cond_acquires(true# lock)
>
> Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
> ---
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Shuah Khan <skhan@linuxfoundation.org>
> Cc: linux-doc@vger.kernel.org
> Cc: Mauro Carvalho Chehab <mchehab@kernel.org>
>
>  tools/lib/python/kdoc/xforms_lists.py |   20 ++++++++++----------
>  1 file changed, 10 insertions(+), 10 deletions(-)

Applied, thanks.

jon

^ permalink raw reply

* Re: [PATCH] docs: kernel-doc: python: strip __counted_by_ptr macro
From: Jonathan Corbet @ 2026-05-15 14:15 UTC (permalink / raw)
  To: Tudor Ambarus, Mauro Carvalho Chehab, Kees Cook,
	Gustavo A. R. Silva
  Cc: linux-kernel, linux-doc, linux-hardening, peter.griffin,
	andre.draszik, willmcvicker, jyescas, krzk, kernel-team,
	Tudor Ambarus
In-Reply-To: <20260506-kdoc-__counted_by_ptr-v1-1-70763486871f@linaro.org>

Tudor Ambarus <tudor.ambarus@linaro.org> writes:

> The `__counted_by_ptr` macro was recently introduced [1] to extend
> bounds checking semantics to standard dynamically allocated pointers.
>
> However, the new Python implementation of kernel-doc does not currently
> recognize it as a compiler attribute. When kernel-doc encounters a
> struct member annotated with this macro, it fails to parse the variable
> name correctly, resulting in false-positive warnings like:
>
>   Warning: ... struct member '__counted_by_ptr(cmdcnt' not described
>
> Add `__counted_by_ptr` to the `struct_xforms` regex list so it gets
> safely stripped out during the parsing phase, mirroring the existing
> behavior for `__counted_by`. Update the corresponding unit tests.
>
> Link: https://git.kernel.org/torvalds/c/150a04d817d8 [1]
> Signed-off-by: Tudor Ambarus <tudor.ambarus@linaro.org>
> ---
>  tools/lib/python/kdoc/xforms_lists.py | 1 +
>  tools/unittests/test_cmatch.py        | 1 +
>  2 files changed, 2 insertions(+)

Applied, thanks.

jon

^ permalink raw reply

* Re: [PATCH v13 2/4] kunit: Add backtrace suppression self-tests
From: Albert Esteve @ 2026-05-15 14:14 UTC (permalink / raw)
  To: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
	workflows, linux-riscv, linux-doc, peterz, Guenter Roeck,
	Linux Kernel Functional Testing, Alessandro Carminati,
	Dan Carpenter, Kees Cook
In-Reply-To: <20260515-kunit_add_support-v13-2-18ee42f96e7b@redhat.com>

On Fri, May 15, 2026 at 2:30 PM Albert Esteve <aesteve@redhat.com> wrote:
>
> From: Guenter Roeck <linux@roeck-us.net>
>
> Add unit tests to verify that warning backtrace suppression works.
>
> Tests cover both API forms:
> - Scoped: kunit_warning_suppress() with in-block count verification
>   and post-block inactivity check.
> - Direct functions: kunit_start/end_suppress_warning() with
>   sequential independent suppression blocks and per-block counts.
>
> Furthermore, tests verify incremental warning counting, that
> kunit_has_active_suppress_warning() transitions correctly around
> suppression boundaries, and that suppression active in the test
> kthread does not leak to a separate kthread.
>
> If backtrace suppression does _not_ work, the unit tests will likely
> trigger unsuppressed backtraces, which should actually help to get
> the affected architectures / platforms fixed.
>

Another set of sashiko comments for this patch
https://sashiko.dev/#/patchset/20260515-kunit_add_support-v13-0-18ee42f96e7b%40redhat.com?part=2
here:

1. CPU spike from while (!kthread_should_stop()) schedule()
Ha! I expected this one because I saw it in a previous review from the
bot. schedule() from TASK_RUNNING yields the CPU; it does not
spin-wait. The thread is rescheduled only when the scheduler gives it
time, not in a tight loop. But the important thing is that the window
where this loop actually runs is negligible: the parent calls
kthread_stop() immediately after wait_for_completion() returns. Using
set_current_state(TASK_INTERRUPTIBLE) would be slightly more
CPU-friendly, but for a test that probably runs and exits in
microseconds, it makes no practical difference. And it unnecessarily
adds complexity.

2. Orphaned kthread on early abort
This cannot happen in this test. The only KUNIT_ASSERT_* that could
abort early is KUNIT_ASSERT_FALSE(test, IS_ERR(task)). If that
assertion fails, it means kthread_run() itself returned an error,
therefore, the kthread was never started and there is nothing to
orphan. If kthread_run() succeeds, the assertion passes, and execution
continues sequentially to kthread_stop(). No code path allows a live
kthread to exist while bypassing kthread_stop().

> Tested-by: Linux Kernel Functional Testing <lkft@linaro.org>
> Acked-by: Dan Carpenter <dan.carpenter@linaro.org>
> Reviewed-by: Kees Cook <keescook@chromium.org>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
> Reviewed-by: David Gow <david@davidgow.net>
> Signed-off-by: Albert Esteve <aesteve@redhat.com>
> ---
>  lib/kunit/Makefile                     |   1 +
>  lib/kunit/backtrace-suppression-test.c | 192 +++++++++++++++++++++++++++++++++
>  2 files changed, 193 insertions(+)
>
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 4592f9d0aa8dd..2e8a6b71a2ab0 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -22,6 +22,7 @@ obj-$(if $(CONFIG_KUNIT),y) +=                hooks.o
>
>  obj-$(CONFIG_KUNIT_TEST) +=            kunit-test.o
>  obj-$(CONFIG_KUNIT_TEST) +=            platform-test.o
> +obj-$(CONFIG_KUNIT_TEST) +=            backtrace-suppression-test.o
>
>  # string-stream-test compiles built-in only.
>  ifeq ($(CONFIG_KUNIT_TEST),y)
> diff --git a/lib/kunit/backtrace-suppression-test.c b/lib/kunit/backtrace-suppression-test.c
> new file mode 100644
> index 0000000000000..59a038b2739f5
> --- /dev/null
> +++ b/lib/kunit/backtrace-suppression-test.c
> @@ -0,0 +1,192 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * KUnit test for suppressing warning tracebacks.
> + *
> + * Copyright (C) 2024, Guenter Roeck
> + * Author: Guenter Roeck <linux@roeck-us.net>
> + */
> +
> +#include <kunit/test.h>
> +#include <linux/bug.h>
> +#include <linux/completion.h>
> +#include <linux/kthread.h>
> +
> +static void backtrace_suppression_test_warn_direct(struct kunit *test)
> +{
> +       if (!IS_ENABLED(CONFIG_BUG))
> +               kunit_skip(test, "requires CONFIG_BUG");
> +
> +       kunit_warning_suppress(test) {
> +               WARN(1, "This backtrace should be suppressed");
> +               /*
> +                * Count must be checked inside the scope; the handle
> +                * is not accessible after the block exits.
> +                */
> +               KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +       }
> +       KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
> +}
> +
> +static noinline void trigger_backtrace_warn(void)
> +{
> +       WARN(1, "This backtrace should be suppressed");
> +}
> +
> +static void backtrace_suppression_test_warn_indirect(struct kunit *test)
> +{
> +       if (!IS_ENABLED(CONFIG_BUG))
> +               kunit_skip(test, "requires CONFIG_BUG");
> +
> +       kunit_warning_suppress(test) {
> +               trigger_backtrace_warn();
> +               KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +       }
> +}
> +
> +static void backtrace_suppression_test_warn_multi(struct kunit *test)
> +{
> +       if (!IS_ENABLED(CONFIG_BUG))
> +               kunit_skip(test, "requires CONFIG_BUG");
> +
> +       kunit_warning_suppress(test) {
> +               WARN(1, "This backtrace should be suppressed");
> +               trigger_backtrace_warn();
> +               KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
> +       }
> +}
> +
> +static void backtrace_suppression_test_warn_on_direct(struct kunit *test)
> +{
> +       if (!IS_ENABLED(CONFIG_BUG))
> +               kunit_skip(test, "requires CONFIG_BUG");
> +
> +       kunit_warning_suppress(test) {
> +               WARN_ON(1);
> +               KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +       }
> +}
> +
> +static noinline void trigger_backtrace_warn_on(void)
> +{
> +       WARN_ON(1);
> +}
> +
> +static void backtrace_suppression_test_warn_on_indirect(struct kunit *test)
> +{
> +       if (!IS_ENABLED(CONFIG_BUG))
> +               kunit_skip(test, "requires CONFIG_BUG");
> +
> +       kunit_warning_suppress(test) {
> +               trigger_backtrace_warn_on();
> +               KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +       }
> +}
> +
> +static void backtrace_suppression_test_count(struct kunit *test)
> +{
> +       if (!IS_ENABLED(CONFIG_BUG))
> +               kunit_skip(test, "requires CONFIG_BUG");
> +
> +       kunit_warning_suppress(test) {
> +               KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 0);
> +
> +               WARN(1, "suppressed");
> +               KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> +
> +               WARN(1, "suppressed again");
> +               KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 2);
> +       }
> +}
> +
> +static void backtrace_suppression_test_active_state(struct kunit *test)
> +{
> +       KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
> +
> +       kunit_warning_suppress(test) {
> +               KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
> +       }
> +
> +       KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
> +
> +       kunit_warning_suppress(test) {
> +               KUNIT_EXPECT_TRUE(test, kunit_has_active_suppress_warning());
> +       }
> +
> +       KUNIT_EXPECT_FALSE(test, kunit_has_active_suppress_warning());
> +}
> +
> +static void backtrace_suppression_test_multi_scope(struct kunit *test)
> +{
> +       struct kunit_suppressed_warning *sw1, *sw2;
> +
> +       if (!IS_ENABLED(CONFIG_BUG))
> +               kunit_skip(test, "requires CONFIG_BUG");
> +
> +       sw1 = kunit_start_suppress_warning(test);
> +       trigger_backtrace_warn_on();
> +       WARN(1, "suppressed by sw1");
> +       kunit_end_suppress_warning(test, sw1);
> +
> +       sw2 = kunit_start_suppress_warning(test);
> +       WARN(1, "suppressed by sw2");
> +       kunit_end_suppress_warning(test, sw2);
> +
> +       KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw1), 2);
> +       KUNIT_EXPECT_EQ(test, kunit_suppressed_warning_count(sw2), 1);
> +}
> +
> +struct cross_kthread_data {
> +       bool was_active;
> +       struct completion done;
> +};
> +
> +static int cross_kthread_fn(void *data)
> +{
> +       struct cross_kthread_data *d = data;
> +
> +       d->was_active = kunit_has_active_suppress_warning();
> +       complete(&d->done);
> +       while (!kthread_should_stop())
> +               schedule();
> +       return 0;
> +}
> +
> +static void backtrace_suppression_test_cross_kthread(struct kunit *test)
> +{
> +       struct cross_kthread_data data;
> +       struct task_struct *task;
> +
> +       data.was_active = false;
> +       init_completion(&data.done);
> +
> +       kunit_warning_suppress(test) {
> +               task = kthread_run(cross_kthread_fn, &data, "kunit-cross-test");
> +               KUNIT_ASSERT_FALSE(test, IS_ERR(task));
> +               wait_for_completion(&data.done);
> +               kthread_stop(task);
> +       }
> +
> +       KUNIT_EXPECT_FALSE(test, data.was_active);
> +}
> +
> +static struct kunit_case backtrace_suppression_test_cases[] = {
> +       KUNIT_CASE(backtrace_suppression_test_warn_direct),
> +       KUNIT_CASE(backtrace_suppression_test_warn_indirect),
> +       KUNIT_CASE(backtrace_suppression_test_warn_multi),
> +       KUNIT_CASE(backtrace_suppression_test_warn_on_direct),
> +       KUNIT_CASE(backtrace_suppression_test_warn_on_indirect),
> +       KUNIT_CASE(backtrace_suppression_test_count),
> +       KUNIT_CASE(backtrace_suppression_test_active_state),
> +       KUNIT_CASE(backtrace_suppression_test_multi_scope),
> +       KUNIT_CASE(backtrace_suppression_test_cross_kthread),
> +       {}
> +};
> +
> +static struct kunit_suite backtrace_suppression_test_suite = {
> +       .name = "backtrace-suppression-test",
> +       .test_cases = backtrace_suppression_test_cases,
> +};
> +kunit_test_suites(&backtrace_suppression_test_suite);
> +
> +MODULE_LICENSE("GPL");
> +MODULE_DESCRIPTION("KUnit test to verify warning backtrace suppression");
>
> --
> 2.53.0
>


^ permalink raw reply

* Re: [PATCH v2 5/6] misc: amd-sbi: Add SBTSI ioctl register transfer interface
From: Guenter Roeck @ 2026-05-15 14:11 UTC (permalink / raw)
  To: Akshay Gupta, linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, arnd, gregkh, naveenkrishna.chatradhi, Prathima.Lk,
	Anand.Umarji, Kevin.Tung
In-Reply-To: <20260515134506.397649-6-Akshay.Gupta@amd.com>

On 5/15/26 06:45, Akshay Gupta wrote:
> From: Prathima <Prathima.Lk@amd.com>
> 
> Implement IOCTL interface for SB-TSI driver to enable userspace access
> to TSI register read/write operations through the AMD Advanced Platform
> Management Link (APML) protocol.
> Add an ioctl command (SBTSI_IOCTL_REG_XFER_CMD) that accepts a register
> address, data byte, and direction flag. Serialize access with a mutex
> shared between the hwmon and ioctl paths to prevent concurrent bus
> transactions from corrupting register state.
> 
> Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
> Signed-off-by: Prathima <Prathima.Lk@amd.com>
> ---
> Changes since v1:
> - Use of devm_mutex_init in place of mutex_init
> - Use of guard_mutex in place of mutex_lock()/mutex_unlock()
> - Use of devm_add_action_or_reset() for clean removal
>   
>   drivers/hwmon/sbtsi_temp.c      |  6 +++
>   drivers/misc/amd-sbi/tsi-core.c | 84 ++++++++++++++++++++++++++++++++-
>   drivers/misc/amd-sbi/tsi-core.h | 15 ++++++
>   drivers/misc/amd-sbi/tsi.c      | 20 ++++++--
>   include/linux/misc/tsi.h        |  8 ++++
>   include/uapi/misc/amd-apml.h    | 23 +++++++++
>   6 files changed, 151 insertions(+), 5 deletions(-)
>   create mode 100644 drivers/misc/amd-sbi/tsi-core.h
> 
> diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
> index d7ae986d824c..00e982f4c716 100644
> --- a/drivers/hwmon/sbtsi_temp.c
> +++ b/drivers/hwmon/sbtsi_temp.c
> @@ -64,12 +64,15 @@ static inline void sbtsi_mc_to_reg(s32 temp, u8 *integer, u8 *decimal)
>   /*
>    * Read integer and decimal parts of an SB-TSI temperature register pair
>    * The read order is determined by the ReadOrder bit to ensure atomic latching.
> + * The mutex protects against concurrent access to the shared I2C/I3C bus by
> + * the hwmon sysfs and a userspace ioctl
>    */
>   static int sbtsi_temp_read(struct sbtsi_data *data, u8 reg1, u8 reg2,
>   			   u8 *val1, u8 *val2)
>   {
>   	int ret;
>   
> +	guard(mutex)(&data->lock);

I would suggest to hide this behind access functions such as sbtsi_lock(),
sbtsi_unlock(), and the matching guard functions. That can be done in a
separate patch; it should not be necessary to include hwmon in the patch
introducing the ioctl.

Thanks,
Guenter


^ permalink raw reply

* Re: [PATCH] Documentation: fix typo and formattting in security/credentials.rst
From: Jonathan Corbet @ 2026-05-15 14:10 UTC (permalink / raw)
  To: Mayank Gite, Paul Moore
  Cc: Mayank Gite, Serge Hallyn, Shuah Khan, linux-security-module,
	linux-doc, linux-kernel
In-Reply-To: <20260506225925.271163-1-drapl0n.kernel@gmail.com>

Mayank Gite <drapl0n.kernel@gmail.com> writes:

> - Fixes a typo in "Keys and keyrings" section. Replaces "keying" with
>   "keyring".
> - Updates formatting of keyring types.
>
> Signed-off-by: Mayank Gite <drapl0n.kernel@gmail.com>
> ---
>  Documentation/security/credentials.rst | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/security/credentials.rst b/Documentation/security/credentials.rst
> index d0191c8b8060..4996838491b1 100644
> --- a/Documentation/security/credentials.rst
> +++ b/Documentation/security/credentials.rst
> @@ -189,9 +189,9 @@ The Linux kernel supports the following types of credentials:
>       be searched for the desired key.  Each process may subscribe to a number
>       of keyrings:
>  
> -	Per-thread keying
> -	Per-process keyring
> -	Per-session keyring
> +	- Per-thread keyring
> +	- Per-process keyring
> +	- Per-session keyring
>  
Applied, thanks.

jon

^ permalink raw reply

* Re: [PATCH v3 00/13] Improve process/maintainers output
From: Jonathan Corbet @ 2026-05-15 14:07 UTC (permalink / raw)
  To: Mauro Carvalho Chehab, Mauro Carvalho Chehab, Miguel Ojeda
  Cc: Mauro Carvalho Chehab, linux-doc, linux-kernel, rust-for-linux,
	Björn Roy Baron, Alice Ryhl, Andreas Hindborg, Andrew Morton,
	Benno Lossin, Boqun Feng, Danilo Krummrich, Gary Guo, Joe Perches,
	Matteo Croce, Shuah Khan, Trevor Gross
In-Reply-To: <cover.1778309595.git.mchehab+huawei@kernel.org>

Mauro Carvalho Chehab <mchehab+huawei@kernel.org> writes:

> Hi Jon,
>
> This series improve the output at process/maintainers: instead of a
> pure enriched text, the maintainer's file content is now converted
> to a table, and has gained a javascript to allow filtering entries.

OK, I've applied it.  I've wondered about including the MAINTAINERS
stuff, but I must admit that the search box is kind of cool...

jon

^ permalink raw reply

* [PATCH v3 3/3] fs/resctrl: Factor MBA parse-time conversion to be per-arch
From: Ben Horgan @ 2026-05-15 14:06 UTC (permalink / raw)
  To: ben.horgan
  Cc: james.morse, reinette.chatre, fenghuay, linux-kernel,
	linux-arm-kernel, tglx, mingo, bp, dave.hansen, hpa, corbet, x86,
	linux-doc, dave.martin, Dave Martin, Ben Horgan
In-Reply-To: <20260515140612.1205251-1-ben.horgan@arm.com>

From: Dave Martin <Dave.Martin@arm.com>

The control value parser for the MB resource currently coerces the
memory bandwidth percentage value from userspace to be an exact
multiple of the rdt_resource::resctrl_membw::bw_gran parameter.

On MPAM systems, this results in somewhat worse-than-worst-case
rounding, since the bandwidth granularity advertised to resctrl by the
MPAM driver is in general only an approximation to the actual hardware
granularity on these systems, and the hardware bandwidth allocation
control value is not natively a percentage -- necessitating a further
conversion in the resctrl_arch_update_domains() path, regardless of the
conversion done at parse time.

For MPAM and x86 use their custom pre-prepared parse-time conversion,
resctrl_arch_preconvert_bw(). This will avoid accumulated error
from rounding the value twice on MPAM systems. For x86 systems there
is no functional change.

Clarify the documentation, but avoid overly exact promises.

Clamping to bw_min and bw_max still feels generic: leave it in the core
code, for now.

[ BH: Split out x86 specific changes ]
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
Signed-off-by: Ben Horgan <Ben.Horgan@arm.com>
Reviewed-by: Ben Horgan <ben.horgan@arm.com>
---
 Documentation/filesystems/resctrl.rst | 17 +++++++++--------
 fs/resctrl/ctrlmondata.c              |  6 +++---
 2 files changed, 12 insertions(+), 11 deletions(-)

diff --git a/Documentation/filesystems/resctrl.rst b/Documentation/filesystems/resctrl.rst
index b003bed339fd..4322d8025453 100644
--- a/Documentation/filesystems/resctrl.rst
+++ b/Documentation/filesystems/resctrl.rst
@@ -236,12 +236,11 @@ with respect to allocation:
 		user can request.
 
 "bandwidth_gran":
-		The granularity in which the memory bandwidth
-		percentage is allocated. The allocated
-		b/w percentage is rounded off to the next
-		control step available on the hardware. The
-		available bandwidth control steps are:
-		min_bandwidth + N * bandwidth_gran.
+		The approximate granularity in which the memory bandwidth
+		percentage is allocated. The allocated bandwidth percentage
+		is rounded up to the next control step available on the
+		hardware. The available hardware steps are no larger than
+		this value.
 
 "delay_linear":
 		Indicates if the delay scale is linear or
@@ -871,8 +870,10 @@ The minimum bandwidth percentage value for each cpu model is predefined
 and can be looked up through "info/MB/min_bandwidth". The bandwidth
 granularity that is allocated is also dependent on the cpu model and can
 be looked up at "info/MB/bandwidth_gran". The available bandwidth
-control steps are: min_bw + N * bw_gran. Intermediate values are rounded
-to the next control step available on the hardware.
+control steps are, approximately, min_bw + N * bw_gran.  The steps may
+appear irregular due to rounding to an exact percentage: bw_gran is the
+maximum interval between the percentage values corresponding to any two
+adjacent steps in the hardware.
 
 The bandwidth throttling is a core specific mechanism on some of Intel
 SKUs. Using a high bandwidth and a low bandwidth setting on two threads
diff --git a/fs/resctrl/ctrlmondata.c b/fs/resctrl/ctrlmondata.c
index 9a7dfc48cb2e..934e12f5d145 100644
--- a/fs/resctrl/ctrlmondata.c
+++ b/fs/resctrl/ctrlmondata.c
@@ -37,8 +37,8 @@ typedef int (ctrlval_parser_t)(struct rdt_parse_data *data,
 /*
  * Check whether MBA bandwidth percentage value is correct. The value is
  * checked against the minimum and max bandwidth values specified by the
- * hardware. The allocated bandwidth percentage is rounded to the next
- * control step available on the hardware.
+ * hardware. The allocated bandwidth percentage is converted as
+ * appropriate for consumption by the specific hardware driver.
  */
 static bool bw_validate(char *buf, u32 *data, struct rdt_resource *r)
 {
@@ -71,7 +71,7 @@ static bool bw_validate(char *buf, u32 *data, struct rdt_resource *r)
 		return false;
 	}
 
-	*data = roundup(bw, (unsigned long)r->membw.bw_gran);
+	*data = resctrl_arch_preconvert_bw(bw, r);
 	return true;
 }
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 2/3] arm_mpam: resctrl: Add pass-through resctrl_arch_preconvert_bw()
From: Ben Horgan @ 2026-05-15 14:06 UTC (permalink / raw)
  To: ben.horgan
  Cc: james.morse, reinette.chatre, fenghuay, linux-kernel,
	linux-arm-kernel, tglx, mingo, bp, dave.hansen, hpa, corbet, x86,
	linux-doc, dave.martin
In-Reply-To: <20260515140612.1205251-1-ben.horgan@arm.com>

resctrl rounds up the percentage value of the MBA based on the bw_gran. As
MPAM uses a binary fixed point fraction format for MBA rather than a
decimal percentage, this introduces rounding errors.

Without this additional rounding, if the user reads the value in an MB
schema and then writes it back to the schema, the value in hardware won't
change. However, with this additional rounding, this guarantee is broken
for systems with mbw_wd < 7.

resctrl is introducing resctrl_arch_preconvert_bw() to allow the arch code
to specify the conversion resctrl does to the user-provided bandwidth
value. Add the MPAM version of resctrl_arch_preconvert_bw(). This does no
conversion.

Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
 drivers/resctrl/mpam_resctrl.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/drivers/resctrl/mpam_resctrl.c b/drivers/resctrl/mpam_resctrl.c
index 226ff6f532fa..5a2104af22cc 100644
--- a/drivers/resctrl/mpam_resctrl.c
+++ b/drivers/resctrl/mpam_resctrl.c
@@ -167,6 +167,11 @@ bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
 	return mpam_resctrl_controls[rid].cdp_enabled;
 }
 
+u32 resctrl_arch_preconvert_bw(u32 val, const struct rdt_resource *r)
+{
+	return val;
+}
+
 /**
  * resctrl_reset_task_closids() - Reset the PARTID/PMG values for all tasks.
  *
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 1/3] x86/resctrl: Add resctrl_arch_preconvert_bw()
From: Ben Horgan @ 2026-05-15 14:06 UTC (permalink / raw)
  To: ben.horgan
  Cc: james.morse, reinette.chatre, fenghuay, linux-kernel,
	linux-arm-kernel, tglx, mingo, bp, dave.hansen, hpa, corbet, x86,
	linux-doc, dave.martin
In-Reply-To: <20260515140612.1205251-1-ben.horgan@arm.com>

On MPAM systems the rounding behaviour of the MBA control would be improved
if the rounding in the fs/resctrl code is removed but this is not the
case for x86. To allow any rounding or conversion of the bandwidth value
provided by the user to be specified by the arch code a new arch hook is
required.

Introduce resctrl_arch_preconvert_bw(), and add its x86 implementation.
This is currently unused in resctrl but when plumbed in it will replace the
call to roundup() in bw_validate().

Signed-off-by: Dave Martin <dave.martin@arm.com>
Signed-off-by: Ben Horgan <ben.horgan@arm.com>
---
Changes since Dave's v2:
Split from larger patch and add commit message
Update kernel-doc (Reinette)
---
 arch/x86/kernel/cpu/resctrl/ctrlmondata.c |  6 ++++++
 include/linux/resctrl.h                   | 19 +++++++++++++++++++
 2 files changed, 25 insertions(+)

diff --git a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
index b20e705606b8..19ae596f6b30 100644
--- a/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
+++ b/arch/x86/kernel/cpu/resctrl/ctrlmondata.c
@@ -16,9 +16,15 @@
 #define pr_fmt(fmt)	KBUILD_MODNAME ": " fmt
 
 #include <linux/cpu.h>
+#include <linux/math.h>
 
 #include "internal.h"
 
+u32 resctrl_arch_preconvert_bw(u32 val, const struct rdt_resource *r)
+{
+	return roundup(val, (unsigned long)r->membw.bw_gran);
+}
+
 int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 			    u32 closid, enum resctrl_conf_type t, u32 cfg_val)
 {
diff --git a/include/linux/resctrl.h b/include/linux/resctrl.h
index 006e57fd7ca5..33a6742da4f9 100644
--- a/include/linux/resctrl.h
+++ b/include/linux/resctrl.h
@@ -500,6 +500,25 @@ bool resctrl_arch_mbm_cntr_assign_enabled(struct rdt_resource *r);
  */
 int resctrl_arch_mbm_cntr_assign_set(struct rdt_resource *r, bool enable);
 
+/**
+ * resctrl_arch_preconvert_bw() - Prepare bandwidth control value for arch use.
+ * @val:	Bandwidth control value written to the schemata file by userspace.
+ * @r:		Resource whose schema was written.
+ *
+ * Convert the user provided bandwidth control value to an appropriate form for
+ * consumption by the hardware driver for resource @r. Converted value is stored
+ * in rdt_ctrl_domain::staged_config[] for later consumption by
+ * resctrl_arch_update_domains(). Is not called when MBA software controller is
+ * enabled.
+ *
+ * Architectures for which this pre-conversion hook is not useful should supply
+ * an implementation of this function that just returns val unmodified.
+ *
+ * Return:
+ * The converted value.
+ */
+u32 resctrl_arch_preconvert_bw(u32 val, const struct rdt_resource *r);
+
 /*
  * Update the ctrl_val and apply this config right now.
  * Must be called on one of the domain's CPUs.
-- 
2.43.0


^ permalink raw reply related

* [PATCH v3 0/3] x86,fs/resctrl,arm_mpam: Factor MBA parse-time conversion to be per-arch
From: Ben Horgan @ 2026-05-15 14:06 UTC (permalink / raw)
  To: ben.horgan
  Cc: james.morse, reinette.chatre, fenghuay, linux-kernel,
	linux-arm-kernel, tglx, mingo, bp, dave.hansen, hpa, corbet, x86,
	linux-doc, dave.martin

This is a new version of Dave Martin's patch [1] to delegate rounding of
bandwidth control user values to the arch code. As there is now more than one
architecture using resctrl, I split the original patch into two, a core resctrl
patch and an x86 patch, and added an MPAM patch. Please let me know if the patch
break down and ordering is sensible and whether the pattern should be followed
for any future similar changes.

This does have a user visible effect on MB schema when using MPAM hardware
with 'bandwidth_gran' greater than 1. I'm not sure if MPAM hardware with such
coarse controls exists in the wild but it is spec compliant and I've tested it
on a model.

[1] https://lore.kernel.org/lkml/20251031154225.14799-1-Dave.Martin@arm.com/

Ben Horgan (2):
  x86/resctrl: Add resctrl_arch_preconvert_bw()
  arm_mpam: resctrl: Add pass-through resctrl_arch_preconvert_bw()

Dave Martin (1):
  fs/resctrl: Factor MBA parse-time conversion to be per-arch

 Documentation/filesystems/resctrl.rst     | 17 +++++++++--------
 arch/x86/kernel/cpu/resctrl/ctrlmondata.c |  6 ++++++
 drivers/resctrl/mpam_resctrl.c            |  5 +++++
 fs/resctrl/ctrlmondata.c                  |  6 +++---
 include/linux/resctrl.h                   | 19 +++++++++++++++++++
 5 files changed, 42 insertions(+), 11 deletions(-)

-- 
2.43.0


^ permalink raw reply

* Re: [PATCH v4] docs: reporting-issues: replace "these advices" with "all of this advice"
From: Jonathan Corbet @ 2026-05-15 13:56 UTC (permalink / raw)
  To: Chen-Shi-Hong, linux; +Cc: skhan, linux-doc, linux-kernel, Chen-Shi-Hong
In-Reply-To: <20260514082808.655-1-eric039eric@gmail.com>

Chen-Shi-Hong <eric039eric@gmail.com> writes:

> "Advice" is an uncountable noun, so "these advices" is grammatically
> incorrect.
>
> Replace it with "all of this advice" instead, which keeps the sentence
> grammatical while also making it clear that it refers to the full set of
> recommendations in the paragraph.
>
> Signed-off-by: Chen-Shi-Hong <eric039eric@gmail.com>
> ---
> v4:
> - move version changelog below the "---"
> - send as a separate thread
>
> v3:
> - resend against the original base as requested
> - replace "these advices" directly with "all of this advice"
>
> v2:
> - use "all of this advice" based on review feedback
>  Documentation/admin-guide/reporting-issues.rst | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)

Applied, thanks.

jon

^ permalink raw reply

* Re: [PATCH] dm: fix dm-inlinecrypt docs warnings
From: Jonathan Corbet @ 2026-05-15 13:55 UTC (permalink / raw)
  To: Randy Dunlap, linux-kernel
  Cc: Randy Dunlap, Linlin Zhang, Alasdair Kergon, Mike Snitzer,
	Mikulas Patocka, Benjamin Marzinski, dm-devel, Shuah Khan,
	linux-doc
In-Reply-To: <20260512180409.1193504-1-rdunlap@infradead.org>

Randy Dunlap <rdunlap@infradead.org> writes:

> Add this file to the index and use a longer heading overline string
> to eliminate warnings:
>
> Documentation/admin-guide/device-mapper/dm-inlinecrypt.rst:1: WARNING: Title overline too short.
> ========
> dm-inlinecrypt
> ========
> Documentation/admin-guide/device-mapper/dm-inlinecrypt.rst: WARNING: document isn't included in any toctree [toc.not_included]
>
> Fixes: b4a0774bd7fd ("dm: add documentation for dm-inlinecrypt target")
> Signed-off-by: Randy Dunlap <rdunlap@infradead.org>
> ---
> Cc: Linlin Zhang <linlin.zhang@oss.qualcomm.com>
> Cc: Alasdair Kergon <agk@redhat.com>
> Cc: Mike Snitzer <snitzer@kernel.org>
> Cc: Mikulas Patocka <mpatocka@redhat.com>
> Cc: Benjamin Marzinski <bmarzins@redhat.com>
> Cc: dm-devel@lists.linux.dev
> Cc: Jonathan Corbet <corbet@lwn.net>
> Cc: Shuah Khan <skhan@linuxfoundation.org>
> Cc: linux-doc@vger.kernel.org
>
>  Documentation/admin-guide/device-mapper/dm-inlinecrypt.rst |    4 ++--
>  Documentation/admin-guide/device-mapper/index.rst          |    1 +
>  2 files changed, 3 insertions(+), 2 deletions(-)

This doesn't apply to docs-next, so I'm guessing it's intended for some
other tree?

Thanks,

jon

^ permalink raw reply

* Re: [PATCH RFC 2/5] dma-heap: charge dma-buf memory via explicit memcg
From: Christian Brauner @ 2026-05-15 13:53 UTC (permalink / raw)
  To: Albert Esteve
  Cc: Tejun Heo, Johannes Weiner, Michal Koutný, Jonathan Corbet,
	Shuah Khan, Sumit Semwal, Christian König, Michal Hocko,
	Roman Gushchin, Shakeel Butt, Muchun Song, Andrew Morton,
	Benjamin Gaignard, Brian Starkey, John Stultz, T.J. Mercier,
	Paul Moore, James Morris, Serge E. Hallyn, Stephen Smalley,
	Ondrej Mosnacek, Shuah Khan, cgroups, linux-doc, linux-kernel,
	linux-media, dri-devel, linaro-mm-sig, linux-mm,
	linux-security-module, selinux, linux-kselftest, mripard,
	echanude
In-Reply-To: <20260512-v2_20230123_tjmercier_google_com-v1-2-6326701c3691@redhat.com>

On Tue, May 12, 2026 at 11:10:44AM +0200, Albert Esteve wrote:
> On embedded platforms a central process often allocates dma-buf
> memory on behalf of client applications. Without a way to
> attribute the charge to the requesting client's cgroup, the
> cost lands on the allocator, making per-cgroup memory limits
> ineffective for the actual consumers.
> 
> Add charge_pid_fd to struct dma_heap_allocation_data. When set to

Please be aware that pidfds come in two flavors:

thread-group pidfds and thread-specific pidfds. Make sure that your API
doesn't implicitly depend on this distinction not existing.


> a valid pidfd, DMA_HEAP_IOCTL_ALLOC resolves the target task's
> memcg and charges the buffer there via mem_cgroup_charge_dmabuf()
> inside dma_heap_buffer_alloc(). Without charge_pid_fd, and with
> the mem_accounting module parameter enabled, the buffer is charged
> to the allocator's own cgroup.
> 
> Additionally, commit 3c227be90659 ("dma-buf: system_heap: account for
> system heap allocation in memcg") adds __GFP_ACCOUNT to system-heap
> page allocations. Keeping __GFP_ACCOUNT would charge the same pages
> twice (once to kmem, once to MEMCG_DMABUF), thus remove it and route
> all accounting through a single MEMCG_DMABUF path.
> 
> Usage examples:
> 
>   1. Central allocator charging to a client at allocation time.
>      The allocator knows the client's PID (e.g., from binder's
>      sender_pid) and uses pidfd to attribute the charge:
> 
>        pid_t client_pid = txn->sender_pid;
>        int pidfd = pidfd_open(client_pid, 0);
> 
>        struct dma_heap_allocation_data alloc = {
>            .len             = buffer_size,
>            .fd_flags        = O_RDWR | O_CLOEXEC,
>            .charge_pid_fd   = pidfd,
>        };
>        ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
>        close(pidfd);
>        /* alloc.fd is now charged to client's cgroup */
> 
>   2. Default allocation (no pidfd, mem_accounting=1).
>      When charge_pid_fd is not set and the mem_accounting module
>      parameter is enabled, the buffer is charged to the allocator's
>      own cgroup:
> 
>        struct dma_heap_allocation_data alloc = {
>            .len      = buffer_size,
>            .fd_flags = O_RDWR | O_CLOEXEC,
>        };
>        ioctl(heap_fd, DMA_HEAP_IOCTL_ALLOC, &alloc);
>        /* charged to current process's cgroup */
> 
> Current limitations:
> 
>  - Single-owner model: a dma-buf carries one memcg charge regardless of
>    how many processes share it. Means only the first owner (and exporter)
>    of the shared buffer bears the charge.
>  - Only memcg accounting supported. While this makes sense for system
>    heap buffers, other heaps (e.g., CMA heaps) will require selectively
>    charging also for the dmem controller.
> 
> Signed-off-by: Albert Esteve <aesteve@redhat.com>
> ---
>  Documentation/admin-guide/cgroup-v2.rst |  5 ++--
>  drivers/dma-buf/dma-buf.c               | 16 ++++---------
>  drivers/dma-buf/dma-heap.c              | 42 ++++++++++++++++++++++++++++++---
>  drivers/dma-buf/heaps/system_heap.c     |  2 --
>  include/uapi/linux/dma-heap.h           |  6 +++++
>  5 files changed, 53 insertions(+), 18 deletions(-)
> 
> diff --git a/Documentation/admin-guide/cgroup-v2.rst b/Documentation/admin-guide/cgroup-v2.rst
> index 8bdbc2e866430..824d269531eb1 100644
> --- a/Documentation/admin-guide/cgroup-v2.rst
> +++ b/Documentation/admin-guide/cgroup-v2.rst
> @@ -1636,8 +1636,9 @@ The following nested keys are defined.
>  		structures.
>  
>  	  dmabuf (npn)
> -		Amount of memory used for exported DMA buffers allocated by the cgroup.
> -		Stays with the allocating cgroup regardless of how the buffer is shared.
> +		Amount of memory used for exported DMA buffers allocated by or on
> +		behalf of the cgroup. Stays with the allocating cgroup regardless
> +		of how the buffer is shared.
>  
>  	  workingset_refault_anon
>  		Number of refaults of previously evicted anonymous pages.
> diff --git a/drivers/dma-buf/dma-buf.c b/drivers/dma-buf/dma-buf.c
> index ce02377f48908..23fb758b78297 100644
> --- a/drivers/dma-buf/dma-buf.c
> +++ b/drivers/dma-buf/dma-buf.c
> @@ -181,8 +181,11 @@ static void dma_buf_release(struct dentry *dentry)
>  	 */
>  	BUG_ON(dmabuf->cb_in.active || dmabuf->cb_out.active);
>  
> -	mem_cgroup_uncharge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> -	mem_cgroup_put(dmabuf->memcg);
> +	if (dmabuf->memcg) {
> +		mem_cgroup_uncharge_dmabuf(dmabuf->memcg,
> +					  PAGE_ALIGN(dmabuf->size) / PAGE_SIZE);
> +		mem_cgroup_put(dmabuf->memcg);
> +	}
>  
>  	dmabuf->ops->release(dmabuf);
>  
> @@ -764,13 +767,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
>  		dmabuf->resv = resv;
>  	}
>  
> -	dmabuf->memcg = get_mem_cgroup_from_mm(current->mm);
> -	if (!mem_cgroup_charge_dmabuf(dmabuf->memcg, PAGE_ALIGN(dmabuf->size) / PAGE_SIZE,
> -				      GFP_KERNEL)) {
> -		ret = -ENOMEM;
> -		goto err_memcg;
> -	}
> -
>  	file->private_data = dmabuf;
>  	file->f_path.dentry->d_fsdata = dmabuf;
>  	dmabuf->file = file;
> @@ -781,8 +777,6 @@ struct dma_buf *dma_buf_export(const struct dma_buf_export_info *exp_info)
>  
>  	return dmabuf;
>  
> -err_memcg:
> -	mem_cgroup_put(dmabuf->memcg);
>  err_file:
>  	fput(file);
>  err_module:
> diff --git a/drivers/dma-buf/dma-heap.c b/drivers/dma-buf/dma-heap.c
> index ac5f8685a6494..ff6e259afcdc0 100644
> --- a/drivers/dma-buf/dma-heap.c
> +++ b/drivers/dma-buf/dma-heap.c
> @@ -7,13 +7,17 @@
>   */
>  
>  #include <linux/cdev.h>
> +#include <linux/cgroup.h>
>  #include <linux/device.h>
>  #include <linux/dma-buf.h>
>  #include <linux/dma-heap.h>
> +#include <linux/memcontrol.h>
> +#include <linux/sched/mm.h>
>  #include <linux/err.h>
>  #include <linux/export.h>
>  #include <linux/list.h>
>  #include <linux/nospec.h>
> +#include <linux/pidfd.h>
>  #include <linux/syscalls.h>
>  #include <linux/uaccess.h>
>  #include <linux/xarray.h>
> @@ -55,10 +59,12 @@ MODULE_PARM_DESC(mem_accounting,
>  		 "Enable cgroup-based memory accounting for dma-buf heap allocations (default=false).");
>  
>  static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
> -				 u32 fd_flags,
> -				 u64 heap_flags)
> +				 u32 fd_flags, u64 heap_flags,
> +				 struct mem_cgroup *charge_to)
>  {
>  	struct dma_buf *dmabuf;
> +	unsigned int nr_pages;
> +	struct mem_cgroup *memcg = charge_to;
>  	int fd;
>  
>  	/*
> @@ -73,6 +79,22 @@ static int dma_heap_buffer_alloc(struct dma_heap *heap, size_t len,
>  	if (IS_ERR(dmabuf))
>  		return PTR_ERR(dmabuf);
>  
> +	nr_pages = len / PAGE_SIZE;
> +
> +	if (memcg)
> +		css_get(&memcg->css);
> +	else if (mem_accounting)
> +		memcg = get_mem_cgroup_from_mm(current->mm);
> +
> +	if (memcg) {
> +		if (!mem_cgroup_charge_dmabuf(memcg, nr_pages, GFP_KERNEL)) {
> +			mem_cgroup_put(memcg);
> +			dma_buf_put(dmabuf);
> +			return -ENOMEM;
> +		}
> +		dmabuf->memcg = memcg;
> +	}
> +
>  	fd = dma_buf_fd(dmabuf, fd_flags);
>  	if (fd < 0) {
>  		dma_buf_put(dmabuf);
> @@ -102,6 +124,9 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
>  {
>  	struct dma_heap_allocation_data *heap_allocation = data;
>  	struct dma_heap *heap = file->private_data;
> +	struct mem_cgroup *memcg = NULL;
> +	struct task_struct *task;
> +	unsigned int pidfd_flags;
>  	int fd;
>  
>  	if (heap_allocation->fd)
> @@ -113,9 +138,20 @@ static long dma_heap_ioctl_allocate(struct file *file, void *data)
>  	if (heap_allocation->heap_flags & ~DMA_HEAP_VALID_HEAP_FLAGS)
>  		return -EINVAL;
>  
> +	if (heap_allocation->charge_pid_fd) {
> +		task = pidfd_get_task(heap_allocation->charge_pid_fd, &pidfd_flags);

Will always get a thread-group leader pidfd and will fail if this is a
thread-specific pidfd. pidfd_open(1234, PIDFD_THREAD) can be used to
open a thread-specific pidfd.

> +		if (IS_ERR(task))
> +			return PTR_ERR(task);
> +
> +		memcg = get_mem_cgroup_from_mm(task->mm);
> +		put_task_struct(task);
> +	}
> +
>  	fd = dma_heap_buffer_alloc(heap, heap_allocation->len,
>  				   heap_allocation->fd_flags,
> -				   heap_allocation->heap_flags);
> +				   heap_allocation->heap_flags,
> +				   memcg);
> +	mem_cgroup_put(memcg);
>  	if (fd < 0)
>  		return fd;
>  
> diff --git a/drivers/dma-buf/heaps/system_heap.c b/drivers/dma-buf/heaps/system_heap.c
> index 03c2b87cb1112..95d7688167b93 100644
> --- a/drivers/dma-buf/heaps/system_heap.c
> +++ b/drivers/dma-buf/heaps/system_heap.c
> @@ -385,8 +385,6 @@ static struct page *alloc_largest_available(unsigned long size,
>  		if (max_order < orders[i])
>  			continue;
>  		flags = order_flags[i];
> -		if (mem_accounting)
> -			flags |= __GFP_ACCOUNT;
>  		page = alloc_pages(flags, orders[i]);
>  		if (!page)
>  			continue;
> diff --git a/include/uapi/linux/dma-heap.h b/include/uapi/linux/dma-heap.h
> index a4cf716a49fa6..e02b0f8cbc6a1 100644
> --- a/include/uapi/linux/dma-heap.h
> +++ b/include/uapi/linux/dma-heap.h
> @@ -29,6 +29,10 @@
>   *			handle to the allocated dma-buf
>   * @fd_flags:		file descriptor flags used when allocating
>   * @heap_flags:		flags passed to heap
> + * @charge_pid_fd:	optional pidfd of the process whose cgroup should be
> + *			charged for this allocation; 0 means charge the calling
> + *			process's cgroup
> + * @__padding:		reserved, must be zero
>   *
>   * Provided by userspace as an argument to the ioctl
>   */
> @@ -37,6 +41,8 @@ struct dma_heap_allocation_data {
>  	__u32 fd;
>  	__u32 fd_flags;
>  	__u64 heap_flags;
> +	__u32 charge_pid_fd;
> +	__u32 __padding;
>  };
>  
>  #define DMA_HEAP_IOC_MAGIC		'H'
> 
> -- 
> 2.53.0
> 

^ permalink raw reply

* Re: [PATCH] docs: sphinx-static: fix typo "wich" -> "which"
From: Jonathan Corbet @ 2026-05-15 13:52 UTC (permalink / raw)
  To: Clinton Phillips; +Cc: Clinton Phillips, linux-doc, linux-kernel
In-Reply-To: <20260513195956.25307-1-clintdotphillips@gmail.com>

Clinton Phillips <clintdotphillips@gmail.com> writes:

> Trivial typo fix in a CSS comment for the documentation theme.
>
> Signed-off-by: Clinton Phillips <clintdotphillips@gmail.com>
> ---
>  Documentation/sphinx-static/custom.css | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/Documentation/sphinx-static/custom.css b/Documentation/sphinx-static/custom.css
> index f91393426..5aa0a1ed9 100644
> --- a/Documentation/sphinx-static/custom.css
> +++ b/Documentation/sphinx-static/custom.css
> @@ -30,7 +30,7 @@ img.logo {
>      margin-bottom: 20px;
>  }
>  
> -/* The default is to use -1em, wich makes it override text */
> +/* The default is to use -1em, which makes it override text */
>  li { text-indent: 0em; }

Applied, thanks.

jon

^ permalink raw reply

* Re: [PATCH v13 0/4] kunit: Add support for suppressing warning backtraces
From: Guenter Roeck @ 2026-05-15 13:51 UTC (permalink / raw)
  To: Albert Esteve, Arnd Bergmann, Brendan Higgins, David Gow,
	Rae Moar, Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann,
	David Airlie, Simona Vetter, Jonathan Corbet, Shuah Khan,
	Andrew Morton, Paul Walmsley, Palmer Dabbelt, Albert Ou,
	Alexandre Ghiti
  Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
	workflows, linux-riscv, linux-doc, peterz, Alessandro Carminati,
	Kees Cook, Linux Kernel Functional Testing, Maíra Canal,
	Dan Carpenter, Simona Vetter
In-Reply-To: <20260515-kunit_add_support-v13-0-18ee42f96e7b@redhat.com>

Hi Albert,

On 5/15/26 05:29, Albert Esteve wrote:
...

> Guenter Roeck (3):
>        kunit: Add backtrace suppression self-tests
>        drm: Suppress intentional warning backtraces in scaling unit tests
>        kunit: Add documentation for warning backtrace suppression API
> 


How much of that is from me at this point ? Wouldn't it make sense to drop me
as "author" of those patches ?

I would not mind. I had the idea, but others like you are doing the hard work
of pushing it through.

Thanks,
Guenter


^ permalink raw reply

* [PATCH v2 6/6] docs: misc: amd-sbi: Document SBTSI userspace interface
From: Akshay Gupta @ 2026-05-15 13:45 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, akshay.gupta,
	naveenkrishna.chatradhi, Prathima.Lk, Anand.Umarji, Kevin.Tung,
	Akshay Gupta
In-Reply-To: <20260515134506.397649-1-Akshay.Gupta@amd.com>

From: Prathima <Prathima.Lk@amd.com>

- Document AMD sideband IOCTL description defined
  for SBTSI and its usage.
  User space C-APIs are made available by esmi_oob_library [1],
  which is provided by the E-SMS project [2].

  Link: https://github.com/amd/esmi_oob_library [1]
  Link: https://www.amd.com/en/developer/e-sms.html [2]

Include a user-space open example for /dev/sbtsi-* and list auxiliary
bus sysfs paths.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v1:
- Elaborate the document

 Documentation/misc-devices/amd-sbi.rst | 64 ++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/Documentation/misc-devices/amd-sbi.rst b/Documentation/misc-devices/amd-sbi.rst
index f91ddadefe48..6a6344439ef5 100644
--- a/Documentation/misc-devices/amd-sbi.rst
+++ b/Documentation/misc-devices/amd-sbi.rst
@@ -48,6 +48,56 @@ Access restrictions:
  * APML Mailbox messages and Register xfer access are read-write,
  * CPUID and MCA_MSR access is read-only.
 
+SBTSI device
+============
+
+sbtsi driver under the drivers/misc/amd-sbi creates miscdevice
+/dev/sbtsi-* to let user space programs run APML TSI register xfer
+commands.
+
+The driver supports both I2C and I3C transports for SB-TSI targets.
+The transport is selected by the bus where the device is enumerated.
+
+.. code-block:: bash
+
+   $ ls -al /dev/sbtsi-4c
+   crw-------    1 root     root       10, 116 Apr  2 05:22 /dev/sbtsi-4c
+
+
+Access restrictions:
+ * Only root user is allowed to open the file.
+ * APML TSI Register xfer access is read-write.
+
+SBTSI hwmon interface
+=====================
+
+The sbtsi_temp auxiliary driver binds to the auxiliary device published
+by the core sbtsi driver on the auxiliary bus. The auxiliary device is
+named amd-sbtsi.temp-sensor.<addr> where <addr> is the device's dynamic
+address.
+
+It registers a hwmon device, providing a standard Linux hwmon interface
+for reading CPU temperature and managing temperature limits.
+
+The hwmon device appears under ``/sys/class/hwmon/`` when both ``sbtsi.ko``
+and ``sbtsi_temp.ko`` are loaded.
+
+Verify auxiliary bus device::
+
+  ls /sys/bus/auxiliary/devices/
+  # e.g. amd-sbtsi.temp-sensor.X
+
+Example usage::
+
+  # Read current temperature
+  cat /sys/class/hwmon/hwmon<N>/temp1_input
+
+  # Set high temperature limit to 70 °C
+  echo 70000 > /sys/class/hwmon/hwmon<N>/temp1_max
+
+  # Verify
+  cat /sys/class/hwmon/hwmon<N>/temp1_max
+
 Driver IOCTLs
 =============
 
@@ -63,6 +113,9 @@ Driver IOCTLs
 .. c:macro:: SBRMI_IOCTL_REG_XFER_CMD
 .. kernel-doc:: include/uapi/misc/amd-apml.h
    :doc: SBRMI_IOCTL_REG_XFER_CMD
+.. c:macro:: SBTSI_IOCTL_REG_XFER_CMD
+.. kernel-doc:: include/uapi/misc/amd-apml.h
+   :doc: SBTSI_IOCTL_REG_XFER_CMD
 
 User-space usage
 ================
@@ -85,6 +138,16 @@ Next thing, open the device file, as follows::
     exit(1);
   }
 
+To open SB-TSI device::
+
+  int file;
+
+  file = open("/dev/sbtsi-*", O_RDWR);
+  if (file < 0) {
+    /* ERROR HANDLING */
+    exit(1);
+  }
+
 The following IOCTLs are defined:
 
 ``#define SB_BASE_IOCTL_NR      	0xF9``
@@ -92,6 +155,7 @@ The following IOCTLs are defined:
 ``#define SBRMI_IOCTL_CPUID_CMD		_IOWR(SB_BASE_IOCTL_NR, 1, struct apml_cpuid_msg)``
 ``#define SBRMI_IOCTL_MCAMSR_CMD	_IOWR(SB_BASE_IOCTL_NR, 2, struct apml_mcamsr_msg)``
 ``#define SBRMI_IOCTL_REG_XFER_CMD	_IOWR(SB_BASE_IOCTL_NR, 3, struct apml_reg_xfer_msg)``
+``#define SBTSI_IOCTL_REG_XFER_CMD      _IOWR(SB_BASE_IOCTL_NR, 4, struct apml_tsi_xfer_msg)``
 
 
 User space C-APIs are made available by esmi_oob_library, hosted at
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 4/6] misc: amd-sbi: Add support for SB-TSI over I3C
From: Akshay Gupta @ 2026-05-15 13:45 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, akshay.gupta,
	naveenkrishna.chatradhi, Prathima.Lk, Anand.Umarji, Kevin.Tung,
	Akshay Gupta
In-Reply-To: <20260515134506.397649-1-Akshay.Gupta@amd.com>

From: Prathima <Prathima.Lk@amd.com>

AMD SB-TSI temperature sensors can be accessed over both
I2C and I3C buses depending on the platform configuration.
Extend the SB-TSI driver to support both I2C and I3C bus interfaces
by selecting the appropriate transport based on the probed bus type.
The driver maintains backward compatibility with existing I2C
deployments while enabling support for systems using the I3C bus.
Register both I2C and I3C drivers using module_i3c_i2c_driver() and
update the Kconfig dependency from I2C to I3C_OR_I2C.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v1:
- Changes in accordance with usage of auxiliary device

 drivers/misc/amd-sbi/Kconfig    |  4 +--
 drivers/misc/amd-sbi/tsi-core.c | 38 ++++++++++++++++++++
 drivers/misc/amd-sbi/tsi.c      | 61 +++++++++++++++++++++++++++++++--
 include/linux/misc/tsi.h        | 10 +++++-
 4 files changed, 107 insertions(+), 6 deletions(-)

diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig
index 512251690e0e..1a96b71f8506 100644
--- a/drivers/misc/amd-sbi/Kconfig
+++ b/drivers/misc/amd-sbi/Kconfig
@@ -23,13 +23,13 @@ config AMD_SBRMI_HWMON
 
 config AMD_SBTSI
 	tristate "AMD side band TSI support"
-	depends on I2C
+	depends on I3C_OR_I2C
 	depends on ARM || ARM64 || COMPILE_TEST
 	select AUXILIARY_BUS
 	help
 	  Enables support for the AMD SB-TSI (Side Band Temperature Sensor
 	  Interface) driver, which provides access to emulated CPU temperature
-	  sensors on AMD SoCs via an I2C connected BMC device.
+	  sensors on AMD SoCs via an I2C/I3C connected BMC device.
 
 	  This driver can also be built as a module. If so, the module will
 	  be called sbtsi.
diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
index 6ef1831515bb..19388737b225 100644
--- a/drivers/misc/amd-sbi/tsi-core.c
+++ b/drivers/misc/amd-sbi/tsi-core.c
@@ -23,8 +23,46 @@ static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read
 	return i2c_smbus_write_byte_data(data->client, reg, *val);
 }
 
+/* I3C read transfer function */
+static int sbtsi_i3c_read(struct sbtsi_data *data, u8 reg, u8 *val)
+{
+	struct i3c_xfer xfers[2] = { };
+
+	/* Add Register data to read/write */
+	xfers[0].rnw = false;
+	xfers[0].len = 1;
+	xfers[0].data.out = &reg;
+
+	xfers[1].rnw = true;
+	xfers[1].len = 1;
+	xfers[1].data.in = val;
+
+	return i3c_device_do_xfers(data->i3cdev, xfers, 2, I3C_SDR);
+}
+
+/* I3C write transfer function */
+static int sbtsi_i3c_write(struct sbtsi_data *data, u8 reg, u8 val)
+{
+	u8 buf[2];
+	struct i3c_xfer xfers = {
+		.rnw = false,
+		.len = 2,
+		.data.out = buf,
+	};
+
+	buf[0] = reg;
+	buf[1] = val;
+
+	return i3c_device_do_xfers(data->i3cdev, &xfers, 1, I3C_SDR);
+}
+
+/* Unified transfer function for I2C and I3C access */
 int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
 {
+	if (data->is_i3c)
+		return is_read ? sbtsi_i3c_read(data, reg, val)
+			       : sbtsi_i3c_write(data, reg, *val);
+
 	return sbtsi_i2c_xfer(data, reg, val, is_read);
 }
 EXPORT_SYMBOL_GPL(sbtsi_xfer);
diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
index ee2216785550..43bbac7faf08 100644
--- a/drivers/misc/amd-sbi/tsi.c
+++ b/drivers/misc/amd-sbi/tsi.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-or-later
 /*
- * tsi.c - AMD SBTSI I2C core driver. Probes the SBTSI device over I2C
+ * tsi.c - AMD SBTSI I2C/I3C core driver. Probes the SBTSI device over I2C/I3C
  *         and publishes an auxiliary device on the auxiliary bus.
  *
  * Copyright (C) 2026 Advanced Micro Devices, Inc.
@@ -89,6 +89,7 @@ static int sbtsi_i2c_probe(struct i2c_client *client)
 	if (!data)
 		return -ENOMEM;
 
+	data->is_i3c = false;
 	data->client = client;
 	err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG);
 	if (err < 0)
@@ -123,7 +124,61 @@ static struct i2c_driver sbtsi_driver = {
 	.id_table = sbtsi_id,
 };
 
-module_i2c_driver(sbtsi_driver);
+static int sbtsi_i3c_probe(struct i3c_device *i3cdev)
+{
+	struct device *dev = i3cdev_to_dev(i3cdev);
+	struct sbtsi_data *data;
+	int err;
+	u8 val;
+
+	/*
+	 * AMD OOB devices differ on basis of Instance ID,
+	 * for SBTSI, instance ID is 0.
+	 * As the device Id match is not on basis of Instance ID,
+	 * add the below check to probe the SBTSI device only and
+	 * not other OOB devices.
+	 */
+	if (I3C_PID_INSTANCE_ID(i3cdev->desc->info.pid) != 0)
+		return -ENXIO;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->i3cdev = i3cdev;
+	data->is_i3c = true;
+
+	err = sbtsi_xfer(data, SBTSI_REG_CONFIG, &val, true);
+	if (err)
+		return err;
+
+	data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), val);
+	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), val);
+
+	dev_set_drvdata(dev, data);
+	return sbtsi_create_hwmon_adev(dev, i3cdev->desc->info.dyn_addr);
+}
+
+static const struct i3c_device_id sbtsi_i3c_id[] = {
+	/* PID for AMD SBTSI device */
+	I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x1, NULL),
+	I3C_DEVICE_EXTRA_INFO(0x0, 0x0, 0x118, NULL),	/* Socket:0, Venice */
+	I3C_DEVICE_EXTRA_INFO(0x0, 0x100, 0x118, NULL),	/* Socket:1, Venice */
+	I3C_DEVICE_EXTRA_INFO(0x112, 0x0, 0x119, NULL),	/* Socket:0, Venice */
+	I3C_DEVICE_EXTRA_INFO(0x112, 0x100, 0x119, NULL),	/* Socket:1, Venice */
+	{}
+};
+MODULE_DEVICE_TABLE(i3c, sbtsi_i3c_id);
+
+static struct i3c_driver sbtsi_i3c_driver = {
+	.driver = {
+		.name = "sbtsi-i3c",
+	},
+	.probe = sbtsi_i3c_probe,
+	.id_table = sbtsi_i3c_id,
+};
+
+module_i3c_i2c_driver(sbtsi_i3c_driver, &sbtsi_driver);
 
-MODULE_DESCRIPTION("AMD SB-TSI I2C core driver");
+MODULE_DESCRIPTION("AMD SB-TSI I2C/I3C core driver");
 MODULE_LICENSE("GPL");
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
index 8f8cb90c2023..7ce689081427 100644
--- a/include/linux/misc/tsi.h
+++ b/include/linux/misc/tsi.h
@@ -9,18 +9,26 @@
 #define _LINUX_TSI_H_
 
 #include <linux/i2c.h>
+#include <linux/i3c/device.h>
+#include <linux/i3c/master.h>
 #include <linux/types.h>
 
 /**
  * struct sbtsi_data - driver private data for an AMD SB-TSI device
  * @client:	underlying I2C client
+ * @i3cdev:	underlying I3C device (when using I3C bus)
  * @ext_range_mode:	sensor uses extended temperature range
  * @read_order:	if set, decimal part must be read before integer part
+ * @is_i3c:	true when the device is accessed over I3C
  */
 struct sbtsi_data {
-	struct i2c_client *client;
+	union {
+		struct i2c_client *client;
+		struct i3c_device *i3cdev;
+	};
 	bool ext_range_mode;
 	bool read_order;
+	bool is_i3c;
 };
 
 /*
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 5/6] misc: amd-sbi: Add SBTSI ioctl register transfer interface
From: Akshay Gupta @ 2026-05-15 13:45 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, akshay.gupta,
	naveenkrishna.chatradhi, Prathima.Lk, Anand.Umarji, Kevin.Tung,
	Akshay Gupta
In-Reply-To: <20260515134506.397649-1-Akshay.Gupta@amd.com>

From: Prathima <Prathima.Lk@amd.com>

Implement IOCTL interface for SB-TSI driver to enable userspace access
to TSI register read/write operations through the AMD Advanced Platform
Management Link (APML) protocol.
Add an ioctl command (SBTSI_IOCTL_REG_XFER_CMD) that accepts a register
address, data byte, and direction flag. Serialize access with a mutex
shared between the hwmon and ioctl paths to prevent concurrent bus
transactions from corrupting register state.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v1:
- Use of devm_mutex_init in place of mutex_init
- Use of guard_mutex in place of mutex_lock()/mutex_unlock()
- Use of devm_add_action_or_reset() for clean removal
 
 drivers/hwmon/sbtsi_temp.c      |  6 +++
 drivers/misc/amd-sbi/tsi-core.c | 84 ++++++++++++++++++++++++++++++++-
 drivers/misc/amd-sbi/tsi-core.h | 15 ++++++
 drivers/misc/amd-sbi/tsi.c      | 20 ++++++--
 include/linux/misc/tsi.h        |  8 ++++
 include/uapi/misc/amd-apml.h    | 23 +++++++++
 6 files changed, 151 insertions(+), 5 deletions(-)
 create mode 100644 drivers/misc/amd-sbi/tsi-core.h

diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index d7ae986d824c..00e982f4c716 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -64,12 +64,15 @@ static inline void sbtsi_mc_to_reg(s32 temp, u8 *integer, u8 *decimal)
 /*
  * Read integer and decimal parts of an SB-TSI temperature register pair
  * The read order is determined by the ReadOrder bit to ensure atomic latching.
+ * The mutex protects against concurrent access to the shared I2C/I3C bus by
+ * the hwmon sysfs and a userspace ioctl
  */
 static int sbtsi_temp_read(struct sbtsi_data *data, u8 reg1, u8 reg2,
 			   u8 *val1, u8 *val2)
 {
 	int ret;
 
+	guard(mutex)(&data->lock);
 	ret = sbtsi_xfer(data, reg1, val1, true);
 	if (!ret)
 		ret = sbtsi_xfer(data, reg2, val2, true);
@@ -78,12 +81,15 @@ static int sbtsi_temp_read(struct sbtsi_data *data, u8 reg1, u8 reg2,
 
 /*
  * Write integer and decimal parts of an SB-TSI temperature register pair.
+ * The mutex protects against concurrent access to the shared I2C/I3C bus by
+ * the hwmon sysfs and a userspace ioctl
  */
 static int sbtsi_temp_write(struct sbtsi_data *data, u8 reg_int, u8 reg_dec,
 			    u8 val_int, u8 val_dec)
 {
 	int ret;
 
+	guard(mutex)(&data->lock);
 	ret = sbtsi_xfer(data, reg_int, &val_int, false);
 	if (!ret)
 		ret = sbtsi_xfer(data, reg_dec, &val_dec, false);
diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
index 19388737b225..c5bd60409d5b 100644
--- a/drivers/misc/amd-sbi/tsi-core.c
+++ b/drivers/misc/amd-sbi/tsi-core.c
@@ -6,8 +6,12 @@
  * Copyright (C) 2026 Advanced Micro Devices, Inc.
  */
 
+#include <linux/fs.h>
+#include <linux/ioctl.h>
 #include <linux/module.h>
-#include <linux/misc/tsi.h>
+#include <linux/uaccess.h>
+#include <uapi/misc/amd-apml.h>
+#include "tsi-core.h"
 
 /* I2C transfer function */
 static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
@@ -62,7 +66,83 @@ int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
 	if (data->is_i3c)
 		return is_read ? sbtsi_i3c_read(data, reg, val)
 			       : sbtsi_i3c_write(data, reg, *val);
-
 	return sbtsi_i2c_xfer(data, reg, val, is_read);
 }
 EXPORT_SYMBOL_GPL(sbtsi_xfer);
+
+/*
+ * The mutex protects against concurrent access to the shared I2C/I3C bus by
+ * the hwmon sysfs and a userspace ioctl.
+ */
+static int sbtsi_xfer_ioctl(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
+{
+	guard(mutex)(&data->lock);
+	return sbtsi_xfer(data, reg, val, is_read);
+}
+
+static int apml_tsi_reg_xfer(struct sbtsi_data *data,
+			     struct apml_tsi_xfer_msg __user *arg)
+{
+	struct apml_tsi_xfer_msg msg = { 0 };
+	int ret;
+
+	if (copy_from_user(&msg, arg, sizeof(struct apml_tsi_xfer_msg)))
+		return -EFAULT;
+
+	ret = sbtsi_xfer_ioctl(data, msg.reg_addr, &msg.data_in_out, msg.rflag);
+
+	if (msg.rflag && !ret) {
+		if (copy_to_user(arg, &msg, sizeof(struct apml_tsi_xfer_msg)))
+			return -EFAULT;
+	}
+	return ret;
+}
+
+static long sbtsi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
+{
+	void __user *argp = (void __user *)arg;
+	struct sbtsi_data *data;
+
+	data = container_of(fp->private_data, struct sbtsi_data, sbtsi_misc_dev);
+	switch (cmd) {
+	case SBTSI_IOCTL_REG_XFER_CMD:
+		return apml_tsi_reg_xfer(data, argp);
+	default:
+		return -ENOTTY;
+	}
+}
+
+static const struct file_operations sbtsi_fops = {
+	.owner		= THIS_MODULE,
+	.unlocked_ioctl	= sbtsi_ioctl,
+	.compat_ioctl	= compat_ptr_ioctl,
+};
+
+static void sbtsi_misc_deregister(void *data)
+{
+	misc_deregister((struct miscdevice *)data);
+}
+
+int create_misc_tsi_device(struct sbtsi_data *data, struct device *dev)
+{
+	int ret;
+
+	data->sbtsi_misc_dev.name = devm_kasprintf(dev, GFP_KERNEL,
+						   "sbtsi-%x", data->dev_addr);
+	if (!data->sbtsi_misc_dev.name)
+		return -ENOMEM;
+	data->sbtsi_misc_dev.minor    = MISC_DYNAMIC_MINOR;
+	data->sbtsi_misc_dev.fops     = &sbtsi_fops;
+	data->sbtsi_misc_dev.parent   = dev;
+	data->sbtsi_misc_dev.nodename = devm_kasprintf(dev, GFP_KERNEL,
+						       "sbtsi-%x", data->dev_addr);
+	if (!data->sbtsi_misc_dev.nodename)
+		return -ENOMEM;
+	data->sbtsi_misc_dev.mode = 0600;
+
+	ret = misc_register(&data->sbtsi_misc_dev);
+	if (ret)
+		return ret;
+	return devm_add_action_or_reset(dev, sbtsi_misc_deregister,
+					&data->sbtsi_misc_dev);
+}
diff --git a/drivers/misc/amd-sbi/tsi-core.h b/drivers/misc/amd-sbi/tsi-core.h
new file mode 100644
index 000000000000..7bf967a09837
--- /dev/null
+++ b/drivers/misc/amd-sbi/tsi-core.h
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AMD SBTSI misc tsi device .
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _LINUX_TSI_CORE_H_
+#define _LINUX_TSI_CORE_H_
+
+#include <linux/misc/tsi.h>
+
+int create_misc_tsi_device(struct sbtsi_data *data, struct device *dev);
+
+#endif /* _LINUX_TSI_CORE_H_ */
diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
index 43bbac7faf08..6a9356740f4e 100644
--- a/drivers/misc/amd-sbi/tsi.c
+++ b/drivers/misc/amd-sbi/tsi.c
@@ -10,8 +10,8 @@
 #include <linux/bitfield.h>
 #include <linux/module.h>
 #include <linux/of.h>
-#include <linux/misc/tsi.h>
 #include <linux/slab.h>
+#include "tsi-core.h"
 
 #define SBTSI_REG_CONFIG		0x03 /* RO */
 
@@ -89,6 +89,9 @@ static int sbtsi_i2c_probe(struct i2c_client *client)
 	if (!data)
 		return -ENOMEM;
 
+	err = devm_mutex_init(dev, &data->lock);
+	if (err)
+		return err;
 	data->is_i3c = false;
 	data->client = client;
 	err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG);
@@ -98,7 +101,11 @@ static int sbtsi_i2c_probe(struct i2c_client *client)
 	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), err);
 
 	dev_set_drvdata(dev, data);
-	return sbtsi_create_hwmon_adev(dev, client->addr);
+	err = sbtsi_create_hwmon_adev(dev, client->addr);
+	if (err < 0)
+		return err;
+	data->dev_addr = client->addr;
+	return create_misc_tsi_device(data, dev);
 }
 
 static const struct i2c_device_id sbtsi_id[] = {
@@ -145,6 +152,9 @@ static int sbtsi_i3c_probe(struct i3c_device *i3cdev)
 	if (!data)
 		return -ENOMEM;
 
+	err = devm_mutex_init(dev, &data->lock);
+	if (err)
+		return err;
 	data->i3cdev = i3cdev;
 	data->is_i3c = true;
 
@@ -156,7 +166,11 @@ static int sbtsi_i3c_probe(struct i3c_device *i3cdev)
 	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), val);
 
 	dev_set_drvdata(dev, data);
-	return sbtsi_create_hwmon_adev(dev, i3cdev->desc->info.dyn_addr);
+	err = sbtsi_create_hwmon_adev(dev, i3cdev->desc->info.dyn_addr);
+	if (err < 0)
+		return err;
+	data->dev_addr = i3cdev->desc->info.dyn_addr;
+	return create_misc_tsi_device(data, dev);
 }
 
 static const struct i3c_device_id sbtsi_i3c_id[] = {
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
index 7ce689081427..184b1aa14f0a 100644
--- a/include/linux/misc/tsi.h
+++ b/include/linux/misc/tsi.h
@@ -11,12 +11,17 @@
 #include <linux/i2c.h>
 #include <linux/i3c/device.h>
 #include <linux/i3c/master.h>
+#include <linux/miscdevice.h>
+#include <linux/mutex.h>
 #include <linux/types.h>
 
 /**
  * struct sbtsi_data - driver private data for an AMD SB-TSI device
  * @client:	underlying I2C client
  * @i3cdev:	underlying I3C device (when using I3C bus)
+ * @sbtsi_misc_dev: miscdevice exposing ioctl interface at /dev/sbtsi-<addr>
+ * @lock:           mutex protecting concurrent access to the device
+ * @dev_addr:       I2C/I3C device address, used to name the misc device node
  * @ext_range_mode:	sensor uses extended temperature range
  * @read_order:	if set, decimal part must be read before integer part
  * @is_i3c:	true when the device is accessed over I3C
@@ -26,6 +31,9 @@ struct sbtsi_data {
 		struct i2c_client *client;
 		struct i3c_device *i3cdev;
 	};
+	struct miscdevice sbtsi_misc_dev;
+	struct mutex lock;	/* protects concurrent access to the device */
+	u8 dev_addr;
 	bool ext_range_mode;
 	bool read_order;
 	bool is_i3c;
diff --git a/include/uapi/misc/amd-apml.h b/include/uapi/misc/amd-apml.h
index 745b3338fc06..8a85f79b0938 100644
--- a/include/uapi/misc/amd-apml.h
+++ b/include/uapi/misc/amd-apml.h
@@ -73,6 +73,13 @@ struct apml_reg_xfer_msg {
 	__u8 rflag;
 };
 
+struct apml_tsi_xfer_msg {
+	__u8 reg_addr;		/* TSI register address offset */
+	__u8 data_in_out;	/* Register data for read/write */
+	__u8 rflag;		/* Register read or write */
+	__u8 pad;		/* Explicit padding */
+};
+
 /*
  * AMD sideband interface base IOCTL
  */
@@ -149,4 +156,20 @@ struct apml_reg_xfer_msg {
  */
 #define SBRMI_IOCTL_REG_XFER_CMD	_IOWR(SB_BASE_IOCTL_NR, 3, struct apml_reg_xfer_msg)
 
+/**
+ * DOC: SBTSI_IOCTL_REG_XFER_CMD
+ *
+ * @Parameters
+ *
+ * @struct apml_tsi_xfer_msg
+ *	Pointer to the &struct apml_tsi_xfer_msg that will contain the protocol
+ *	information
+ *
+ * @Description
+ * IOCTL command for APML TSI messages using generic _IOWR
+ * The IOCTL provides userspace access to AMD sideband TSI register xfer protocol
+ * - TSI protocol to read/write temperature sensor registers
+ */
+#define SBTSI_IOCTL_REG_XFER_CMD	_IOWR(SB_BASE_IOCTL_NR, 4, struct apml_tsi_xfer_msg)
+
 #endif /*_AMD_APML_H_*/
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 3/6] hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction
From: Akshay Gupta @ 2026-05-15 13:45 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, akshay.gupta,
	naveenkrishna.chatradhi, Prathima.Lk, Anand.Umarji, Kevin.Tung,
	Akshay Gupta
In-Reply-To: <20260515134506.397649-1-Akshay.Gupta@amd.com>

From: Prathima <Prathima.Lk@amd.com>

Move the I2C read/write byte operations from the sbtsi hwmon driver into
a common sbtsi_xfer() function in tsi-core.c.
This decouples the hwmon sensor driver from the underlying bus transport,
preparing for I3C support in a subsequent patch.
This patch does not introduce any functional changes. The updates are limited
to code organization/cleanup and should not affect the runtime
behavior of the driver

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v1:
- New patch

 drivers/hwmon/sbtsi_temp.c      | 17 ++++++-----------
 drivers/misc/amd-sbi/Makefile   |  2 +-
 drivers/misc/amd-sbi/tsi-core.c | 30 ++++++++++++++++++++++++++++++
 include/linux/misc/tsi.h        | 13 +++++++++++++
 4 files changed, 50 insertions(+), 12 deletions(-)
 create mode 100644 drivers/misc/amd-sbi/tsi-core.c

diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index 078f4ab25bde..d7ae986d824c 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -70,15 +70,10 @@ static int sbtsi_temp_read(struct sbtsi_data *data, u8 reg1, u8 reg2,
 {
 	int ret;
 
-	ret = i2c_smbus_read_byte_data(data->client, reg1);
-	if (ret < 0)
-		return ret;
-	*val1 = ret;
-	ret = i2c_smbus_read_byte_data(data->client, reg2);
-	if (ret < 0)
-		return ret;
-	*val2 = ret;
-	return 0;
+	ret = sbtsi_xfer(data, reg1, val1, true);
+	if (!ret)
+		ret = sbtsi_xfer(data, reg2, val2, true);
+	return ret;
 }
 
 /*
@@ -89,9 +84,9 @@ static int sbtsi_temp_write(struct sbtsi_data *data, u8 reg_int, u8 reg_dec,
 {
 	int ret;
 
-	ret = i2c_smbus_write_byte_data(data->client, reg_int, val_int);
+	ret = sbtsi_xfer(data, reg_int, &val_int, false);
 	if (!ret)
-		ret = i2c_smbus_write_byte_data(data->client, reg_dec, val_dec);
+		ret = sbtsi_xfer(data, reg_dec, &val_dec, false);
 	return ret;
 }
 
diff --git a/drivers/misc/amd-sbi/Makefile b/drivers/misc/amd-sbi/Makefile
index 28f95b9e204f..ce9321f5c601 100644
--- a/drivers/misc/amd-sbi/Makefile
+++ b/drivers/misc/amd-sbi/Makefile
@@ -3,5 +3,5 @@ sbrmi-i2c-objs  		+= rmi-i2c.o rmi-core.o
 sbrmi-i2c-$(CONFIG_AMD_SBRMI_HWMON)	+= rmi-hwmon.o
 obj-$(CONFIG_AMD_SBRMI_I2C)	+= sbrmi-i2c.o
 # SBTSI Configuration
-sbtsi-objs	+= tsi.o
+sbtsi-objs	+= tsi.o tsi-core.o
 obj-$(CONFIG_AMD_SBTSI)	+= sbtsi.o
diff --git a/drivers/misc/amd-sbi/tsi-core.c b/drivers/misc/amd-sbi/tsi-core.c
new file mode 100644
index 000000000000..6ef1831515bb
--- /dev/null
+++ b/drivers/misc/amd-sbi/tsi-core.c
@@ -0,0 +1,30 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * tsi-core.c - file defining SB-TSI protocols compliant
+ *              AMD SoC device.
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/module.h>
+#include <linux/misc/tsi.h>
+
+/* I2C transfer function */
+static int sbtsi_i2c_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
+{
+	if (is_read) {
+		int ret = i2c_smbus_read_byte_data(data->client, reg);
+
+		if (ret < 0)
+			return ret;
+		*val = ret;
+		return 0;
+	}
+	return i2c_smbus_write_byte_data(data->client, reg, *val);
+}
+
+int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read)
+{
+	return sbtsi_i2c_xfer(data, reg, val, is_read);
+}
+EXPORT_SYMBOL_GPL(sbtsi_xfer);
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
index 6f7177edbcf5..8f8cb90c2023 100644
--- a/include/linux/misc/tsi.h
+++ b/include/linux/misc/tsi.h
@@ -31,4 +31,17 @@ struct sbtsi_data {
 #define AMD_SBTSI_ADEV		"amd-sbtsi"
 #define AMD_SBTSI_AUX_HWMON	"temp-sensor"
 
+/**
+ * sbtsi_xfer - Perform a register read or write transfer on an AMD SB-TSI device.
+ *
+ * @data:    Pointer to the sbtsi_data structure containing the device context
+ * @reg:     Register address to access.
+ * @val:     Pointer to the value to read into or write from.
+ * @is_read: If true, performs a read transfer and stores the result in @val.
+ *           If false, performs a write transfer using the value in @val.
+ *
+ * Returns 0 on success, or a negative error code on failure.
+ */
+int sbtsi_xfer(struct sbtsi_data *data, u8 reg, u8 *val, bool is_read);
+
 #endif /* _LINUX_TSI_H_ */
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 2/6] hwmon: sbtsi_temp: Refactor temperature register access into helpers
From: Akshay Gupta @ 2026-05-15 13:45 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, akshay.gupta,
	naveenkrishna.chatradhi, Prathima.Lk, Anand.Umarji, Kevin.Tung,
	Akshay Gupta
In-Reply-To: <20260515134506.397649-1-Akshay.Gupta@amd.com>

From: Prathima <Prathima.Lk@amd.com>

Extract the paired integer/decimal register reads and writes from the
hwmon read/write callbacks into sbtsi_temp_read() and sbtsi_temp_write()
helpers. This consolidates error handling and respects the ReadOrder bit
for atomic temperature latching.

This keeps register access independent while preserving existing hwmon
functionality.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v1:
- New patch

 drivers/hwmon/sbtsi_temp.c | 84 +++++++++++++++++++++++++++-----------
 1 file changed, 61 insertions(+), 23 deletions(-)

diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index 28258bf49922..078f4ab25bde 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -61,40 +61,82 @@ static inline void sbtsi_mc_to_reg(s32 temp, u8 *integer, u8 *decimal)
 	*decimal = (temp & 0x7) << 5;
 }
 
+/*
+ * Read integer and decimal parts of an SB-TSI temperature register pair
+ * The read order is determined by the ReadOrder bit to ensure atomic latching.
+ */
+static int sbtsi_temp_read(struct sbtsi_data *data, u8 reg1, u8 reg2,
+			   u8 *val1, u8 *val2)
+{
+	int ret;
+
+	ret = i2c_smbus_read_byte_data(data->client, reg1);
+	if (ret < 0)
+		return ret;
+	*val1 = ret;
+	ret = i2c_smbus_read_byte_data(data->client, reg2);
+	if (ret < 0)
+		return ret;
+	*val2 = ret;
+	return 0;
+}
+
+/*
+ * Write integer and decimal parts of an SB-TSI temperature register pair.
+ */
+static int sbtsi_temp_write(struct sbtsi_data *data, u8 reg_int, u8 reg_dec,
+			    u8 val_int, u8 val_dec)
+{
+	int ret;
+
+	ret = i2c_smbus_write_byte_data(data->client, reg_int, val_int);
+	if (!ret)
+		ret = i2c_smbus_write_byte_data(data->client, reg_dec, val_dec);
+	return ret;
+}
+
 static int sbtsi_read(struct device *dev, enum hwmon_sensor_types type,
 		      u32 attr, int channel, long *val)
 {
 	struct sbtsi_data *data = dev_get_drvdata(dev);
 	s32 temp_int, temp_dec;
+	int err;
+	u8 val_int, val_dec;
 
 	switch (attr) {
 	case hwmon_temp_input:
-		if (data->read_order) {
-			temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC);
-			temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT);
-		} else {
-			temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_INT);
-			temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_DEC);
-		}
+		if (data->read_order)
+			err = sbtsi_temp_read(data,
+					      SBTSI_REG_TEMP_DEC, SBTSI_REG_TEMP_INT,
+					      &val_dec, &val_int);
+		else
+			err = sbtsi_temp_read(data,
+					      SBTSI_REG_TEMP_INT, SBTSI_REG_TEMP_DEC,
+					      &val_int, &val_dec);
+		if (err < 0)
+			return err;
 		break;
 	case hwmon_temp_max:
-		temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_INT);
-		temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_HIGH_DEC);
+		err = sbtsi_temp_read(data,
+				      SBTSI_REG_TEMP_HIGH_INT, SBTSI_REG_TEMP_HIGH_DEC,
+				      &val_int, &val_dec);
+		if (err < 0)
+			return err;
 		break;
 	case hwmon_temp_min:
-		temp_int = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_INT);
-		temp_dec = i2c_smbus_read_byte_data(data->client, SBTSI_REG_TEMP_LOW_DEC);
+		err = sbtsi_temp_read(data,
+				      SBTSI_REG_TEMP_LOW_INT, SBTSI_REG_TEMP_LOW_DEC,
+				      &val_int, &val_dec);
+
+		if (err < 0)
+			return err;
 		break;
 	default:
 		return -EINVAL;
 	}
 
-
-	if (temp_int < 0)
-		return temp_int;
-	if (temp_dec < 0)
-		return temp_dec;
-
+	temp_int = val_int;
+	temp_dec = val_dec;
 	*val = sbtsi_reg_to_mc(temp_int, temp_dec);
 	if (data->ext_range_mode)
 		*val -= SBTSI_TEMP_EXT_RANGE_ADJ;
@@ -106,7 +148,7 @@ static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type,
 		       u32 attr, int channel, long val)
 {
 	struct sbtsi_data *data = dev_get_drvdata(dev);
-	int reg_int, reg_dec, err;
+	int reg_int, reg_dec;
 	u8 temp_int, temp_dec;
 
 	switch (attr) {
@@ -127,11 +169,7 @@ static int sbtsi_write(struct device *dev, enum hwmon_sensor_types type,
 	val = clamp_val(val, SBTSI_TEMP_MIN, SBTSI_TEMP_MAX);
 	sbtsi_mc_to_reg(val, &temp_int, &temp_dec);
 
-	err = i2c_smbus_write_byte_data(data->client, reg_int, temp_int);
-	if (err)
-		return err;
-
-	return i2c_smbus_write_byte_data(data->client, reg_dec, temp_dec);
+	return sbtsi_temp_write(data, reg_int, reg_dec, temp_int, temp_dec);
 }
 
 static umode_t sbtsi_is_visible(const void *data,
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 1/6] hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc
From: Akshay Gupta @ 2026-05-15 13:45 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, akshay.gupta,
	naveenkrishna.chatradhi, Prathima.Lk, Anand.Umarji, Kevin.Tung,
	Akshay Gupta
In-Reply-To: <20260515134506.397649-1-Akshay.Gupta@amd.com>

From: Prathima <Prathima.Lk@amd.com>

Move SBTSI(Side-Band Temperature Sensor Interface) core functionality out
of the hwmon-only path and into drivers/misc/amd-sbi so it can be reused
by non-hwmon consumers.

I2C probe parsing is moved from drivers/hwmon/sbtsi_temp.c
into drivers/misc/amd-sbi/tsi.c under CONFIG_AMD_SBTSI. The core driver
stores struct sbtsi_data on the bus device and registers an auxiliary
device amd-sbtsi.temp-sensor.<addr> per target.

This split prepares the driver for additional interfaces while keeping
hwmon support in hwmon subsystem on top of common SBTSI core logic.

Reviewed-by: Akshay Gupta <Akshay.Gupta@amd.com>
Signed-off-by: Prathima <Prathima.Lk@amd.com>
---
Changes since v1:
- Use auxiliary device to probe hwmon sensor instead of moving
  the hwmon functionality to misc subsystem. This change is as
  per feedback.

 drivers/hwmon/Kconfig         |   2 +-
 drivers/hwmon/sbtsi_temp.c    |  73 ++++---------------
 drivers/misc/amd-sbi/Kconfig  |  13 ++++
 drivers/misc/amd-sbi/Makefile |   3 +
 drivers/misc/amd-sbi/tsi.c    | 129 ++++++++++++++++++++++++++++++++++
 include/linux/misc/tsi.h      |  34 +++++++++
 6 files changed, 194 insertions(+), 60 deletions(-)
 create mode 100644 drivers/misc/amd-sbi/tsi.c
 create mode 100644 include/linux/misc/tsi.h

diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 14e4cea48acc..6fa51e6ef6ff 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1939,7 +1939,7 @@ config SENSORS_SL28CPLD
 
 config SENSORS_SBTSI
 	tristate "Emulated SB-TSI temperature sensor"
-	depends on I2C
+	depends on AMD_SBTSI
 	help
 	  If you say yes here you get support for emulated temperature
 	  sensors on AMD SoCs with SB-TSI interface connected to a BMC device.
diff --git a/drivers/hwmon/sbtsi_temp.c b/drivers/hwmon/sbtsi_temp.c
index c5b2488c4c7f..28258bf49922 100644
--- a/drivers/hwmon/sbtsi_temp.c
+++ b/drivers/hwmon/sbtsi_temp.c
@@ -7,13 +7,12 @@
  * Copyright (c) 2020, Kun Yi <kunyi@google.com>
  */
 
+#include <linux/auxiliary_bus.h>
 #include <linux/err.h>
-#include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/hwmon.h>
+#include <linux/init.h>
 #include <linux/module.h>
-#include <linux/of.h>
-#include <linux/bitfield.h>
+#include <linux/misc/tsi.h>
 
 /*
  * SB-TSI registers only support SMBus byte data access. "_INT" registers are
@@ -22,39 +21,17 @@
  */
 #define SBTSI_REG_TEMP_INT		0x01 /* RO */
 #define SBTSI_REG_STATUS		0x02 /* RO */
-#define SBTSI_REG_CONFIG		0x03 /* RO */
 #define SBTSI_REG_TEMP_HIGH_INT		0x07 /* RW */
 #define SBTSI_REG_TEMP_LOW_INT		0x08 /* RW */
 #define SBTSI_REG_TEMP_DEC		0x10 /* RW */
 #define SBTSI_REG_TEMP_HIGH_DEC		0x13 /* RW */
 #define SBTSI_REG_TEMP_LOW_DEC		0x14 /* RW */
 
-/*
- * Bit for reporting value with temperature measurement range.
- * bit == 0: Use default temperature range (0C to 255.875C).
- * bit == 1: Use extended temperature range (-49C to +206.875C).
- */
-#define SBTSI_CONFIG_EXT_RANGE_SHIFT	2
-/*
- * ReadOrder bit specifies the reading order of integer and decimal part of
- * CPU temperature for atomic reads. If bit == 0, reading integer part triggers
- * latching of the decimal part, so integer part should be read first.
- * If bit == 1, read order should be reversed.
- */
-#define SBTSI_CONFIG_READ_ORDER_SHIFT	5
-
 #define SBTSI_TEMP_EXT_RANGE_ADJ	49000
 
 #define SBTSI_TEMP_MIN	0
 #define SBTSI_TEMP_MAX	255875
 
-/* Each client has this additional data */
-struct sbtsi_data {
-	struct i2c_client *client;
-	bool ext_range_mode;
-	bool read_order;
-};
-
 /*
  * From SB-TSI spec: CPU temperature readings and limit registers encode the
  * temperature in increments of 0.125 from 0 to 255.875. The "high byte"
@@ -195,55 +172,33 @@ static const struct hwmon_chip_info sbtsi_chip_info = {
 	.info = sbtsi_info,
 };
 
-static int sbtsi_probe(struct i2c_client *client)
+static int sbtsi_probe(struct auxiliary_device *adev,
+		       const struct auxiliary_device_id *id)
 {
-	struct device *dev = &client->dev;
+	struct sbtsi_data *data = dev_get_drvdata(adev->dev.parent);
+	struct device *dev = &adev->dev;
 	struct device *hwmon_dev;
-	struct sbtsi_data *data;
-	int err;
 
-	data = devm_kzalloc(dev, sizeof(struct sbtsi_data), GFP_KERNEL);
-	if (!data)
-		return -ENOMEM;
-
-	data->client = client;
-
-	err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG);
-	if (err < 0)
-		return err;
-	data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), err);
-	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), err);
-
-	hwmon_dev = devm_hwmon_device_register_with_info(dev, client->name, data,
+	hwmon_dev = devm_hwmon_device_register_with_info(dev, "sbtsi", data,
 							 &sbtsi_chip_info, NULL);
 
 	return PTR_ERR_OR_ZERO(hwmon_dev);
 }
 
-static const struct i2c_device_id sbtsi_id[] = {
-	{"sbtsi"},
-	{}
+static const struct auxiliary_device_id sbtsi_id[] = {
+	{ .name = AMD_SBTSI_ADEV "." AMD_SBTSI_AUX_HWMON },
+	{ }
 };
-MODULE_DEVICE_TABLE(i2c, sbtsi_id);
+MODULE_DEVICE_TABLE(auxiliary, sbtsi_id);
 
-static const struct of_device_id __maybe_unused sbtsi_of_match[] = {
-	{
-		.compatible = "amd,sbtsi",
-	},
-	{ },
-};
-MODULE_DEVICE_TABLE(of, sbtsi_of_match);
-
-static struct i2c_driver sbtsi_driver = {
+static struct auxiliary_driver sbtsi_driver = {
 	.driver = {
 		.name = "sbtsi",
-		.of_match_table = of_match_ptr(sbtsi_of_match),
 	},
 	.probe = sbtsi_probe,
 	.id_table = sbtsi_id,
 };
-
-module_i2c_driver(sbtsi_driver);
+module_auxiliary_driver(sbtsi_driver);
 
 MODULE_AUTHOR("Kun Yi <kunyi@google.com>");
 MODULE_DESCRIPTION("Hwmon driver for AMD SB-TSI emulated sensor");
diff --git a/drivers/misc/amd-sbi/Kconfig b/drivers/misc/amd-sbi/Kconfig
index 30e7fad7356c..512251690e0e 100644
--- a/drivers/misc/amd-sbi/Kconfig
+++ b/drivers/misc/amd-sbi/Kconfig
@@ -20,3 +20,16 @@ config AMD_SBRMI_HWMON
 	  This provides support for RMI device hardware monitoring. If enabled,
 	  a hardware monitoring device will be created for each socket in
 	  the system.
+
+config AMD_SBTSI
+	tristate "AMD side band TSI support"
+	depends on I2C
+	depends on ARM || ARM64 || COMPILE_TEST
+	select AUXILIARY_BUS
+	help
+	  Enables support for the AMD SB-TSI (Side Band Temperature Sensor
+	  Interface) driver, which provides access to emulated CPU temperature
+	  sensors on AMD SoCs via an I2C connected BMC device.
+
+	  This driver can also be built as a module. If so, the module will
+	  be called sbtsi.
diff --git a/drivers/misc/amd-sbi/Makefile b/drivers/misc/amd-sbi/Makefile
index 38eaaa651fd9..28f95b9e204f 100644
--- a/drivers/misc/amd-sbi/Makefile
+++ b/drivers/misc/amd-sbi/Makefile
@@ -2,3 +2,6 @@
 sbrmi-i2c-objs  		+= rmi-i2c.o rmi-core.o
 sbrmi-i2c-$(CONFIG_AMD_SBRMI_HWMON)	+= rmi-hwmon.o
 obj-$(CONFIG_AMD_SBRMI_I2C)	+= sbrmi-i2c.o
+# SBTSI Configuration
+sbtsi-objs	+= tsi.o
+obj-$(CONFIG_AMD_SBTSI)	+= sbtsi.o
diff --git a/drivers/misc/amd-sbi/tsi.c b/drivers/misc/amd-sbi/tsi.c
new file mode 100644
index 000000000000..ee2216785550
--- /dev/null
+++ b/drivers/misc/amd-sbi/tsi.c
@@ -0,0 +1,129 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * tsi.c - AMD SBTSI I2C core driver. Probes the SBTSI device over I2C
+ *         and publishes an auxiliary device on the auxiliary bus.
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#include <linux/auxiliary_bus.h>
+#include <linux/bitfield.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/misc/tsi.h>
+#include <linux/slab.h>
+
+#define SBTSI_REG_CONFIG		0x03 /* RO */
+
+/*
+ * Bit for reporting value with temperature measurement range.
+ * bit == 0: Use default temperature range (0C to 255.875C).
+ * bit == 1: Use extended temperature range (-49C to +206.875C).
+ */
+#define SBTSI_CONFIG_EXT_RANGE_SHIFT	2
+
+/*
+ * ReadOrder bit specifies the reading order of integer and decimal part of
+ * CPU temperature for atomic reads. If bit == 0, reading integer part triggers
+ * latching of the decimal part, so integer part should be read first.
+ */
+#define SBTSI_CONFIG_READ_ORDER_SHIFT	5
+
+static void sbtsi_adev_release(struct device *dev)
+{
+	kfree(to_auxiliary_dev(dev));
+}
+
+static void sbtsi_unregister_hwmon_adev(void *_adev)
+{
+	struct auxiliary_device *adev = _adev;
+
+	auxiliary_device_delete(adev);
+	auxiliary_device_uninit(adev);
+}
+
+/*
+ * Create and publish an auxiliary device. The hwmon driver in
+ * drivers/hwmon/sbtsi_temp.c binds to this device.
+ *
+ * @dev:      I2C device (parent of the auxiliary device)
+ * @dev_addr: I2C address — used as the auxiliary device instance ID so that
+ *            each socket gets a unique name.
+ */
+static int sbtsi_create_hwmon_adev(struct device *dev, u8 dev_addr)
+{
+	struct auxiliary_device *adev;
+	int ret;
+
+	adev = kzalloc_obj(*adev);
+	if (!adev)
+		return -ENOMEM;
+
+	adev->name = AMD_SBTSI_AUX_HWMON;
+	adev->id = dev_addr;
+	adev->dev.parent = dev;
+	adev->dev.release = sbtsi_adev_release;
+
+	ret = auxiliary_device_init(adev);
+	if (ret) {
+		kfree(adev);
+		return ret;
+	}
+
+	ret = __auxiliary_device_add(adev, AMD_SBTSI_ADEV);
+	if (ret) {
+		auxiliary_device_uninit(adev);
+		return ret;
+	}
+
+	return devm_add_action_or_reset(dev, sbtsi_unregister_hwmon_adev, adev);
+}
+
+static int sbtsi_i2c_probe(struct i2c_client *client)
+{
+	struct device *dev = &client->dev;
+	struct sbtsi_data *data;
+	int err;
+
+	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->client = client;
+	err = i2c_smbus_read_byte_data(data->client, SBTSI_REG_CONFIG);
+	if (err < 0)
+		return err;
+	data->ext_range_mode = FIELD_GET(BIT(SBTSI_CONFIG_EXT_RANGE_SHIFT), err);
+	data->read_order = FIELD_GET(BIT(SBTSI_CONFIG_READ_ORDER_SHIFT), err);
+
+	dev_set_drvdata(dev, data);
+	return sbtsi_create_hwmon_adev(dev, client->addr);
+}
+
+static const struct i2c_device_id sbtsi_id[] = {
+	{"sbtsi"},
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, sbtsi_id);
+
+static const struct of_device_id __maybe_unused sbtsi_of_match[] = {
+	{
+		.compatible = "amd,sbtsi",
+	},
+	{ },
+};
+MODULE_DEVICE_TABLE(of, sbtsi_of_match);
+
+static struct i2c_driver sbtsi_driver = {
+	.driver = {
+		.name = "sbtsi-i2c",
+		.of_match_table = of_match_ptr(sbtsi_of_match),
+	},
+	.probe = sbtsi_i2c_probe,
+	.id_table = sbtsi_id,
+};
+
+module_i2c_driver(sbtsi_driver);
+
+MODULE_DESCRIPTION("AMD SB-TSI I2C core driver");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/misc/tsi.h b/include/linux/misc/tsi.h
new file mode 100644
index 000000000000..6f7177edbcf5
--- /dev/null
+++ b/include/linux/misc/tsi.h
@@ -0,0 +1,34 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * AMD SBTSI shared data structure and auxiliary bus definitions.
+ *
+ * Copyright (C) 2026 Advanced Micro Devices, Inc.
+ */
+
+#ifndef _LINUX_TSI_H_
+#define _LINUX_TSI_H_
+
+#include <linux/i2c.h>
+#include <linux/types.h>
+
+/**
+ * struct sbtsi_data - driver private data for an AMD SB-TSI device
+ * @client:	underlying I2C client
+ * @ext_range_mode:	sensor uses extended temperature range
+ * @read_order:	if set, decimal part must be read before integer part
+ */
+struct sbtsi_data {
+	struct i2c_client *client;
+	bool ext_range_mode;
+	bool read_order;
+};
+
+/*
+ * Name of the auxiliary device published on the auxiliary bus by the core
+ * driver.  The full device name is "amd-sbtsi.temp-sensor.<id>". where
+ * <id> is the auxiliary device instance id.
+ */
+#define AMD_SBTSI_ADEV		"amd-sbtsi"
+#define AMD_SBTSI_AUX_HWMON	"temp-sensor"
+
+#endif /* _LINUX_TSI_H_ */
-- 
2.34.1


^ permalink raw reply related

* [PATCH v2 0/6] misc: amd-sbi: Refactor SBTSI driver with I3C support and ioctl interface
From: Akshay Gupta @ 2026-05-15 13:45 UTC (permalink / raw)
  To: linux-doc, linux-kernel, linux-hwmon
  Cc: corbet, skhan, linux, arnd, gregkh, akshay.gupta,
	naveenkrishna.chatradhi, Prathima.Lk, Anand.Umarji, Kevin.Tung,
	Akshay Gupta

This series refactors the AMD SB-TSI (Side-Band Temperature Sensor
Interface) driver by moving the core from the hwmon subsystem into the
drivers/misc/amd-sbi framework, alongside the existing SB-RMI driver.
Registers an auxiliary device keeping hwmon sensors functionality intact. 

Background:
The SB-TSI driver currently lives under drivers/hwmon/sbtsi_temp.c and
is limited to exposing temperature readings via the hwmon interface.
As AMD platforms evolve, SB-TSI access is required from multiple
consumers (hwmon, userspace via ioctl, I3C-attached devices), making
the hwmon-only placement insufficient.

This series restructures the driver into a layered design:

  - tsi-core.c   : core register access and ioctl/miscdevice support
  - tsi.c        : I2C/I3C probe and glue
  - sbtsi_temp.c : hwmon sensor layer built on top of the core using aux device

Changes in this series:
1. Move core SBTSI driver probe from drivers/hwmon into drivers/misc/amd-sbi,
   and registering an auxiliary device in core for hwmon subsystem probing

2. Register order follows the device ReadOrder bit so both parts latch atomically;
   limit registers (temp / temp1_max / temp1_min) use the same helpers instead of
   separate SMBus calls. 

3. Move sbtsi register transfer to core abstraction to decouple the hwmon sensor
   driver from the underlying bus transport. Preparing for I3C support in a
   subsequent patch

4. Extend the driver to support SB-TSI over I3C in addition to I2C.
   Both buses share the same core read/write path via sbtsi_xfer();
   the is_i3c flag selects the underlying transport at probe time.
   Backward compatibility with existing I2C deployments is maintained.

5. Add a miscdevice (/dev/sbtsi-<addr>) and an ioctl interface
   (SBTSI_IOCTL_REG_XFER_CMD) that allows root userspace to perform
   SB-TSI register read/write operations through the APML protocol,
   consistent with the existing SBRMI ioctl interface.

6. Document the new SBTSI miscdevice and its ioctl in
   Documentation/misc-devices/amd-sbi.rst.

Testing:
Tested on AMD Genoa/Turin/Venice BMC platforms with both I2C and I3C-attached
SB-TSI targets. hwmon sysfs attributes (tempX_input, tempX_max, etc.)
and ioctl register transfers verified against hardware.

Prathima (6):
  hwmon/misc: amd-sbi: Move core sbtsi support from hwmon to misc
  hwmon: sbtsi_temp: Refactor temperature register access into helpers
  hwmon/misc: amd-sbi: Move sbtsi register transfer to core abstraction
  misc: amd-sbi: Add support for SB-TSI over I3C
  misc: amd-sbi: Add SBTSI ioctl register transfer interface
  docs: misc: amd-sbi: Document SBTSI userspace interface

 Documentation/misc-devices/amd-sbi.rst |  64 ++++++++
 drivers/hwmon/Kconfig                  |   2 +-
 drivers/hwmon/sbtsi_temp.c             | 158 ++++++++++----------
 drivers/misc/amd-sbi/Kconfig           |  13 ++
 drivers/misc/amd-sbi/Makefile          |   3 +
 drivers/misc/amd-sbi/tsi-core.c        | 148 ++++++++++++++++++
 drivers/misc/amd-sbi/tsi-core.h        |  15 ++
 drivers/misc/amd-sbi/tsi.c             | 198 +++++++++++++++++++++++++
 include/linux/misc/tsi.h               |  63 ++++++++
 include/uapi/misc/amd-apml.h           |  23 +++
 10 files changed, 604 insertions(+), 83 deletions(-)
 create mode 100644 drivers/misc/amd-sbi/tsi-core.c
 create mode 100644 drivers/misc/amd-sbi/tsi-core.h
 create mode 100644 drivers/misc/amd-sbi/tsi.c
 create mode 100644 include/linux/misc/tsi.h

-- 
2.34.1


^ permalink raw reply

* Re: [PATCH v13 1/4] bug/kunit: Core support for suppressing warning backtraces
From: Albert Esteve @ 2026-05-15 13:36 UTC (permalink / raw)
  To: Arnd Bergmann, Brendan Higgins, David Gow, Rae Moar,
	Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Jonathan Corbet, Shuah Khan, Andrew Morton,
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti
  Cc: linux-kernel, linux-arch, linux-kselftest, kunit-dev, dri-devel,
	workflows, linux-riscv, linux-doc, peterz, Alessandro Carminati,
	Guenter Roeck, Kees Cook
In-Reply-To: <20260515-kunit_add_support-v13-1-18ee42f96e7b@redhat.com>

On Fri, May 15, 2026 at 2:29 PM Albert Esteve <aesteve@redhat.com> wrote:
>
> From: Alessandro Carminati <acarmina@redhat.com>
>
> Some unit tests intentionally trigger warning backtraces by passing bad
> parameters to kernel API functions. Such unit tests typically check the
> return value from such calls, not the existence of the warning backtrace.
>
> Such intentionally generated warning backtraces are neither desirable
> nor useful for a number of reasons:
> - They can result in overlooked real problems.
> - A warning that suddenly starts to show up in unit tests needs to be
>   investigated and has to be marked to be ignored, for example by
>   adjusting filter scripts. Such filters are ad hoc because there is
>   no real standard format for warnings. On top of that, such filter
>   scripts would require constant maintenance.
>
> Solve the problem by providing a means to suppress warning backtraces
> originating from the current kthread while executing test code. Since
> each KUnit test runs in its own kthread, this effectively scopes
> suppression to the test that enabled it. Limit changes to generic code
> to the absolute minimum.
>
> Implementation details:
> Suppression is integrated into the existing KUnit hooks infrastructure
> in test-bug.h, reusing the kunit_running static branch for zero
> overhead when no tests are running.
>
> Suppression is checked at three points in the warning path:
> - In warn_slowpath_fmt(), the check runs before any output, fully
>   suppressing both message and backtrace. This covers architectures
>   without __WARN_FLAGS.
> - In __warn_printk(), the check suppresses the warning message text.
>   This covers architectures that define __WARN_FLAGS but not their own
>   __WARN_printf (arm64, loongarch, parisc, powerpc, riscv, sh), where
>   the message is printed before the trap enters __report_bug().
> - In __report_bug(), the check runs before __warn() is called,
>   suppressing the backtrace and stack dump.
>
> To avoid double-counting on architectures where both __warn_printk()
> and __report_bug() run for the same warning, kunit_is_suppressed_warning()
> takes a bool parameter: true to increment the suppression counter
> (used in warn_slowpath_fmt and __report_bug), false to check only
> (used in __warn_printk).
>
> The suppression state is dynamically allocated via kunit_kzalloc() and
> tied to the KUnit test lifecycle via kunit_add_action(), ensuring
> automatic cleanup at test exit. On cleanup, the node is removed with
> list_del_rcu() followed by synchronize_rcu() to wait for any concurrent
> RCU readers to finish. Because kunit_end_suppress_warning() (and the
> __cleanup wrapper) always runs from process context, synchronize_rcu()
> is safe. The handle memory remains valid until the test exits, so the
> suppression count can be read after the scope closes. Writer-side
> access to the global suppression list is serialized with a spinlock;
> readers use RCU. To avoid false suppression of warnings fired from
> hardware interrupt handlers (where current still points to the test
> task), the check exits early when not in task context.
>
> Two API forms are provided:
> - kunit_warning_suppress(test) { ... }: scoped, uses __cleanup for
>   automatic teardown on scope exit, kunit_add_action() as safety net
>   for abnormal exits (e.g. kthread_exit from failed assertions).
>   Suppression handle is only accessible inside the block.
> - kunit_start/end_suppress_warning(test): direct functions returning
>   an explicit handle, for retaining the handle within the test,
>   or for cross-function usage.

Let me address sashiko's comments for
https://sashiko.dev/#/patchset/20260515-kunit_add_support-v13-0-18ee42f96e7b%40redhat.com?part=1
here:

1. "Is this assumption always accurate? Tests frequently acquire
spinlocks or RCU read locks."
The assumption is accurate because kunit_end_suppress_warning() and
the __cleanup wrapper fire at the closing brace of the
kunit_warning_suppress() scope. If a developer holds a spinlock or RCU
read lock when that scope closes, their test is structurally incorrect
regardless of this API. The API documentation notes that process
context is required.

2. "If kunit_start_suppress_warning() fails and returns NULL, will
this skip the entire loop body?"
Yes, intentionally. KUNIT_FAIL() is called before returning NULL, so
the test is already marked as failed at that point. Skipping the body
of a failed test is expected KUnit behavior. In patch 3,
scaling_factor is initialized to INT_MIN precisely for this reason.

3. "Does this mean the single-fire budget is consumed anyway on
non-CONFIG_GENERIC_BUG architectures?"
Yes, true, but it should only affect non-__WARN_FLAGS architectures.
If there is demand, it can be addressed in a follow-up series. It does
not affect current API users.

4. "Would GFP_KERNEL / synchronize_rcu() cause a sleep-in-atomic bug
if used in atomic context?"
Yes, and that would be a test design error. kunit_warning_suppress()
is a KUnit test API; KUnit tests run in process context by design. As
stated in `Documentation/core-api/memory-allocation.rst`, GFP_KERNEL
implies GFP_RECLAIM, which requires the calling context to be allowed
to sleep. Using it in an atomic context is incorrect regardless of
which API calls it. `kunit_kzalloc(test, ..., GFP_KERNEL)` is the
standard allocation pattern throughout KUnit itself (e.g.,
lib/kunit/assert_test.c, platform-test.c, ...), so this API follows
the same convention.

5. "Could a child kthread's task_struct be freed and reused, causing
false suppression?"
The API is designed to be called from the test task only. w->task =
current stores the caller's task_struct, and the inline comment
explains the stability guarantee: the test task cannot exit before
KUnit tears down the test. The correct pattern for child kthread is
demonstrated in backtrace_suppression_test_cross_kthread: the test
task opens and closes the suppression scope; child threads only read
the suppression state. Otherwise it is an API misuse.

>
> Signed-off-by: Guenter Roeck <linux@roeck-us.net>
> Signed-off-by: Alessandro Carminati <acarmina@redhat.com>
> Reviewed-by: Kees Cook <kees@kernel.org>
> Reviewed-by: David Gow <david@davidgow.net>
> Signed-off-by: Albert Esteve <aesteve@redhat.com>
> ---
>  include/kunit/test-bug.h |  26 ++++++++++
>  include/kunit/test.h     |  98 ++++++++++++++++++++++++++++++++++++
>  kernel/panic.c           |  11 ++++
>  lib/bug.c                |  12 ++++-
>  lib/kunit/Makefile       |   3 +-
>  lib/kunit/bug.c          | 127 +++++++++++++++++++++++++++++++++++++++++++++++
>  lib/kunit/hooks-impl.h   |   2 +
>  7 files changed, 276 insertions(+), 3 deletions(-)
>
> diff --git a/include/kunit/test-bug.h b/include/kunit/test-bug.h
> index 47aa8f21ccce8..99869029fc686 100644
> --- a/include/kunit/test-bug.h
> +++ b/include/kunit/test-bug.h
> @@ -10,6 +10,7 @@
>  #define _KUNIT_TEST_BUG_H
>
>  #include <linux/stddef.h> /* for NULL */
> +#include <linux/types.h>  /* for bool */
>
>  #if IS_ENABLED(CONFIG_KUNIT)
>
> @@ -23,6 +24,7 @@ DECLARE_STATIC_KEY_FALSE(kunit_running);
>  extern struct kunit_hooks_table {
>         __printf(3, 4) void (*fail_current_test)(const char*, int, const char*, ...);
>         void *(*get_static_stub_address)(struct kunit *test, void *real_fn_addr);
> +       bool (*is_suppressed_warning)(bool count);
>  } kunit_hooks;
>
>  /**
> @@ -60,9 +62,33 @@ static inline struct kunit *kunit_get_current_test(void)
>                 }                                                               \
>         } while (0)
>
> +/**
> + * kunit_is_suppressed_warning() - Check if warnings are being suppressed
> + *                                 by the current KUnit test.
> + * @count: if true, increment the suppression counter on match.
> + *
> + * Returns true if the current task has active warning suppression.
> + * Uses the kunit_running static branch for zero overhead when no tests run.
> + *
> + * A single WARN*() may traverse multiple call sites in the warning path
> + * (e.g., __warn_printk() and __report_bug()). Pass @count = true at the
> + * primary suppression point to count each warning exactly once, and
> + * @count = false at secondary points to suppress output without
> + * inflating the count.
> + */
> +static inline bool kunit_is_suppressed_warning(bool count)
> +{
> +       if (!static_branch_unlikely(&kunit_running))
> +               return false;
> +
> +       return kunit_hooks.is_suppressed_warning &&
> +              kunit_hooks.is_suppressed_warning(count);
> +}
> +
>  #else
>
>  static inline struct kunit *kunit_get_current_test(void) { return NULL; }
> +static inline bool kunit_is_suppressed_warning(bool count) { return false; }
>
>  #define kunit_fail_current_test(fmt, ...) do {} while (0)
>
> diff --git a/include/kunit/test.h b/include/kunit/test.h
> index 9cd1594ab697d..be71612f61655 100644
> --- a/include/kunit/test.h
> +++ b/include/kunit/test.h
> @@ -1795,4 +1795,102 @@ do {                                                                           \
>  // include resource.h themselves if they need it.
>  #include <kunit/resource.h>
>
> +/*
> + * Warning backtrace suppression API.
> + *
> + * Suppresses WARN*() backtraces on the current task while active. Two forms
> + * are provided:
> + *
> + * - Scoped: kunit_warning_suppress(test) { ... }
> + *   Suppression is active for the duration of the block. On normal exit,
> + *   the for-loop increment deactivates suppression. On early exit (break,
> + *   return, goto), the __cleanup attribute fires. On kthread_exit() (e.g.,
> + *   a failed KUnit assertion), kunit_add_action() cleans up at test
> + *   teardown. The suppression handle is only accessible inside the block,
> + *   so warning counts must be checked before the block exits.
> + *
> + * - Direct: kunit_start_suppress_warning() / kunit_end_suppress_warning()
> + *   The underlying functions, returning an explicit handle pointer. Use
> + *   when the handle needs to be retained (e.g., for post-suppression
> + *   count checks) or passed across helper functions.
> + */
> +struct kunit_suppressed_warning;
> +
> +struct kunit_suppressed_warning *
> +kunit_start_suppress_warning(struct kunit *test);
> +void kunit_end_suppress_warning(struct kunit *test,
> +                               struct kunit_suppressed_warning *w);
> +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w);
> +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp);
> +bool kunit_has_active_suppress_warning(void);
> +
> +/**
> + * kunit_warning_suppress() - Suppress WARN*() backtraces for the duration
> + *                            of a block.
> + * @test: The test context object.
> + *
> + * Scoped form of the suppression API. Suppression starts when the block is
> + * entered and ends automatically when the block exits through any path. See
> + * the section comment above for the cleanup guarantees on each exit path.
> + * Fails the test if suppression is already active; nesting is not supported.
> + *
> + * The warning count can be checked inside the block via
> + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(). The handle is not accessible
> + * after the block exits.
> + *
> + * Example::
> + *
> + *   kunit_warning_suppress(test) {
> + *       trigger_warning();
> + *       KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, 1);
> + *   }
> + */
> +#define kunit_warning_suppress(test)                                   \
> +       for (struct kunit_suppressed_warning *__kunit_suppress          \
> +            __cleanup(__kunit_suppress_auto_cleanup) =                 \
> +            kunit_start_suppress_warning(test);                        \
> +            __kunit_suppress;                                          \
> +            kunit_end_suppress_warning(test, __kunit_suppress),        \
> +            __kunit_suppress = NULL)
> +
> +/**
> + * KUNIT_SUPPRESSED_WARNING_COUNT() - Returns the suppressed warning count.
> + *
> + * Returns the number of WARN*() calls suppressed since the current
> + * suppression block started, or 0 if the handle is NULL. Usable inside a
> + * kunit_warning_suppress() block.
> + */
> +#define KUNIT_SUPPRESSED_WARNING_COUNT() \
> +       kunit_suppressed_warning_count(__kunit_suppress)
> +
> +/**
> + * KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT() - Sets an expectation that the
> + *                                           suppressed warning count equals
> + *                                           @expected.
> + * @test: The test context object.
> + * @expected: an expression that evaluates to the expected warning count.
> + *
> + * Sets an expectation that the number of suppressed WARN*() calls equals
> + * @expected. This is semantically equivalent to
> + * KUNIT_EXPECT_EQ(@test, KUNIT_SUPPRESSED_WARNING_COUNT(), @expected).
> + * See KUNIT_EXPECT_EQ() for more information.
> + */
> +#define KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(test, expected) \
> +       KUNIT_EXPECT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
> +
> +/**
> + * KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT() - Sets an assertion that the
> + *                                           suppressed warning count equals
> + *                                           @expected.
> + * @test: The test context object.
> + * @expected: an expression that evaluates to the expected warning count.
> + *
> + * Sets an assertion that the number of suppressed WARN*() calls equals
> + * @expected. This is the same as KUNIT_EXPECT_SUPPRESSED_WARNING_COUNT(),
> + * except it causes an assertion failure (see KUNIT_ASSERT_TRUE()) when the
> + * assertion is not met.
> + */
> +#define KUNIT_ASSERT_SUPPRESSED_WARNING_COUNT(test, expected) \
> +       KUNIT_ASSERT_EQ(test, KUNIT_SUPPRESSED_WARNING_COUNT(), expected)
> +
>  #endif /* _KUNIT_TEST_H */
> diff --git a/kernel/panic.c b/kernel/panic.c
> index 20feada5319d4..213725b612aa1 100644
> --- a/kernel/panic.c
> +++ b/kernel/panic.c
> @@ -39,6 +39,7 @@
>  #include <linux/sys_info.h>
>  #include <trace/events/error_report.h>
>  #include <asm/sections.h>
> +#include <kunit/test-bug.h>
>
>  #define PANIC_TIMER_STEP 100
>  #define PANIC_BLINK_SPD 18
> @@ -1124,6 +1125,11 @@ void warn_slowpath_fmt(const char *file, int line, unsigned taint,
>         bool rcu = warn_rcu_enter();
>         struct warn_args args;
>
> +       if (kunit_is_suppressed_warning(true)) {
> +               warn_rcu_exit(rcu);
> +               return;
> +       }
> +
>         pr_warn(CUT_HERE);
>
>         if (!fmt) {
> @@ -1146,6 +1152,11 @@ void __warn_printk(const char *fmt, ...)
>         bool rcu = warn_rcu_enter();
>         va_list args;
>
> +       if (kunit_is_suppressed_warning(false)) {
> +               warn_rcu_exit(rcu);
> +               return;
> +       }
> +
>         pr_warn(CUT_HERE);
>
>         va_start(args, fmt);
> diff --git a/lib/bug.c b/lib/bug.c
> index 224f4cfa4aa31..874cb4ae4d047 100644
> --- a/lib/bug.c
> +++ b/lib/bug.c
> @@ -48,6 +48,7 @@
>  #include <linux/rculist.h>
>  #include <linux/ftrace.h>
>  #include <linux/context_tracking.h>
> +#include <kunit/test-bug.h>
>
>  extern struct bug_entry __start___bug_table[], __stop___bug_table[];
>
> @@ -209,8 +210,6 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
>                         return BUG_TRAP_TYPE_NONE;
>         }
>
> -       disable_trace_on_warning();
> -
>         bug_get_file_line(bug, &file, &line);
>         fmt = bug_get_format(bug);
>
> @@ -220,6 +219,15 @@ static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long buga
>         no_cut   = bug->flags & BUGFLAG_NO_CUT_HERE;
>         has_args = bug->flags & BUGFLAG_ARGS;
>
> +       /*
> +        * Before the once logic so suppressed warnings do not consume
> +        * the single-fire budget of WARN_ON_ONCE().
> +        */
> +       if (warning && kunit_is_suppressed_warning(true))
> +               return BUG_TRAP_TYPE_WARN;
> +
> +       disable_trace_on_warning();
> +
>         if (warning && once) {
>                 if (done)
>                         return BUG_TRAP_TYPE_WARN;
> diff --git a/lib/kunit/Makefile b/lib/kunit/Makefile
> index 656f1fa35abcc..4592f9d0aa8dd 100644
> --- a/lib/kunit/Makefile
> +++ b/lib/kunit/Makefile
> @@ -10,7 +10,8 @@ kunit-objs +=                         test.o \
>                                         executor.o \
>                                         attributes.o \
>                                         device.o \
> -                                       platform.o
> +                                       platform.o \
> +                                       bug.o
>
>  ifeq ($(CONFIG_KUNIT_DEBUGFS),y)
>  kunit-objs +=                          debugfs.o
> diff --git a/lib/kunit/bug.c b/lib/kunit/bug.c
> new file mode 100644
> index 0000000000000..6752b497aeefe
> --- /dev/null
> +++ b/lib/kunit/bug.c
> @@ -0,0 +1,127 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * KUnit helpers for backtrace suppression
> + *
> + * Copyright (C) 2025 Alessandro Carminati <acarmina@redhat.com>
> + * Copyright (C) 2024 Guenter Roeck <linux@roeck-us.net>
> + */
> +
> +#include <kunit/resource.h>
> +#include <linux/export.h>
> +#include <linux/rculist.h>
> +#include <linux/sched.h>
> +#include <linux/spinlock.h>
> +
> +#include "hooks-impl.h"
> +
> +struct kunit_suppressed_warning {
> +       struct list_head node;
> +       struct task_struct *task;
> +       struct kunit *test;
> +       atomic_t counter;
> +};
> +
> +static LIST_HEAD(suppressed_warnings);
> +static DEFINE_SPINLOCK(suppressed_warnings_lock);
> +
> +static void kunit_suppress_warning_remove(struct kunit_suppressed_warning *w)
> +{
> +       unsigned long flags;
> +
> +       spin_lock_irqsave(&suppressed_warnings_lock, flags);
> +       list_del_rcu(&w->node);
> +       spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
> +       synchronize_rcu(); /* Wait for readers to finish */
> +}
> +
> +KUNIT_DEFINE_ACTION_WRAPPER(kunit_suppress_warning_cleanup,
> +                           kunit_suppress_warning_remove,
> +                           struct kunit_suppressed_warning *);
> +
> +bool kunit_has_active_suppress_warning(void)
> +{
> +       return __kunit_is_suppressed_warning_impl(false);
> +}
> +EXPORT_SYMBOL_GPL(kunit_has_active_suppress_warning);
> +
> +struct kunit_suppressed_warning *
> +kunit_start_suppress_warning(struct kunit *test)
> +{
> +       struct kunit_suppressed_warning *w;
> +       unsigned long flags;
> +       int ret;
> +
> +       if (kunit_has_active_suppress_warning()) {
> +               KUNIT_FAIL(test, "Another suppression block is already active");
> +               return NULL;
> +       }
> +
> +       w = kunit_kzalloc(test, sizeof(*w), GFP_KERNEL);
> +       if (!w) {
> +               KUNIT_FAIL(test, "Failed to allocate suppression handle.");
> +               return NULL;
> +       }
> +
> +       /*
> +        * Store current without taking a reference. The test task cannot
> +        * exit before kunit tears down the test, so the pointer is stable
> +        * for the lifetime of this handle.
> +        */
> +       w->task = current;
> +       w->test = test;
> +
> +       spin_lock_irqsave(&suppressed_warnings_lock, flags);
> +       list_add_rcu(&w->node, &suppressed_warnings);
> +       spin_unlock_irqrestore(&suppressed_warnings_lock, flags);
> +
> +       ret = kunit_add_action_or_reset(test,
> +                                       kunit_suppress_warning_cleanup, w);
> +       if (ret) {
> +               KUNIT_FAIL(test, "Failed to add suppression cleanup action.");
> +               return NULL;
> +       }
> +
> +       return w;
> +}
> +EXPORT_SYMBOL_GPL(kunit_start_suppress_warning);
> +
> +void kunit_end_suppress_warning(struct kunit *test,
> +                               struct kunit_suppressed_warning *w)
> +{
> +       if (!w)
> +               return;
> +       kunit_release_action(test, kunit_suppress_warning_cleanup, w);
> +}
> +EXPORT_SYMBOL_GPL(kunit_end_suppress_warning);
> +
> +void __kunit_suppress_auto_cleanup(struct kunit_suppressed_warning **wp)
> +{
> +       if (*wp)
> +               kunit_end_suppress_warning((*wp)->test, *wp);
> +}
> +EXPORT_SYMBOL_GPL(__kunit_suppress_auto_cleanup);
> +
> +int kunit_suppressed_warning_count(struct kunit_suppressed_warning *w)
> +{
> +       return w ? atomic_read(&w->counter) : 0;
> +}
> +EXPORT_SYMBOL_GPL(kunit_suppressed_warning_count);
> +
> +bool __kunit_is_suppressed_warning_impl(bool count)
> +{
> +       struct kunit_suppressed_warning *w;
> +
> +       if (!in_task())
> +               return false;
> +
> +       guard(rcu)();
> +       list_for_each_entry_rcu(w, &suppressed_warnings, node) {
> +               if (w->task == current) {
> +                       if (count)
> +                               atomic_inc(&w->counter);
> +                       return true;
> +               }
> +       }
> +
> +       return false;
> +}
> diff --git a/lib/kunit/hooks-impl.h b/lib/kunit/hooks-impl.h
> index 4e71b2d0143ba..d8720f2616925 100644
> --- a/lib/kunit/hooks-impl.h
> +++ b/lib/kunit/hooks-impl.h
> @@ -19,6 +19,7 @@ void __printf(3, 4) __kunit_fail_current_test_impl(const char *file,
>                                                    int line,
>                                                    const char *fmt, ...);
>  void *__kunit_get_static_stub_address_impl(struct kunit *test, void *real_fn_addr);
> +bool __kunit_is_suppressed_warning_impl(bool count);
>
>  /* Code to set all of the function pointers. */
>  static inline void kunit_install_hooks(void)
> @@ -26,6 +27,7 @@ static inline void kunit_install_hooks(void)
>         /* Install the KUnit hook functions. */
>         kunit_hooks.fail_current_test = __kunit_fail_current_test_impl;
>         kunit_hooks.get_static_stub_address = __kunit_get_static_stub_address_impl;
> +       kunit_hooks.is_suppressed_warning = __kunit_is_suppressed_warning_impl;
>  }
>
>  #endif /* _KUNIT_HOOKS_IMPL_H */
>
> --
> 2.53.0
>


^ permalink raw reply


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