Linux Documentation
 help / color / mirror / Atom feed
* [PATCH v4 0/2] spi: add new_device/delete_device sysfs interface
From: Vishwaroop A @ 2026-05-11 10:40 UTC (permalink / raw)
  To: broonie, linux-spi
  Cc: smangipudi, jonathanh, thierry.reding, corbet, linux-doc, va

Add I2C-style new_device/delete_device sysfs attributes to SPI host
controllers, allowing userspace to instantiate and remove SPI devices
at runtime without device-tree changes.

Changes since v3:
  - Replaced holding add_lock across __spi_add_device() + list
    insertion (which caused an ABBA deadlock between add_lock and the
    kernfs active reference during concurrent unbind) with:
    * A 'dead' flag on spi_controller, set in
      spi_unregister_controller() under both add_lock and
      userspace_clients_lock.
    * __spi_add_device() checks ctlr->dead under add_lock to reject
      new devices after teardown begins.
    * new_device_store() checks ctlr->dead under userspace_clients_lock
      before list insertion, falling back to cleanup + ENODEV.
    * add_lock is released before device_del() so in-flight sysfs
      stores can drain without deadlocking.
    * get_device() taken before spi_add_device() prevents
      use-after-free if __unregister runs concurrently.
  - Used #if IS_ENABLED() preprocessor guard (not runtime IS_ENABLED())
    for the ctlr->dead check in __spi_add_device(), since the dead
    field is conditionally compiled.

Changes since v2:
  - Gated sysfs attributes and locking on CONFIG_SPI_DYNAMIC.

Changes since v1:
  - Added locking to prevent races between new_device_store() and
    concurrent spi_unregister_controller().

Link: https://lore.kernel.org/linux-tegra/909f0c92-d110-4253-903e-5c81e21e12c9@nvidia.com/

Vishwaroop A (2):
  spi: add new_device/delete_device sysfs interface
  docs: spi: add documentation for userspace device instantiation

 .../ABI/testing/sysfs-class-spi-master        |  34 +++
 Documentation/spi/index.rst                   |   1 +
 Documentation/spi/instantiating-devices.rst   |  88 +++++++
 drivers/spi/spi.c                             | 216 +++++++++++++++++-
 include/linux/spi/spi.h                       |  13 +
 5 files changed, 346 insertions(+), 6 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-class-spi-master
 create mode 100644 Documentation/spi/instantiating-devices.rst

-- 
2.17.1


^ permalink raw reply

* Re: [PATCH v10 01/30] arm64/sysreg: Update SMIDR_EL1 to DDI0601 2025-06
From: Mark Rutland @ 2026-05-11 10:40 UTC (permalink / raw)
  To: Mark Brown
  Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
	Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
	Oliver Upton, Dave Martin, Fuad Tabba, Ben Horgan,
	linux-arm-kernel, kvmarm, linux-kernel, kvm, linux-doc,
	linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <af6DH_j7pyEm4HyI@sirena.co.uk>

On Sat, May 09, 2026 at 09:43:11AM +0900, Mark Brown wrote:
> On Fri, May 08, 2026 at 06:12:01PM +0100, Mark Rutland wrote:
> > On Fri, Mar 06, 2026 at 05:00:53PM +0000, Mark Brown wrote:
> 
> > > Update the definition of SMIDR_EL1 in the sysreg definition to reflect the
> > > information in DD0601 2025-06. This includes somewhat more generic ways of
> > > describing the sharing of SMCUs, more information on supported priorities
> > > and provides additional resolution for describing affinity groups.
> 
> > FWIW, these are all in ARM DDI 0487 M.b:
> 
> >   https://developer.arm.com/documentation/ddi0487/mb/
> 
> > Is anything later in the series going to depend on these fields, or
> > would everything behave correctly with the existing RES0 field
> > definitions?
> 
> We're exposing the affinity fields so there's a build time issue.

What I'm asking is what is the rationale for updating these definitions?
e.g.

* Are we planning to use any of the fields in a specific way in the
  *host*?

* Are we planning to use any of the fields in a specific way in the
  *guest*?

* Is this updated just out of habit?

Knowing the rationale would help with review, even if that rationale is
just "it seemed nice to use the latest".

> > > +Field	55:52	HIP
> 
> > Reading the ARM ARM, HIP is arguably a backwards-incompatible change.
> 
> Yes, I belive people are aware.

Ok. Is that considered a problem, or accepted?

Which people are aware?

> > Do we expect to expose that to VMs, or just hide priorities entirely? I
> > suspect we probably want to require that the guest sees
> > SMIDR_EL1.SMPS==0, and not care about any of that.
> 
> Currently we're not exposing priority support to guests so we don't need
> to worry about it yet.

Do we plan to in future?

Mark.

^ permalink raw reply

* Re: [PATCH v2] killswitch: add per-function short-circuit mitigation primitive
From: Anthony Iliopoulos @ 2026-05-11 10:33 UTC (permalink / raw)
  To: Sasha Levin
  Cc: Florian Weimer, corbet, akpm, skhan, linux-doc, linux-kernel,
	linux-kselftest, gregkh
In-Reply-To: <af8pw54Y-Q18kSR0@laps>

On Sat, May 09, 2026 at 08:34:11AM -0400, Sasha Levin wrote:
> On Sat, May 09, 2026 at 02:02:24PM +0200, Florian Weimer wrote:
> > * Sasha Levin:
> > 
> > > When a kernel (security) issue goes public, fleets stay exposed until a patched
> > > kernel is built, distributed, and rebooted into.
> > > 
> > > For many such issues the simplest mitigation is to stop calling the buggy
> > > function. Killswitch provides that. An admin writes:
> > > 
> > >     echo "engage af_alg_sendmsg -1" \
> > >         > /sys/kernel/security/killswitch/control
> > > 
> > > After this, af_alg_sendmsg() returns -EPERM on every call without
> > > running its body. The mitigation takes effect immediately, and is dropped on
> > > the next reboot -- by which point a patched kernel is hopefully in place.
> > 
> > Do you expect this to be safe to enable in kernel lockdown mode (i.e.,
> > with typical Secure Boot configurations in distributions)?
> 
> Yes: under lockdown, killswitch has to be configured on the cmdline. Runtime
> engage is gated on the new LOCKDOWN_KILLSWITCH reason.

Basically this proposal allows for any function to be overridden on a
production kernel as long as no lockdown level is enabled, which is quite
dangerous.

Assuming this is acceptable (which I am not sure it should be), then this
is equivalent to the existing error injection code that we already have in
the kernel (CONFIG_FAIL_FUNCTION) minus the explicit whitelisting on a per
function basis required to permit injection.

Given that this achieves the exact same result, then why don't we consider
simply removing the whitelisting restriction from fail_function altogether
and use that instead? The only thing missing then would be the boot param
parsing and setup.

This way we'll be removing a few hundred lines of code instead of adding
more duplication, while enabling the same functionality.

[As a bonus, this would also make the existing framework more practical to
 use for testing arbitrary function failures. I have been carrying a debug
 only patch to that effect for a while, which basically just shorts the
 whitelisting check when CONFIG_FUNCTION_ERROR_INJECTION_ALLOW_ALL=y.]

Regards,
Anthony

^ permalink raw reply

* Re: [PATCH v10 04/30] arm64/fpsimd: Determine maximum virtualisable SME vector length
From: Mark Rutland @ 2026-05-11 10:32 UTC (permalink / raw)
  To: Mark Brown
  Cc: Marc Zyngier, Joey Gouly, Catalin Marinas, Suzuki K Poulose,
	Will Deacon, Paolo Bonzini, Jonathan Corbet, Shuah Khan,
	Oliver Upton, Dave Martin, Fuad Tabba, Ben Horgan,
	linux-arm-kernel, kvmarm, linux-kernel, kvm, linux-doc,
	linux-kselftest, Peter Maydell, Eric Auger
In-Reply-To: <20260306-kvm-arm64-sme-v10-4-43f7683a0fb7@kernel.org>

On Fri, Mar 06, 2026 at 05:00:56PM +0000, Mark Brown wrote:
> As with SVE we can only virtualise SME vector lengths that are supported by
> all CPUs in the system, implement similar checks to those for SVE. 

So far so good.

> Since unlike SVE there are no specific vector lengths that are
> architecturally required the handling is subtly different, we report a
> system where this happens with a maximum vector length of
> SME_VQ_INVALID.

I think something went wrong during copyediting here.

A system where *what* happens?

> Signed-off-by: Mark Brown <broonie@kernel.org>
> ---
>  arch/arm64/include/asm/fpsimd.h |  2 ++
>  arch/arm64/kernel/fpsimd.c      | 21 ++++++++++++++++++++-
>  2 files changed, 22 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> index e97729aa3b2f..0cd8a866e844 100644
> --- a/arch/arm64/include/asm/fpsimd.h
> +++ b/arch/arm64/include/asm/fpsimd.h
> @@ -69,6 +69,8 @@ static inline void cpacr_restore(unsigned long cpacr)
>  #define ARCH_SVE_VQ_MAX ((ZCR_ELx_LEN_MASK >> ZCR_ELx_LEN_SHIFT) + 1)
>  #define SME_VQ_MAX	((SMCR_ELx_LEN_MASK >> SMCR_ELx_LEN_SHIFT) + 1)
>  
> +#define SME_VQ_INVALID	(SME_VQ_MAX + 1)

Does using (SME_VQ_MAX + 1) for this make something easier than if we
used 0?

My thinking is that 0 will be easier/clearer overall, since we can write
checks of the form:

	if (!info->max_virtualisable_vl) {
		/* SME is not virtualisable */
	}

... or:

	if (some_vl <= max_virtualisable_vl) {
		/* Check properties of a virtualisable VL */
	}

... and there's less scope for error.

> +
>  struct task_struct;
>  
>  extern void fpsimd_save_state(struct user_fpsimd_state *state);
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index 2af0e0c5b9f4..49c050ef6db9 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -1218,7 +1218,8 @@ void cpu_enable_sme(const struct arm64_cpu_capabilities *__always_unused p)
>  void __init sme_setup(void)
>  {
>  	struct vl_info *info = &vl_info[ARM64_VEC_SME];
> -	int min_bit, max_bit;
> +	DECLARE_BITMAP(tmp_map, SVE_VQ_MAX);
> +	int min_bit, max_bit, b;
>  
>  	if (!system_supports_sme())
>  		return;
> @@ -1249,12 +1250,30 @@ void __init sme_setup(void)
>  	 */
>  	set_sme_default_vl(find_supported_vector_length(ARM64_VEC_SME, 32));
>  
> +	bitmap_andnot(tmp_map, info->vq_partial_map, info->vq_map,
> +		      SVE_VQ_MAX);
> +
> +	b = find_last_bit(tmp_map, SVE_VQ_MAX);
> +	if (b >= SVE_VQ_MAX)
> +		/* All VLs virtualisable */
> +		info->max_virtualisable_vl = sve_vl_from_vq(ARCH_SVE_VQ_MAX);

I don't think this is right.

This test tells us that all VLs implemented by boot CPUs are
virtualisable. That set of VLs doesn't necessarily include the
architectural maximum VL.

IIUC that's not a problem for KVM, since KVM enforces that a guest's
maximum VL is an implemented VL. However, this is a problem for
vec_verify_vq_map().

Consider the case where all boot CPUs support only 128-bit, but later we
try to online a CPU that supports 128-bit and 256-bit. That CPU will be
rejected by vec_verify_vq_map().

Note that this isn't broken for SVE today as sve_setup() follows this up
with:

	if (info->max_virtualisable_vl > info->max_vl)
		info->max_virtualisable_vl = info->max_vl;

... but that won't be sufficient for streaming mode VLs given there's no
guarantee that smaller streaming VLs are implemented.

> +	else if (b == SVE_VQ_MAX - 1)
> +		/* No virtualisable VLs */
> +		info->max_virtualisable_vl = sve_vl_from_vq(SME_VQ_INVALID);

Similarly, I think this is broken for vec_verify_vq_map(). Consider a
case with two boot CPUs, where one boot CPU only supports 128-bit, and
the other boot cpu only supports 256-bit. If either CPU is hotplugged
out and then back in, it will be rejected by vec_verify_vq_map().

We don't have a similar problem for SVE since that's not architecturally
possible.

> +	else
> +		info->max_virtualisable_vl = sve_vl_from_vq(__bit_to_vq(b +  1));

This looks suspicious.

At this point we know that 'b' represents the smallest VL which is
partially supported. The next bit is almost never a power of two, is not
guaranteed to be an implemented VL, and is not guaranteed to be larger
than an implemented VL.

Imagine you have two CPUs:

* CPU x supports 128-bit.
* CPU y supports 128-bit and 512-bit.

The algorithm above will find 512-bit as the smallest partically
supported VL. For that, VQ==4 and b==12.

If max_virtualisable_vl is chosen as b+1, then that's b==13 and VQ==3,
which corresponds to a (not architecturally supported) 384-bit VL, which
is bigger than the architecturally-valid 256 bit VL that neither CPU
supports.

As with the other cases above, that's broken for vec_verify_vq_map(),
but I think KVM will gracefully handle this.

To solve all of the above, I think what we actually want to do is find
the largest uniformly implemented VL which is smaller than the smallest
partially implemented VL.

>  	pr_info("SME: minimum available vector length %u bytes per vector\n",
>  		info->min_vl);
>  	pr_info("SME: maximum available vector length %u bytes per vector\n",
>  		info->max_vl);
>  	pr_info("SME: default vector length %u bytes per vector\n",
>  		get_sme_default_vl());
> +
> +	/* KVM decides whether to support mismatched systems. Just warn here: */
> +	if (info->max_virtualisable_vl < info->max_vl ||
> +	    info->max_virtualisable_vl == sve_vl_from_vq(SME_VQ_INVALID))
> +		pr_warn("SME: unvirtualisable vector lengths present\n");

If we used 0 instead of (SME_VQ_MAX + 1), this would just be:

	if (info->max_virtualisable_vl < info->max_vl)
		pr_warn(...);

As above, I think using 0 would be preferable.

Mark.

>  }
>  
>  void sme_suspend_exit(void)
> 
> -- 
> 2.47.3
> 

^ permalink raw reply

* Re: [RFC PATCH v2 1/2] scripts: add kconfirm
From: Jani Nikula @ 2026-05-11  9:57 UTC (permalink / raw)
  To: Julian Braha, nathan, nsc
  Cc: akpm, gary, ljs, arnd, gregkh, masahiroy, ojeda, corbet,
	qingfang.deng, linux-kernel, rust-for-linux, linux-doc,
	linux-kbuild, Julian Braha
In-Reply-To: <20260509203808.1142311-2-julianbraha@gmail.com>

On Sat, 09 May 2026, Julian Braha <julianbraha@gmail.com> wrote:
>  scripts/kconfirm/LICENSE                      | 339 +++++++++

Why?

See LICENSES/preferred/GPL-2.0.


BR,
Jani.


-- 
Jani Nikula, Intel

^ permalink raw reply

* Re: [PATCH v13 04/15] arm64: kexec_file: Fix potential buffer overflow in prepare_elf_headers()
From: Breno Leitao @ 2026-05-11  9:46 UTC (permalink / raw)
  To: Jinjie Ruan
  Cc: corbet, skhan, catalin.marinas, will, chenhuacai, kernel, maddy,
	mpe, npiggin, chleroy, pjw, palmer, aou, alex, tglx, mingo, bp,
	dave.hansen, hpa, robh, saravanak, akpm, bhe, rppt,
	pasha.tatashin, pratyush, ruirui.yang, rdunlap, pmladek,
	dapeng1.mi, kees, elver, kuba, ebiggers, lirongqing, paulmck,
	sourabhjain, coxu, jbohac, ryan.roberts, osandov, cfsworks,
	tangyouling, ritesh.list, adityag, guoren, songshuaishuai,
	kevin.brodsky, vishal.moola, junhui.liu, wangruikang, namcao,
	chao.gao, seanjc, fuqiang.wang, ardb, chenjiahao16, hbathini,
	takahiro.akashi, james.morse, lizhengyu3, x86, linux-doc,
	linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
	linux-riscv, devicetree, kexec
In-Reply-To: <20260511030454.1730881-5-ruanjinjie@huawei.com>

On Mon, May 11, 2026 at 11:04:43AM +0800, Jinjie Ruan wrote:
> There is a race condition between the kexec_load() system call
> (crash kernel loading path) and memory hotplug operations that can
> lead to buffer overflow and potential kernel crash.
> 
> During prepare_elf_headers(), the following steps occur:
> 1. The first for_each_mem_range() queries current System RAM memory ranges
> 2. Allocates buffer based on queried count
> 3. The 2st for_each_mem_range() populates ranges from memblock
> 
> If memory hotplug occurs between step 1 and step 3, the number of ranges
> can increase, causing out-of-bounds write when populating cmem->ranges[].
> 
> This happens because kexec_load() uses kexec_trylock (atomic_t) while
> memory hotplug uses device_hotplug_lock (mutex), so they don't serialize
> with each other.
> 
> Add the explicit bounds checking to prevent out-of-bounds access.

It seems you have a TOCTOU type of issue, and this seems to be shrinking
the window, but not fully solving it?

> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Will Deacon <will.deacon@arm.com>
> Cc: Andrew Morton <akpm@linux-foundation.org>
> Cc: Baoquan He <bhe@redhat.com>
> Cc: Breno Leitao <leitao@debian.org>
> Cc: stable@vger.kernel.org
> Fixes: 3751e728cef2 ("arm64: kexec_file: add crash dump support")
> Closes: https://sashiko.dev/#/patchset/20260323072745.2481719-1-ruanjinjie%40huawei.com
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> ---
>  arch/arm64/kernel/machine_kexec_file.c | 5 +++++
>  1 file changed, 5 insertions(+)
> 
> diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
> index e31fabed378a..a67e7b1abbab 100644
> --- a/arch/arm64/kernel/machine_kexec_file.c
> +++ b/arch/arm64/kernel/machine_kexec_file.c
> @@ -59,6 +59,11 @@ static int prepare_elf_headers(void **addr, unsigned long *sz)
>  	cmem->max_nr_ranges = nr_ranges;
>  	cmem->nr_ranges = 0;
>  	for_each_mem_range(i, &start, &end) {
> +		if (cmem->nr_ranges >= cmem->max_nr_ranges) {
> +			ret = -ENOMEM;

-ENOMEM seems to be the the wrong errno. This isn't an allocation
failure; it's a transient race. -EBUSY or -EAGAIN would be more honest

^ permalink raw reply

* Re: [PATCH v1] docs/ja_JP: translate more of submitting-patches.rst
From: Akira Yokosawa @ 2026-05-11  9:17 UTC (permalink / raw)
  To: Akiyoshi Kurita; +Cc: linux-kernel, corbet, linux-doc
In-Reply-To: <20260504182425.1402425-1-weibu@redadmin.org>

Hi,

On Tue,  5 May 2026 03:24:25 +0900, Akiyoshi Kurita wrote:
> Translate the "No MIME, no links, no compression, no attachments.
> Just plain text" and "Respond to review comments" sections in
> Documentation/translations/ja_JP/process/submitting-patches.rst.
> 
> Keep the wording close to the English text and wrap lines to match
> the style used in the surrounding Japanese translation.
> 
> Signed-off-by: Akiyoshi Kurita <weibu@redadmin.org>
> ---

Summary phrase of this patch is identical to your earlier patch,
queued as 61e4155c81d1 ("docs/ja_JP: translate more of
submitting-patches.rst").

Not a hard rule, but it is a good practice to pick a summary phrase
different from those of recent other patches, to make the patch
at hand look obviously different.

For example,

  "docs/ja_JP: translate more of submitting-patches.rst (no-mime ...)"

should be good enough.

>  .../ja_JP/process/submitting-patches.rst      | 58 +++++++++++++++++++
>  1 file changed, 58 insertions(+)
> 
> diff --git a/Documentation/translations/ja_JP/process/submitting-patches.rst b/Documentation/translations/ja_JP/process/submitting-patches.rst
> index 928e38a8d34d..d7e04c09f951 100644
> --- a/Documentation/translations/ja_JP/process/submitting-patches.rst
> +++ b/Documentation/translations/ja_JP/process/submitting-patches.rst
> @@ -292,3 +292,61 @@ MAINTAINERS ファイルに記載されている MAN-PAGES メンテナに
>  man-pages パッチ、少なくとも変更の通知を送って、情報が
>  マニュアルページに反映されるようにしてください。ユーザー空間 API の
>  変更は、linux-api@vger.kernel.org にも Cc してください。
> +
> +MIME、リンク、圧縮、添付ファイルは使わない。プレーンテキストだけ
> +----------------------------------------------------------------------

This doesn't sound like a section title to me.  Please retry ...

> +
> +Linus や他のカーネル開発者は、あなたが投稿する変更を読み、
> +コメントできる必要があります。カーネル開発者が標準的な
> +メールツールを使ってあなたの変更を「引用」し、コードの特定の
> +箇所についてコメントできることが重要です。
> +
> +このため、すべてのパッチはメール本文中に ``inline`` で投稿すべきです。
> +これを行う最も簡単な方法は ``git send-email`` を使うことであり、
> +強く推奨されます。``git send-email`` の対話型チュートリアルは
> +https://git-send-email.io で利用できます。
> +
> +``git send-email`` を使わないことを選ぶ場合:
> +
> +.. warning::
> +
> +  パッチをコピー&ペーストする場合は、エディタの word-wrap によって
> +  パッチが壊れないよう注意してください。
> +
> +圧縮の有無にかかわらず、パッチを MIME 添付ファイルとして添付しては
> +いけません。多くの一般的なメールアプリケーションは、MIME 添付
> +ファイルを常にプレーンテキストとして送信するとは限らず、あなたの
> +コードにコメントできなくなります。MIME 添付ファイルは Linus が
> +処理するのにも少し余分な時間がかかるため、MIME 添付された変更が
> +受け入れられる可能性を下げます。
> +
> +例外:  メーラがパッチを壊してしまう場合は、誰かから MIME を使って
> +再送するよう求められることがあります。
> +
> +パッチを変更せずに送信するようメールクライアントを設定するための
> +ヒントについては、Documentation/process/email-clients.rst を参照してください。
> +
> +
> +レビューコメントに返答する
> +--------------------------
> +
> +あなたのパッチには、ほぼ確実に、パッチを改善する方法について
> +レビューアからコメントが付きます。それは、あなたのメールへの返信という
> +形で届きます。それらのコメントには必ず返答してください。レビューアを
> +無視することは、こちらも無視されるためのよい方法です。コメントに
> +答えるには、単にそのメールへ返信すれば構いません。コード変更に
> +つながらないレビューコメントや質問であっても、次のレビューアが状況を
> +よりよく理解できるように、ほぼ確実にコメントまたは changelog エントリに
> +反映すべきです。
> +
> +どのような変更を行うのかをレビューアに必ず伝え、時間を割いてくれた
> +ことに感謝してください。コードレビューは疲れる、時間のかかる作業であり、
> +レビューアが不機嫌になることもあります。そのような場合であっても、
> +丁寧に返答し、指摘された問題に対応してください。次の版を送るときは、
> +cover letter または個々のパッチに ``patch changelog`` を追加し、前回の
> +投稿との差分を説明してください(:ref:`the_canonical_patch_format` を
> +参照してください)。あなたのパッチにコメントした人には、パッチの Cc
> +リストに追加して、新しい版を知らせてください。

Instead of making a cross-ref to the English section, you can do the
same as is done in the earlier part of this document:

   詳細は原文の該当節 ("The canonical patch format") を参照してください。

   .. TODO: Convert to file-local ...

> +
> +メールクライアントとメーリングリストでの作法についての推奨事項は、
> +Documentation/process/email-clients.rst を参照してください。

I will take care of other minor nits later during v7.2 cycle.

Thanks,
Akira

^ permalink raw reply

* Re: [PATCH ipsec-next v8 12/14] xfrm: add XFRM_MSG_MIGRATE_STATE for single SA migration
From: Sabrina Dubroca @ 2026-05-11  9:13 UTC (permalink / raw)
  To: Antony Antony
  Cc: Steffen Klassert, Herbert Xu, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, David Ahern,
	Masahide NAKAMURA, Paul Moore, Stephen Smalley, Ondrej Mosnacek,
	Jonathan Corbet, Shuah Khan, netdev, linux-kernel, selinux,
	linux-doc, Chiachang Wang, Yan Yan, devel
In-Reply-To: <migrate-state-v8-12-4578fb016965@secunet.com>

2026-05-05, 06:34:29 +0200, Antony Antony wrote:
> Add a new netlink method to migrate a single xfrm_state.
> Unlike the existing migration mechanism (SA + policy), this
> supports migrating only the SA and allows changing the reqid.
> 
> The SA is looked up via xfrm_usersa_id, which uniquely
> identifies it, so old_saddr is not needed. old_daddr is carried in
> xfrm_usersa_id.daddr.
> 
> The reqid is invariant in the old migration.
> 
> Signed-off-by: Antony Antony <antony.antony@secunet.com>
> 

[...]
>  include/net/xfrm.h          |  16 ++-
>  include/uapi/linux/xfrm.h   |  21 ++++
>  net/xfrm/xfrm_device.c      |   2 +-
>  net/xfrm/xfrm_policy.c      |  19 +++
>  net/xfrm/xfrm_state.c       |  29 +++--
>  net/xfrm/xfrm_user.c        | 281 +++++++++++++++++++++++++++++++++++++++++++-
>  security/selinux/nlmsgtab.c |   3 +-
>  7 files changed, 357 insertions(+), 14 deletions(-)

If the omission of xfrm_compat.c is intentional, maybe worth
making a note of that?


> diff --git a/include/net/xfrm.h b/include/net/xfrm.h
> index 4b29ab92c2a7..e33e524cd909 100644
> --- a/include/net/xfrm.h
> +++ b/include/net/xfrm.h
> @@ -684,12 +684,20 @@ struct xfrm_migrate {
>  	xfrm_address_t		new_saddr;
>  	struct xfrm_encap_tmpl *encap;
>  	struct xfrm_user_offload *xuo;
> +	struct xfrm_mark        old_mark;
> +	struct xfrm_mark       *new_mark;
> +	struct xfrm_mark        smark;
>  	u8			proto;
>  	u8			mode;
> -	u16			reserved;
> +	u16			msg_type; /* XFRM_MSG_MIGRATE or XFRM_MSG_MIGRATE_STATE */
> +	u32			flags;
>  	u32			old_reqid;
> +	u32			new_reqid;
> +	u32			nat_keepalive_interval;
> +	u32			mapping_maxage;
>  	u16			old_family;
>  	u16			new_family;
> +	const struct xfrm_selector *new_sel;
>  };

afkey doesn't zero its array of xfrm_migrate, so those new fields will
contain garbage there. Hopefully nobody is using it, but...


> @@ -2104,7 +2112,7 @@ void xfrm_dev_resume(struct sk_buff *skb);
>  void xfrm_dev_backlog(struct softnet_data *sd);
>  struct sk_buff *validate_xmit_xfrm(struct sk_buff *skb, netdev_features_t features, bool *again);
>  int xfrm_dev_state_add(struct net *net, struct xfrm_state *x,
> -		       struct xfrm_user_offload *xuo,
> +		       const struct xfrm_user_offload *xuo,
>  		       struct netlink_ext_ack *extack);

nit: unrelated clean up


> diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h
> index a23495c0e0a1..34d8ad5c4818 100644
> --- a/include/uapi/linux/xfrm.h
> +++ b/include/uapi/linux/xfrm.h
[...]
> +/* Flags for xfrm_user_migrate_state.flags */
> +enum xfrm_migrate_state_flags {
> +	XFRM_MIGRATE_STATE_NO_OFFLOAD = 1, /* do not inherit offload from existing SA */

nit: maybe XFRM_MIGRATE_STATE_CLEAR_OFFLOAD?

> +	XFRM_MIGRATE_STATE_UPDATE_SEL = 2, /* update host-to-host selector from saddr and daddr */

"update sel" to me sounds more like "overwrite the whole thing" than
"copy some bits, fix up others". The name is already long, but maybe
"XFRM_MIGRATE_STATE_UPDATE_H2H_SEL"? (if only so that userspace devs
don't think they know what "update sel" means, so they have to read
the doc instead of possibly guessing wrong :))


> diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
> index cf05d778e2dd..9ecc4c8ba693 100644
> --- a/net/xfrm/xfrm_policy.c
> +++ b/net/xfrm/xfrm_policy.c
> @@ -4643,6 +4643,22 @@ static int xfrm_migrate_check(const struct xfrm_migrate *m, int num_migrate,
>  	return 0;
>  }
>  
> +/*
> + * Fill migrate fields that are invariant in XFRM_MSG_MIGRATE: inherited
> + * from the existing SA unchanged. XFRM_MSG_MIGRATE_STATE can update these.
> + */
> +static void xfrm_migrate_copy_old(struct xfrm_migrate *mp,
> +				  const struct xfrm_state *x,
> +				  struct xfrm_mark *new_mark_buf)
> +{
> +	mp->smark                  = x->props.smark;
> +	mp->new_reqid              = x->props.reqid;
> +	mp->nat_keepalive_interval = x->nat_keepalive_interval;
> +	mp->mapping_maxage         = x->mapping_maxage;
> +	*new_mark_buf              = x->mark;
> +	mp->new_mark               = new_mark_buf;

Do you really need a separate buffer for that? Or could you just use

    mp->new_mark = &x->mark;

and skip the new_marks array in xfrm_migrate()?

I find that new_marks array quite ugly, so I'd like to get rid of
it. If that doesn't work, I'd prefer to stuff new_mark_buf directly
inside struct xfrm_migrate, and then set mp->new_mark pointing to it.


> +}
> +
>  int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
>  		 struct xfrm_migrate *m, int num_migrate,
>  		 struct xfrm_kmaddress *k, struct net *net,
> @@ -4650,6 +4666,7 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
>  		 struct netlink_ext_ack *extack, struct xfrm_user_offload *xuo)
>  {
>  	int i, err, nx_cur = 0, nx_new = 0;
> +	struct xfrm_mark new_marks[XFRM_MAX_DEPTH] = {};
>  	struct xfrm_policy *pol = NULL;
>  	struct xfrm_state *x, *xc;
>  	struct xfrm_state *x_cur[XFRM_MAX_DEPTH];
> @@ -4682,6 +4699,8 @@ int xfrm_migrate(const struct xfrm_selector *sel, u8 dir, u8 type,
>  			nx_cur++;
>  			mp->encap = encap;
>  			mp->xuo = xuo;
> +			xfrm_migrate_copy_old(mp, x, &new_marks[i]);

nit: maybe swap mp and x, just to match the order of xfrm_state_migrate()?

It would also be a bit easier to review if you split this refactoring
(and the corresponding changes to xfrm_state_clone_and_setup) into a
separate patch.


> diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
> index 043e573c4f32..44244bd323ea 100644
> --- a/net/xfrm/xfrm_state.c
> +++ b/net/xfrm/xfrm_state.c
> @@ -1974,11 +1974,25 @@ static struct xfrm_state *xfrm_state_clone_and_setup(struct xfrm_state *orig,
>  		goto out;
>  
>  	memcpy(&x->id, &orig->id, sizeof(x->id));
> -	memcpy(&x->sel, &orig->sel, sizeof(x->sel));
> +	if (m->msg_type == XFRM_MSG_MIGRATE_STATE) {
> +		if (m->flags & XFRM_MIGRATE_STATE_UPDATE_SEL) {
> +			u8 prefixlen = (m->new_family == AF_INET6) ? 128 : 32;
> +
> +			memcpy(&x->sel, &orig->sel, sizeof(x->sel));
> +			x->sel.family      = m->new_family;
> +			x->sel.prefixlen_d = prefixlen;
> +			x->sel.prefixlen_s = prefixlen;
> +			memcpy(&x->sel.daddr, &m->new_daddr, sizeof(x->sel.daddr));
> +			memcpy(&x->sel.saddr, &m->new_saddr, sizeof(x->sel.saddr));
> +		} else {
> +			x->sel = *m->new_sel;

nit: the mix of copy styles (memcpy and struct assignment) within this
function, but especially here for x->sel, is a bit unpleasant.

> +		}
> +	} else {
> +		memcpy(&x->sel, &orig->sel, sizeof(x->sel));
> +	}
>  	memcpy(&x->lft, &orig->lft, sizeof(x->lft));

[...]
> diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
> index 03fa4cabf601..a49edf7d6f78 100644
> --- a/net/xfrm/xfrm_user.c
> +++ b/net/xfrm/xfrm_user.c
[...]
> @@ -3125,7 +3145,7 @@ static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh,
>  			   struct nlattr **attrs, struct netlink_ext_ack *extack)
>  {
>  	struct xfrm_userpolicy_id *pi = nlmsg_data(nlh);
> -	struct xfrm_migrate m[XFRM_MAX_DEPTH];
> +	struct xfrm_migrate m[XFRM_MAX_DEPTH] = {};

I'm not really opposed to this change, but what prompted it?


[...]
> +static int xfrm_do_migrate_state(struct sk_buff *skb, struct nlmsghdr *nlh,
> +				 struct nlattr **attrs, struct netlink_ext_ack *extack)
> +{
> +	struct xfrm_user_migrate_state *um = nlmsg_data(nlh);
> +	struct net *net = sock_net(skb->sk);
> +	struct xfrm_user_offload xuo = {};
> +	struct xfrm_migrate m = {};
> +	struct xfrm_state *xc;
> +	struct xfrm_state *x;
> +	int err;
> +
> +	if (!um->id.spi) {
> +		NL_SET_ERR_MSG(extack, "Invalid SPI 0x0");
> +		return -EINVAL;
> +	}
> +
> +	if (um->reserved) {
> +		NL_SET_ERR_MSG(extack, "Reserved field must be zero");
> +		return -EINVAL;
> +	}
> +
> +	if ((um->flags & XFRM_MIGRATE_STATE_NO_OFFLOAD) &&
> +	    attrs[XFRMA_OFFLOAD_DEV]) {
> +		NL_SET_ERR_MSG(extack,
> +			       "XFRM_MIGRATE_STATE_NO_OFFLOAD and XFRMA_OFFLOAD_DEV are mutually exclusive");

Not a strong objection, but they don't really have to be? "don't
inherit and set it from the one provided" sounds ok. (it's a bit
unnecessary to say "don't inherit", but not an issue)

XFRMA_OFFLOAD_DEV with !XFRM_MIGRATE_STATE_NO_OFFLOAD (inherit and
also set from request) seems more problematic.

> +		return -EINVAL;
> +	}
> +
> +	copy_from_user_migrate_state(&m, um);
> +
> +	x = xfrm_state_lookup(net, m.old_mark.v & m.old_mark.m,
> +			      &um->id.daddr, um->id.spi,
> +			      um->id.proto, um->id.family);
> +	if (!x) {
> +		NL_SET_ERR_MSG(extack, "Can not find state");
> +		return -ESRCH;
> +	}
> +
> +	if (um->flags & XFRM_MIGRATE_STATE_UPDATE_SEL) {
> +		u8 prefixlen = (x->sel.family == AF_INET6) ? 128 : 32;
> +
> +		if (x->sel.prefixlen_s != x->sel.prefixlen_d ||
> +		    x->sel.prefixlen_d != prefixlen ||
> +		    !xfrm_addr_equal(&x->sel.daddr, &x->id.daddr, x->sel.family) ||
> +		    !xfrm_addr_equal(&x->sel.saddr, &x->props.saddr, x->sel.family)) {

I think we need to be careful about families here too. id and sel
could have different ones.

[...]
> +	if (attrs[XFRMA_MTIMER_THRESH]) {
> +		err = verify_mtimer_thresh(!!m.encap, x->dir, extack);
> +		if (err)
> +			goto out;
> +	}
> +
> +	if (attrs[XFRMA_NAT_KEEPALIVE_INTERVAL] &&
> +	    nla_get_u32(attrs[XFRMA_NAT_KEEPALIVE_INTERVAL]) && !m.encap) {

if (nla_get_u32_default(attrs[XFRMA_NAT_KEEPALIVE_INTERVAL], 0) && !m.encap)

> +		NL_SET_ERR_MSG(extack,
> +			       "NAT_KEEPALIVE_INTERVAL requires encapsulation");
> +		err = -EINVAL;
> +		goto out;
> +	}
> +
> +	if (attrs[XFRMA_OFFLOAD_DEV]) {
> +		m.xuo = nla_data(attrs[XFRMA_OFFLOAD_DEV]);
> +	} else if (!(um->flags & XFRM_MIGRATE_STATE_NO_OFFLOAD) && x->xso.dev) {

nit: this would be a bit more readable with

    bool inherit_offload = !(um->flags & XFRM_MIGRATE_STATE_NO_OFFLOAD);

> +		xuo.ifindex = x->xso.dev->ifindex;
> +		if (x->xso.dir == XFRM_DEV_OFFLOAD_IN)
> +			xuo.flags = XFRM_OFFLOAD_INBOUND;
> +		if (x->xso.type == XFRM_DEV_OFFLOAD_PACKET)
> +			xuo.flags |= XFRM_OFFLOAD_PACKET;

copy_user_offload is doing almost exactly the same thing (copy from
and xso to an xuo). It would be better to extract some helper
(xso_to_xuo() ?) and use it in both places, otherwise they'll almost
certainly get out of sync.

> +		m.xuo = &xuo;
> +	}
> +
> +	if (attrs[XFRMA_MARK])
> +		m.new_mark = nla_data(attrs[XFRMA_MARK]);
> +
> +	if (attrs[XFRMA_SET_MARK])
> +		xfrm_smark_init(attrs, &m.smark);
> +	else
> +		m.smark = x->props.smark;
> +
> +	m.mapping_maxage = attrs[XFRMA_MTIMER_THRESH] ?
> +		nla_get_u32(attrs[XFRMA_MTIMER_THRESH]) : x->mapping_maxage;

m.mapping_maxage = nla_get_u32_default(attrs[XFRMA_MTIMER_THRESH], x->mapping_maxage);

> +	m.nat_keepalive_interval = attrs[XFRMA_NAT_KEEPALIVE_INTERVAL] ?
> +		nla_get_u32(attrs[XFRMA_NAT_KEEPALIVE_INTERVAL]) :
> +		x->nat_keepalive_interval;

m.nat_keepalive_interval = nla_get_u32_default(attrs[XFRMA_NAT_KEEPALIVE_INTERVAL], x->nat_keepalive_interval);


-- 
Sabrina

^ permalink raw reply

* Re: [PATCH v7 6/6] ARM: zte: defconfig: Add a zx29 defconfig file
From: Linus Walleij @ 2026-05-11  9:00 UTC (permalink / raw)
  To: Stefan Dösinger
  Cc: Jonathan Corbet, Shuah Khan, Russell King, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Arnd Bergmann,
	Krzysztof Kozlowski, Alexandre Belloni, Drew Fustini,
	Greg Kroah-Hartman, Jiri Slaby, linux-doc, linux-kernel,
	linux-arm-kernel, devicetree, linux-serial
In-Reply-To: <23095518.EfDdHjke4D@silicon.doe.home>

On Fri, May 8, 2026 at 12:09 AM Stefan Dösinger
<stefandoesinger@gmail.com> wrote:

> So I read https://docs.kernel.org/process/maintainer-soc.html a few times. If
> I understand it correctly at this point "pull request" still means emails sent
> with p4, correct?

No it's the contents of an
git request-pull v7.1-rc1 git://..... tags/my-soc

put into a regular email and sent to soc@kernel.org.

I'm sorry if the terminology isn't always clear on what a pull request
actually is in the kernel world (as opposed to e.g. github). It's just
an email with request-pull contents and some cover letter.

> Or does someone create a git repository on git.kernel.org
> for me that I can use to send actual pull requests?

We can pull from wherever as long as you can sign your tag
with a GPG key that we can (in best cases) trust. We can also
just inspect the result of a pull request from a branch (no tag)
if we wanna, it just involves more inspection and trust.

> As I understand it, my 6 patches then go to the 4 corners of the kernel:
>
> Patch 1 (dt binding) to devicetree@vger.kernel.org

Nah as long as the DT maintianers ACK it (i.e. Reviewed-by) we
can merge that to the SoC tree.

> Patches 2 (platform), 5 (DTS) and 6 (defconfig) to soc@kernel.org, but not in
> one series but 3 independent ones

In an ideal world.

> Patches 3 and 4 (UART) to linux-serial@vger.kernel.org. I think this can and
> should be a series of both patches belonging together

Yups. Greg merges those.

Yours,
Linus Walleij

^ permalink raw reply

* [PATCH] Documentation: KVM: Document guest-visible compatibility expectations
From: David Woodhouse @ 2026-05-11  8:57 UTC (permalink / raw)
  To: Paolo Bonzini, Jonathan Corbet, Shuah Khan, kvm, linux-doc,
	linux-kernel
  Cc: Oliver Upton, Joey Gouly, Suzuki K Poulose, Zenghui Yu,
	Catalin Marinas, Will Deacon, Raghavendra Rao Ananta, Eric Auger,
	Kees Cook, Arnd Bergmann, Nathan Chancellor, linux-arm-kernel,
	kvmarm, linux-kselftest

[-- Attachment #1: Type: text/plain, Size: 4433 bytes --]

From: David Woodhouse <dwmw@amazon.co.uk>

Document the expectation that KVM maintains guest-visible compatibility
across host kernel upgrades and rollbacks.  Specifically:

 - State saved/restored via KVM ioctls must be sufficient for live
   migration (and live update) between kernel versions.

 - Where a new kernel introduces a guest-visible change, it provides a
   mechanism for userspace to select the previous behaviour.

 - This allows both forward migration (upgrade) and backward migration
   (rollback) of guests.

These expectations have been implicitly required on x86 but were not
explicitly documented. Harmonise the expectations across all of KVM.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
---
 Documentation/virt/kvm/api.rst              | 14 ++++++++++++++
 Documentation/virt/kvm/review-checklist.rst | 20 ++++++++++++++------
 2 files changed, 28 insertions(+), 6 deletions(-)

diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 269970221797..864f3daa7acb 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -97,6 +97,20 @@ Instead, kvm defines extension identifiers and a facility to query
 whether a particular extension identifier is available.  If it is, a
 set of ioctls is available for application use.
 
+KVM will ensure that the state that can be saved and restored via the
+KVM ioctls is sufficient to allow migration of a running guest between
+host kernels while maintaining full compatibility of the guest-visible
+device model.  This includes migration to newer kernels (upgrade) and
+to older kernels (rollback), provided that the older kernel supports
+the set of features exposed to the guest.  Where a new kernel version
+introduces a guest-visible change, it will provide a mechanism (such
+as a capability or a device attribute) that allows userspace to select
+the previous behaviour.  This serves two purposes: guests migrated
+from an older kernel can continue to run with their original
+observable environment, and new guests launched on the newer kernel
+can be configured to match the feature set of the older kernel, so
+that they remain migratable to the older kernel in case of rollback.
+
 
 4. API description
 ==================
diff --git a/Documentation/virt/kvm/review-checklist.rst b/Documentation/virt/kvm/review-checklist.rst
index 053f00c50d66..f0fbe1577a90 100644
--- a/Documentation/virt/kvm/review-checklist.rst
+++ b/Documentation/virt/kvm/review-checklist.rst
@@ -18,22 +18,30 @@ Review checklist for kvm patches
 5.  New features must default to off (userspace should explicitly request them).
     Performance improvements can and should default to on.
 
-6.  New cpu features should be exposed via KVM_GET_SUPPORTED_CPUID2,
+6.  Guest-visible changes must not break migration compatibility.  A guest
+    migrated from an older kernel must be able to run with its original
+    observable environment, and a guest launched on a newer kernel must be
+    configurable to match the older kernel's feature set for rollback.
+    Where a change alters guest-visible behaviour, provide a mechanism
+    (capability, device attribute, etc.) for userspace to select the
+    previous behaviour.
+
+7.  New cpu features should be exposed via KVM_GET_SUPPORTED_CPUID2,
     or its equivalent for non-x86 architectures
 
-7.  The feature should be testable (see below).
+8.  The feature should be testable (see below).
 
-8.  Changes should be vendor neutral when possible.  Changes to common code
+9.  Changes should be vendor neutral when possible.  Changes to common code
     are better than duplicating changes to vendor code.
 
-9.  Similarly, prefer changes to arch independent code than to arch dependent
+10. Similarly, prefer changes to arch independent code than to arch dependent
     code.
 
-10. User/kernel interfaces and guest/host interfaces must be 64-bit clean
+11. User/kernel interfaces and guest/host interfaces must be 64-bit clean
     (all variables and sizes naturally aligned on 64-bit; use specific types
     only - u64 rather than ulong).
 
-11. New guest visible features must either be documented in a hardware manual
+12. New guest visible features must either be documented in a hardware manual
     or be accompanied by documentation.
 
 Testing of KVM code
-- 
2.43.0



[-- Attachment #2: smime.p7s --]
[-- Type: application/pkcs7-signature, Size: 5069 bytes --]

^ permalink raw reply related

* Re: [PATCH 0/3] Documentation/gpu: tables of contents cleanups and fixes
From: Jani Nikula @ 2026-05-11  8:50 UTC (permalink / raw)
  To: dri-devel, linux-doc, Maxime Ripard, Thomas Zimmermann,
	Maarten Lankhorst, Jonathan Corbet
In-Reply-To: <cover.1778238671.git.jani.nikula@intel.com>

On Fri, 08 May 2026, Jani Nikula <jani.nikula@intel.com> wrote:
> Make the GPU documentation slightly easier to navigate.

Maxime, Thomas, Maarten, Jon -

Any preferences which tree to merge this through? I'm thinking either
drm-misc-next or docs-next.

BR,
Jani.


>
> Jani Nikula (3):
>   Documentation/gpu: limit main toctree depth to 2
>   Documentation/gpu: add some tables of contents to large documents
>   Documentation/gpu/rfc: fix toctree
>
>  Documentation/gpu/driver-uapi.rst     |  2 ++
>  Documentation/gpu/drm-internals.rst   |  2 ++
>  Documentation/gpu/drm-kms-helpers.rst |  2 ++
>  Documentation/gpu/drm-kms.rst         |  2 ++
>  Documentation/gpu/drm-mm.rst          |  2 ++
>  Documentation/gpu/drm-ras.rst         |  2 ++
>  Documentation/gpu/drm-uapi.rst        |  4 +++-
>  Documentation/gpu/drm-usage-stats.rst |  2 ++
>  Documentation/gpu/index.rst           |  1 +
>  Documentation/gpu/introduction.rst    |  2 ++
>  Documentation/gpu/rfc/index.rst       | 26 ++++++--------------------
>  11 files changed, 26 insertions(+), 21 deletions(-)

-- 
Jani Nikula, Intel

^ permalink raw reply

* Re: [RFC net-next 0/4] devlink: Add boot-time defaults
From: Jiri Pirko @ 2026-05-11  8:42 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Mark Bloch, Eric Dumazet, Paolo Abeni, Andrew Lunn,
	David S. Miller, Jonathan Corbet, Shuah Khan, Simon Horman,
	Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Andrew Morton,
	Borislav Petkov (AMD), Randy Dunlap, Dave Hansen,
	Christian Brauner, Petr Mladek, Peter Zijlstra (Intel),
	Thomas Gleixner, Pawan Gupta, Dapeng Mi, Kees Cook, Marco Elver,
	Eric Biggers, Li RongQing, Paul E. McKenney, linux-doc,
	linux-kernel, netdev, linux-rdma
In-Reply-To: <20260510093732.6ba47e54@kernel.org>

Sun, May 10, 2026 at 06:37:32PM +0200, kuba@kernel.org wrote:
>On Sat, 9 May 2026 09:01:23 +0200 Jiri Pirko wrote:
>> Sat, May 09, 2026 at 02:52:13AM +0200, kuba@kernel.org wrote:
>> >On Fri, 8 May 2026 20:07:44 +0200 Jiri Pirko wrote:  
>> >legacy vs switchdev only describes the eswitch configuration.
>> >As a non-SR-IOV user I really don't want to see the extra representors
>> >hanging around my systems, confusing all daemons. IIRC mlx5 had some
>> >limitations around the uplink representor. Maybe that's the disconnect.
>> >But for a real, fully featured switchdev eswitches having the
>> >PHY and PF representors on boot, always, will not make sense.  
>> 
>> As "a non-SR-IOV user", what extra representors you talk about? When you
>> have pfs only, you don't have anything extra. Just 1 netdev per-pf, one
>> devlink port per-pf. What's extra about it? When you don't have VFs/SFs.
>> Everyhing is the same:
>
>Some devices have separate uplink ports and PF representors.
>As I said, what you're proposing isn't going to work for all drivers.

Well, the point is, mlx5 appears to the the one needing this, not other
drivers. What I'm trying to point at, mlx5 should not need this.
It makes things compicated, adding a ugly knob for no good reason.
Legacy/switchdev mode, in both, the non-sriov/eswitch user should not
see different behaviour. The mode is an eswitch attribute.

   devlink dev eswitch set - sets devlink device eswitch attributes
       mode { legacy | switchdev }
              Set eswitch mode

              legacy - Legacy SRIOV

              switchdev - SRIOV switchdev offloads


Briefly looking over other drivers, looks like ice, bnxt, octeon, sfc,
there is no new entity created in case of switching to switchdev mode.
The only driver that creates separate pf entities seems to be nfp,
but the mode seems to be determined by the app being run (loaded
firmware).

Am I missing something?


>
>> >> Well, as any other nv config, it persists across kernels/hosts.
>> >> Think about it as "unbreak-my-not-legacy-device" bit.  
>> >
>> >For most devices the switchdev mode does not change anything
>> >substantial about the device. It's purely a kernel / driver config. 
>> >It changes what objects and default rules kernel / driver installs. 
>> >So I don't get why it would make sense to flash into the device
>> >nvmem a Linux SW stack specific config.  
>> 
>> I look at it from the perspective that from some CX generation,
>> switchdev mode should be default. So that is a device-based decision.
>> I believe as such it can optionally be permanenty configured (nv config)
>> on older device. Why not?
>
>Feels a bit arbitrary and won't cover all cases. The question should be

What cases it does not cover? I don't follow.


>why you are nacking a more reasonable solution. Keeping Linux config in
>Linux params.

What's reasonable about adding basically a module option (kernel cmdline
is pretty much the same) for no reason?


^ permalink raw reply

* Re: [PATCH] docs/zh_CN: update admin-guide/index.rst translation
From: kernel test robot @ 2026-05-11  8:39 UTC (permalink / raw)
  To: Yan Zhu, corbet, alexs, si.yanteng, kees
  Cc: oe-kbuild-all, skhan, dzm91, tony.luck, gpiccoli, frederic,
	jani.nikula, longman, mchehab+huawei, linux-doc, linux-kernel,
	Yan Zhu
In-Reply-To: <tencent_7ADF2D1EBD8EAD2028BC93BA7858EA655D0A@qq.com>

Hi Yan,

kernel test robot noticed the following build warnings:

[auto build test WARNING on lwn/docs-next]
[also build test WARNING on linus/master v7.1-rc3 next-20260508]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Yan-Zhu/docs-zh_CN-update-admin-guide-index-rst-translation/20260511-102406
base:   git://git.lwn.net/linux.git docs-next
patch link:    https://lore.kernel.org/r/tencent_7ADF2D1EBD8EAD2028BC93BA7858EA655D0A%40qq.com
patch subject: [PATCH] docs/zh_CN: update admin-guide/index.rst translation
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
docutils: docutils (Docutils 0.21.2, Python 3.13.5, on linux)
reproduce: (https://download.01.org/0day-ci/archive/20260511/202605111009.hlpiVkT6-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605111009.hlpiVkT6-lkp@intel.com/

All warnings (new ones prefixed by >>):

   Checksumming on output with GSO
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [docutils]
   MAINTAINERS:40: WARNING: Inline strong start-string without end-string. [docutils]
>> Documentation/translations/zh_CN/admin-guide/index.rst:114: WARNING: toctree contains reference to nonexisting document 'translations/zh_CN/admin-guide/module-signing' [toc.not_readable]
   Documentation/userspace-api/landlock:504: ./security/landlock/errata/abi-4.h:5: ERROR: Unexpected section title.


vim +114 Documentation/translations/zh_CN/admin-guide/index.rst

   113	
 > 114	.. toctree::
   115	   :maxdepth: 1
   116	
   117	   cpu-load
   118	   mm/index
   119	   module-signing
   120	   numastat
   121	
   122	
   123	Todolist:
   124	

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [RFC net-next 0/4] devlink: Add boot-time defaults
From: Jiri Pirko @ 2026-05-11  8:07 UTC (permalink / raw)
  To: Mark Bloch
  Cc: Jakub Kicinski, Eric Dumazet, Paolo Abeni, Andrew Lunn,
	David S. Miller, Jonathan Corbet, Shuah Khan, Simon Horman,
	Saeed Mahameed, Leon Romanovsky, Tariq Toukan, Andrew Morton,
	Borislav Petkov (AMD), Randy Dunlap, Dave Hansen,
	Christian Brauner, Petr Mladek, Peter Zijlstra (Intel),
	Thomas Gleixner, Pawan Gupta, Dapeng Mi, Kees Cook, Marco Elver,
	Eric Biggers, Li RongQing, Paul E. McKenney, linux-doc,
	linux-kernel, netdev, linux-rdma
In-Reply-To: <580a774b-ba9e-4523-b43a-476f75dd5b12@nvidia.com>

Sun, May 10, 2026 at 02:31:35PM +0200, mbloch@nvidia.com wrote:
>
>
>On 09/05/2026 10:01, Jiri Pirko wrote:
>> Sat, May 09, 2026 at 02:52:13AM +0200, kuba@kernel.org wrote:
>>> On Fri, 8 May 2026 20:07:44 +0200 Jiri Pirko wrote:
>>>>> I don't think switchdev by default should mean CX4+ in general. If we get
>>>>> there, I would expect it to be limited to the DPU/BlueField/ECPF case, where
>>>>> the host PF probe path can depend on the ECPF reaching switchdev. Changing the
>>>>> default for regular host NIC deployments feels like a much larger compatibility
>>>>> change.  
>>>>
>>>> We can't travel throught time, but if from CX5 onwards the default would
>>>> be switchdev, nobody would feel broken in terms of compatibility. That
>>>> is my point. Having "legacy" as default is simply wrong for never NIC
>>>> generations. That is why it is called "legacy" and it should have been
>>>> rotten through and out since CX4 times.
>>>
>>> legacy vs switchdev only describes the eswitch configuration.
>>> As a non-SR-IOV user I really don't want to see the extra representors
>>> hanging around my systems, confusing all daemons. IIRC mlx5 had some
>>> limitations around the uplink representor. Maybe that's the disconnect.
>>> But for a real, fully featured switchdev eswitches having the
>>> PHY and PF representors on boot, always, will not make sense.
>> 
>> As "a non-SR-IOV user", what extra representors you talk about? When you
>> have pfs only, you don't have anything extra. Just 1 netdev per-pf, one
>> devlink port per-pf. What's extra about it? When you don't have VFs/SFs.
>> Everyhing is the same:
>
>The netdev list looking similar is a bit misleading. What matters here is
>not only how many netdevs show up, but what that netdev actually is.
>
>In legacy mode, a PF only user can just use the PF netdev as a regular NIC
>and use ROCE on it directly.

I don't see why we have this limitation. Sounds more like a bug to me.
The netdev is still the same, capable of the same things no matter in
which mode you have it. RoCE should work on it in both modes.


>
>In switchdev mode, even if there are no VFs or SFs yet, the PF is moved into
>the switchdev model and the visible netdev is the uplink representor. That is
>not the same thing from a user point of view. The uplink representor is not a
>ROCE capable endpoint. So a user who used to boot the machine and use ROCE on
>the PF now has to create a VF or SF, use that as the roce endpoint, and also
>set up the switchdev forwarding path with tc, bridge or OVS so traffic from
>that function actually reaches the wire.
>
>That is why I don't think this is only a card generation question. It changes
>the deployment model. It may be the right default for BlueField/ECPF style
>systems, where the host is expected to sit behind a switchdev control plane,
>but it is not a safe default for every regular host NIC setup.

Yeah, the point is, not to change deployment model. The legacy/switchdev
should only change behaviour for sriov/eswitch usecase. The rest
(PF/uplink netdev and related objects) should stay the same.


>
>> 
>> c-220-136-220-218:~$ sudo devlink dev eswitch show pci/0000:08:00.0
>> pci/0000:08:00.0: mode switchdev inline-mode none encap-mode basic
>> c-220-136-220-218:~$ sudo devlink dev eswitch show pci/0000:08:00.1
>> pci/0000:08:00.1: mode legacy inline-mode none encap-mode basic
>> c-220-136-220-218:~$ devlink dev
>> pci/0000:08:00.0: index 0
>>   nested_devlink:
>>     auxiliary/mlx5_core.eth.0
>> devlink_index/1: index 1
>>   nested_devlink:
>>     pci/0000:08:00.0
>>     pci/0000:08:00.1
>> auxiliary/mlx5_core.eth.0: index 2
>> pci/0000:08:00.1: index 3
>>   nested_devlink:
>>     auxiliary/mlx5_core.eth.1
>> auxiliary/mlx5_core.eth.1: index 4
>> c-220-136-220-218:~$ devlink port
>> auxiliary/mlx5_core.eth.0/65535: type eth netdev eth2 flavour physical port 0 splittable false
>> auxiliary/mlx5_core.eth.1/131071: type eth netdev eth3 flavour physical port 1 splittable false
>> c-220-136-220-218:~$ ip link
>> ...
>> 4: eth2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
>>     link/ether b8:e9:24:f2:b7:6c brd ff:ff:ff:ff:ff:ff
>>     altname enp8s0f0np0
>> 5: eth3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
>>     link/ether b8:e9:24:f2:b7:6d brd ff:ff:ff:ff:ff:ff
>>     altname enp8s0f1np1
>> 
>> 
>>>
>>> IOW it's not a question of the generation of the card but of
>>> the deployment type / use case.
>> 
>> I don't think so, not in the case of mlx5. The difference is only when
>> you work with sr-iov, you either use legacy way (ip vf) or the new one.
>> Same usecase.
>> 
>> 
>>>
>>>>> For the ASIC/NV bit: maybe technically possible, but it feels like the wrong
>>>>> layer. This is boot/deployment policy, not a persistent hardware property, and
>>>>> storing it in NV memory would make the state persist across kernels/hosts in a
>>>>> surprising way.  
>>>>
>>>> Well, as any other nv config, it persists across kernels/hosts. Think
>>>> about it as "unbreak-my-not-legacy-device" bit.
>>>
>>> For most devices the switchdev mode does not change anything
>>> substantial about the device. It's purely a kernel / driver config. 
>>> It changes what objects and default rules kernel / driver installs. 
>>> So I don't get why it would make sense to flash into the device
>>> nvmem a Linux SW stack specific config.
>> 
>> I look at it from the perspective that from some CX generation,
>> switchdev mode should be default. So that is a device-based decision.
>> I believe as such it can optionally be permanenty configured (nv config)
>> on older device. Why not?
>
>This is a deployment policy decision, not a permanent property of the card.
>The same adapter can be used in a regular host/RDMA setup or in a
>switchdev/offload setup. If we store this in NVM, that Linux switchdev policy
>follows the device across hosts, kernels and use cases, and can surprise the
>next deployment that just expects a normal NIC.

Yeah, from my perspective, there should be not surprise/behaviour_change
for non-sriov/eswitch user. Then switchdev can be default and everyone
is happy. Why to complicate things?


>
>I'll send another RFC v2 with support limited to:
>devlink=[...]:esw:mode:{ switchdev | switchdev_inactive | legacy }
>and let's see where we land with that.
>
>I still think a small kernel command line knob is the cleanest way to get to
>"switchdev by default" without making the interface too broad. For more
>complex boot-time configuration, I agree that a devlinkd or similar userspace
>path is probably the better direction.
>
>The "pause probing until userspace configures devlink" idea feels less clear
>to me. It is not quite the simple boot policy knob, and not quite the full
>userspace policy manager either. It would add a new probe state and require
>early userspace orchestration before the device is fully materialized. At
>least for now, I would prefer either the small cmdline option for the simple
>global/default case, or a proper devlinkd-like solution for more complex
>policy. Between those, I still prefer the cmdline option for this specific
>early eswitch mode default.
>
>Mark
>
>> 
>> [...]
>

^ permalink raw reply

* Re: [PATCH 1/3] Documentation/gpu: add dedicated documentation for Intel display
From: Jani Nikula @ 2026-05-11  7:41 UTC (permalink / raw)
  To: Randy Dunlap, intel-gfx, intel-xe, dri-devel, linux-doc
  Cc: rodrigo.vivi, Matthew Brost, Thomas Hellström,
	joonas.lahtinen, tursulin
In-Reply-To: <4aba5b5e-75a5-4800-bedb-8f7cc673c7f7@infradead.org>

On Fri, 08 May 2026, Randy Dunlap <rdunlap@infradead.org> wrote:
> On 5/8/26 3:20 AM, Jani Nikula wrote:
>> diff --git a/Documentation/gpu/intel-display/index.rst b/Documentation/gpu/intel-display/index.rst
>> new file mode 100644
>> index 000000000000..8d40363b8f90
>> --- /dev/null
>> +++ b/Documentation/gpu/intel-display/index.rst
>> @@ -0,0 +1,40 @@
>> +.. SPDX-License-Identifier: MIT
>> +.. Copyright © 2026 Intel Corporation
>> +
>> +.. _drm/intel-display:
>> +
>> +====================
>> +Intel Display Driver
>> +====================
>> +
>> +The Intel display driver provides the display, or :ref:`drm-kms`, support for
>> +both the :ref:`drm/xe <drm/xe>` and :ref:`drm/i915 <drm/i915>` Intel GPU
>> +drivers.
>> +
>> +The source code currently resides under ``drivers/gpu/drm/i915/display`` due to
>> +historical reasons, and it's compiled separately into both drm/xe and drm/i915
>> +kernel modules.
>> +
>> +The drm/xe and drm/i915 drivers are the "core" or "parent" drivers for display,
>> +as they initialize and own the drm device, and pass that on to the display
>> +driver. The display driver isn't an independent driver in that sense.
>> +
>> +.. toctree::
>> +   :maxdepth: 1
>> +   :caption: Detailed display topics
>> +
>> +   async-flip
>> +   audio
>> +   cdclk
>> +   dmc
>> +   dpio
>> +   dpll
>> +   drrs
>> +   dsb
>> +   fbc
>> +   fifo-underrun
>> +   frontbuffer
>> +   hotplug
>> +   plane
>> +   psr
>> +   vbt
>
> Is this in almost-alphabetical order or just random?  :)

The above list is alphabetical, but the generated output does seem to be
more random due to the headings. This is in need of better organization
anyway, and this is just a step in the right direction, so I'll roll
with this.

> Tested-by: Randy Dunlap <rdunlap@infradead.org>

Thanks for the reviews and acks and testing, pushed to drm-intel-next.

BR,
Jani.


-- 
Jani Nikula, Intel

^ permalink raw reply

* Re: [PATCH v16 00/12] crypto/dmaengine: qce: introduce BAM locking and use DMA for register I/O
From: Bartosz Golaszewski @ 2026-05-11  7:38 UTC (permalink / raw)
  To: Vinod Koul
  Cc: Bartosz Golaszewski, Jonathan Corbet, Thara Gopinath, Herbert Xu,
	David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
	Stephan Gerhold, Bjorn Andersson, Peter Ujfalusi, Michal Simek,
	Frank Li, dmaengine, linux-doc, linux-kernel, linux-arm-msm,
	linux-crypto, linux-arm-kernel, Bartosz Golaszewski,
	Dmitry Baryshkov, Konrad Dybcio, Manivannan Sadhasivam
In-Reply-To: <ditrkd5jcxlx7onykxh6n3qhyoclfngmpp277y4t4qwc4vswoo@5os4o5lumidn>

On Thu, May 7, 2026 at 11:55 AM Manivannan Sadhasivam <mani@kernel.org> wrote:
>
> On Mon, Apr 27, 2026 at 11:15:33AM +0200, Bartosz Golaszewski wrote:
> > This missed the v7.1 cycle so let's try to get it in for v7.2.
> >
> > Merging strategy: there are build-time dependencies between the crypto
> > and DMA patches so the best approach is for Vinod to create an immutable
> > branch with the DMA part pulled in by the crypto tree.
> >
> > This iteration continues to build on top of v12 but uses the BAM's NWD
> > bit on data descriptors as suggested by Stephan. To that end, there are
> > some more changes like reversing the order of command and data
> > descriptors queuedy by the QCE driver.
> >
> > Currently the QCE crypto driver accesses the crypto engine registers
> > directly via CPU. Trust Zone may perform crypto operations simultaneously
> > resulting in a race condition. To remedy that, let's introduce support
> > for BAM locking/unlocking to the driver. The BAM driver will now wrap
> > any existing issued descriptor chains with additional descriptors
> > performing the locking when the client starts the transaction
> > (dmaengine_issue_pending()). The client wanting to profit from locking
> > needs to switch to performing register I/O over DMA and communicate the
> > address to which to perform the dummy writes via a call to
> > dmaengine_desc_attach_metadata().
> >
> > In the specific case of the BAM DMA this translates to sending command
> > descriptors performing dummy writes with the relevant flags set. The BAM
> > will then lock all other pipes not related to the current pipe group, and
> > keep handling the current pipe only until it sees the the unlock bit.
> >
> > In order for the locking to work correctly, we also need to switch to
> > using DMA for all register I/O.
> >
> > On top of this, the series contains some additional tweaks and
> > refactoring.
> >
> > The goal of this is not to improve the performance but to prepare the
> > driver for supporting decryption into secure buffers in the future.
> >
> > Tested with tcrypt.ko, kcapi and cryptsetup.
> >
> > Shout out to Daniel and Udit from Qualcomm for helping me out with some
> > DMA issues we encountered.
> >
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> > Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
>
> For the whole series,
>
> Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
>
> Thanks for incorporating all the comments, Bart!
>
> - Mani
>

Vinod: Can you please queue patches 1-5 on an immutable branch for
v7.2 and provide it to Herbert to queue the following crypto patches?

Thanks,
Bartosz

^ permalink raw reply

* Re: [PATCH v13 3/4] gpio: rpmsg: add generic rpmsg GPIO driver
From: Arnaud POULIQUEN @ 2026-05-11  7:10 UTC (permalink / raw)
  To: Mathieu Poirier
  Cc: Beleswar Prasad Padhi, Shenwei Wang, Andrew Lunn, Linus Walleij,
	Bartosz Golaszewski, Jonathan Corbet, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Bjorn Andersson, Frank Li,
	Sascha Hauer, Shuah Khan, linux-gpio@vger.kernel.org,
	linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org,
	Pengutronix Kernel Team, Fabio Estevam, Peng Fan,
	devicetree@vger.kernel.org, linux-remoteproc@vger.kernel.org,
	imx@lists.linux.dev, linux-arm-kernel@lists.infradead.org,
	dl-linux-imx, Bartosz Golaszewski
In-Reply-To: <afzIABSh1xtMEGbf@p14s>

Hello Mathieu,

[...]
>>
>> A third option would be a combination of both approaches: instantiate the
>> device using the same name service from the remote side, as done in
>> rpmsg-tty. In that case, a get_config message, or a similar mechanism, would
>> also be needed to retrieve the port information from the remote side.
>>
> 
> I'm not overly fond of a get_config message because it is one more thing we
> have to define and maintain.
> 
> Arnaud: is there a get_config message already defined for rpmsg_tty?

No there isn't.

Regards,
Arnaud

> 
> Beleswar: Can you provide a link to a virtio device that would use a get_config
> message?
>   
>> Tanmaya also proposed another alternative based on reserved addresses.
>>
>> At this point, I suggest letting Mathieu review the discussion and recommend
>> the most suitable approach.
>>
>> Thanks,
>> Arnaud
>>
>>>>
>>>> At the end, whatever solution is implemented, my main concern is that the
>>>> Linux driver design should, if possible, avoid adding unnecessary complexity
>>>> or limitations on the remote side (for instance in openAMP project).
>>>
>>>
>>> Yes definitely, I want the same. Feel free to let me know if this does
>>> not suit with the OpenAMP project.
>>>
>>> Thanks,
>>> Beleswar
>>>
>>>>
>>>> Thanks,
>>>> Arnaud
>>>>
>>>>
>>>>> So Linux does not need to send the port idx everytime while sending a
>>>>> gpio message anymore.
>>>>>
>>>>> Thanks,
>>>>> Beleswar
>>>>>
>>>>> [...]
>>>>>
>>>>
>>


^ permalink raw reply

* Re: [PATCH] docs: Update nosmt support for arm64
From: Jinjie Ruan @ 2026-05-11  6:17 UTC (permalink / raw)
  To: corbet, skhan, akpm, bp, rdunlap, pmladek, pawan.kumar.gupta,
	feng.tang, dapeng1.mi, kees, elver, paulmck, lirongqing,
	safinaskar, bhelgaas, linux-doc, linux-kernel, skelley
In-Reply-To: <20260417032540.3720627-1-ruanjinjie@huawei.com>

Gentle ping.

On 4/17/2026 11:25 AM, Jinjie Ruan wrote:
> commit eed4583bcf9a6 ("arm64: Kconfig: Enable HOTPLUG_SMT") enable
> HOTPLUG_SMT for SMT control for arm64, but the documentation was
> not updated accordingly to reflect that ARM64 now supports control SMT
> via boot parameter and sysfs knobs:
> 
> 1. Boot parameters:
> 
> nosmt:          Disable SMT, can be enabled via sysfs knobs.
> nosmt=force:    Disable SMT, cannot be enabled via sysfs knobs.
> 
> 2. Runtime sysfs controls:
> 
> Write "on", "off", "forceoff" or the number of SMT threads (1, 2, ...)
> to /sys/devices/system/cpu/smt/control.
> 
> Signed-off-by: Jinjie Ruan <ruanjinjie@huawei.com>
> ---
>  Documentation/admin-guide/kernel-parameters.txt | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
> index cb850e5290c2..6a73eb5abae9 100644
> --- a/Documentation/admin-guide/kernel-parameters.txt
> +++ b/Documentation/admin-guide/kernel-parameters.txt
> @@ -4661,7 +4661,7 @@ Kernel parameters
>  	nosmt		[KNL,MIPS,PPC,EARLY] Disable symmetric multithreading (SMT).
>  			Equivalent to smt=1.
>  
> -			[KNL,LOONGARCH,X86,PPC,S390] Disable symmetric multithreading (SMT).
> +			[KNL,LOONGARCH,X86,ARM64,PPC,S390] Disable symmetric multithreading (SMT).
>  			nosmt=force: Force disable SMT, cannot be undone
>  				     via the sysfs control file.
>  


^ permalink raw reply

* [PATCH RFC v4 18/18] riscv: enable resctrl filesystem for Ssqosid
From: Drew Fustini @ 2026-05-11  5:11 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Radim Krčmář, Samuel Holland, Adrien Ricciardi,
	Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
	Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
	Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
	Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
	Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
	Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
	Len Brown, Robert Moore, Sunil V L, Drew Fustini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	Jonathan Corbet
  Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
	devicetree, Paul Walmsley, Conor Dooley, linux-rt-devel,
	linux-doc, Palmer Dabbelt
In-Reply-To: <20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683@kernel.org>

RISCV_ISA_SSQOSID selects RISCV_CBQRI_DRIVER, which in turn depends
on RESCTRL_FS. Enabling the resctrl filesystem itself stays a user
choice via the standard fs/Kconfig MISC_FILESYSTEMS menu.

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

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

-- 
2.43.0


^ permalink raw reply related

* [PATCH RFC v4 17/18] ACPI: RISC-V: Add support for RISC-V Quality of Service Controller (RQSC)
From: Drew Fustini @ 2026-05-11  5:11 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Radim Krčmář, Samuel Holland, Adrien Ricciardi,
	Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
	Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
	Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
	Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
	Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
	Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
	Len Brown, Robert Moore, Sunil V L, Drew Fustini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	Jonathan Corbet
  Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
	devicetree, Paul Walmsley, Conor Dooley, linux-rt-devel,
	linux-doc, Palmer Dabbelt
In-Reply-To: <20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683@kernel.org>

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

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

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

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

-- 
2.43.0


^ permalink raw reply related

* [PATCH RFC v4 16/18] ACPI: RISC-V: Parse RISC-V Quality of Service Controller (RQSC) table
From: Drew Fustini @ 2026-05-11  5:11 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Radim Krčmář, Samuel Holland, Adrien Ricciardi,
	Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
	Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
	Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
	Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
	Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
	Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
	Len Brown, Robert Moore, Sunil V L, Drew Fustini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	Jonathan Corbet
  Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
	devicetree, Paul Walmsley, Conor Dooley, linux-rt-devel,
	linux-doc, Palmer Dabbelt
In-Reply-To: <20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683@kernel.org>

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

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

diff --git a/MAINTAINERS b/MAINTAINERS
index 5589fe766153..3cf3cfa7e6f2 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -23014,6 +23014,8 @@ S:	Supported
 F:	arch/riscv/include/asm/qos.h
 F:	arch/riscv/include/asm/resctrl.h
 F:	arch/riscv/kernel/qos.c
+F:	drivers/acpi/riscv/rqsc.c
+F:	drivers/acpi/riscv/rqsc.h
 F:	drivers/resctrl/cbqri_devices.c
 F:	drivers/resctrl/cbqri_internal.h
 F:	drivers/resctrl/cbqri_resctrl.c
diff --git a/arch/riscv/include/asm/acpi.h b/arch/riscv/include/asm/acpi.h
index 26ab37c171bc..3cfd0102085e 100644
--- a/arch/riscv/include/asm/acpi.h
+++ b/arch/riscv/include/asm/acpi.h
@@ -67,6 +67,16 @@ int acpi_get_riscv_isa(struct acpi_table_header *table,
 
 void acpi_get_cbo_block_size(struct acpi_table_header *table, u32 *cbom_size,
 			     u32 *cboz_size, u32 *cbop_size);
+
+#ifdef CONFIG_RISCV_CBQRI_DRIVER
+int __init acpi_parse_rqsc(struct acpi_table_header *table);
+#else
+static inline int acpi_parse_rqsc(struct acpi_table_header *table)
+{
+	return -EINVAL;
+}
+#endif /* CONFIG_RISCV_CBQRI_DRIVER */
+
 #else
 static inline void acpi_init_rintc_map(void) { }
 static inline struct acpi_madt_rintc *acpi_cpu_get_madt_rintc(int cpu)
diff --git a/drivers/acpi/riscv/Makefile b/drivers/acpi/riscv/Makefile
index 1284a076fa88..77f8f0101b7e 100644
--- a/drivers/acpi/riscv/Makefile
+++ b/drivers/acpi/riscv/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-y					+= rhct.o init.o irq.o
+obj-$(CONFIG_RISCV_CBQRI_DRIVER)	+= rqsc.o
 obj-$(CONFIG_ACPI_PROCESSOR_IDLE)	+= cpuidle.o
 obj-$(CONFIG_ACPI_CPPC_LIB)		+= cppc.o
 obj-$(CONFIG_ACPI_RIMT)			+= rimt.o
diff --git a/drivers/acpi/riscv/rqsc.c b/drivers/acpi/riscv/rqsc.c
new file mode 100644
index 000000000000..ac3d43b13f3b
--- /dev/null
+++ b/drivers/acpi/riscv/rqsc.c
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "ACPI: RQSC: " fmt
+
+#include <linux/acpi.h>
+#include <linux/bits.h>
+#include <linux/riscv_cbqri.h>
+
+#include "rqsc.h"
+
+#define CBQRI_CTRL_SIZE 0x1000
+
+int __init acpi_parse_rqsc(struct acpi_table_header *table)
+{
+	struct acpi_table_rqsc *rqsc = (struct acpi_table_rqsc *)table;
+	struct acpi_rqsc_node *end, *node;
+	int num_controllers = 0;
+
+	/* Reject tables shorter than the fixed RQSC header. */
+	if (rqsc->header.length < sizeof(struct acpi_table_rqsc)) {
+		pr_err("RQSC table truncated: length %u < %zu, aborting\n",
+		       rqsc->header.length, sizeof(struct acpi_table_rqsc));
+		return -EINVAL;
+	}
+
+	end = ACPI_ADD_PTR(struct acpi_rqsc_node, rqsc, rqsc->header.length);
+
+	for (node = ACPI_ADD_PTR(struct acpi_rqsc_node, rqsc,
+				 sizeof(struct acpi_table_rqsc));
+	     node < end;
+	     node = ACPI_ADD_PTR(struct acpi_rqsc_node, node, node->length)
+	) {
+		const struct acpi_rqsc_resource *res0;
+		struct cbqri_controller_info info = {};
+		int ret;
+
+		if ((void *)node + sizeof(*node) > (void *)end) {
+			pr_err("truncated entry at end of table, aborting\n");
+			riscv_cbqri_unregister_last(num_controllers);
+			return -EINVAL;
+		}
+
+		if (node->length < sizeof(*node)) {
+			pr_err("malformed RQSC entry: length %u < %zu, aborting\n",
+			       node->length, sizeof(*node));
+			riscv_cbqri_unregister_last(num_controllers);
+			return -EINVAL;
+		}
+
+		/* GAS must describe system memory. ioremap() consumes it later. */
+		if (node->reg.space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) {
+			pr_warn("controller has unsupported address space_id=%u, skipping\n",
+				node->reg.space_id);
+			continue;
+		}
+
+		/* Address 0 would map page 0 (reset vectors, SBI, boot ROM). */
+		if (!node->reg.address) {
+			pr_warn("controller has zero address, skipping\n");
+			continue;
+		}
+
+		info.type = node->type;
+		/* RQSC v0.9.2 section 2 Table 2: 12-byte GAS-format register interface address */
+		info.addr = node->reg.address;
+		info.size = CBQRI_CTRL_SIZE;
+		info.rcid_count = node->rcid;
+		info.mcid_count = node->mcid;
+
+		/* See CBQRI_MAX_RCID/MCID in <linux/riscv_cbqri.h> for the rationale. */
+		if (info.rcid_count > CBQRI_MAX_RCID) {
+			pr_warn("controller at %pa: rcid_count %u exceeds CBQRI_MAX_RCID %u, skipping\n",
+				&info.addr, info.rcid_count, CBQRI_MAX_RCID);
+			continue;
+		}
+
+		if (info.mcid_count > CBQRI_MAX_MCID) {
+			pr_warn("controller at %pa: mcid_count %u exceeds CBQRI_MAX_MCID %u, skipping\n",
+				&info.addr, info.mcid_count, CBQRI_MAX_MCID);
+			continue;
+		}
+
+		if (node->nres == 0) {
+			pr_warn("controller at %pa has no resource descriptors, skipping\n",
+				&info.addr);
+			continue;
+		}
+
+		/*
+		 * Resources follow the node header in-line. Only res[0] is
+		 * consumed. Bound it against end before reading its prefix so
+		 * a table that ends partway through a resource subtable is
+		 * rejected rather than read past the mapping.
+		 */
+		res0 = (const struct acpi_rqsc_resource *)
+		       ((const u8 *)node + sizeof(*node));
+		if ((void *)res0 + sizeof(*res0) > (void *)end ||
+		    node->length < sizeof(*node) + sizeof(*res0) ||
+		    res0->length < sizeof(*res0)) {
+			pr_warn("controller at %pa: node too short for resource descriptor, skipping\n",
+				&info.addr);
+			continue;
+		}
+
+		if (node->nres > 1)
+			pr_warn("controller at %pa has %u resource descriptors, using first\n",
+				&info.addr, node->nres);
+
+		/*
+		 * id1 is u64 on the wire but cache_id and prox_dom are u32
+		 * downstream (PPTT cache_id, ACPI proximity domain). Reject
+		 * rather than truncate, so a too-large id is not silently
+		 * mapped to the wrong PPTT entry or NUMA node.
+		 */
+		if (res0->id1 > U32_MAX) {
+			pr_warn("controller at %pa: id1 0x%llx exceeds u32, skipping\n",
+				&info.addr, res0->id1);
+			continue;
+		}
+
+		switch (info.type) {
+		case CBQRI_CONTROLLER_TYPE_CAPACITY:
+			info.cache_id = (u32)res0->id1;
+			break;
+		case CBQRI_CONTROLLER_TYPE_BANDWIDTH:
+			info.prox_dom = (u32)res0->id1;
+			break;
+		default:
+			pr_warn("controller at %pa: unknown type %u, skipping\n",
+				&info.addr, info.type);
+			continue;
+		}
+
+		pr_debug("registering controller type=%u addr=%pa rcid=%u mcid=%u\n",
+			 info.type, &info.addr, info.rcid_count, info.mcid_count);
+
+		ret = riscv_cbqri_register_controller(&info);
+		if (ret == 0)
+			num_controllers++;
+		else
+			pr_warn("controller at %pa: registration failed (%d), skipping\n",
+				&info.addr, ret);
+	}
+
+	pr_info("found %d CBQRI controllers\n", num_controllers);
+	return 0;
+}
diff --git a/drivers/acpi/riscv/rqsc.h b/drivers/acpi/riscv/rqsc.h
new file mode 100644
index 000000000000..7bea15cb26d8
--- /dev/null
+++ b/drivers/acpi/riscv/rqsc.h
@@ -0,0 +1,52 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Local definitions for the RISC-V Quality of Service Controller (RQSC)
+ * ACPI table. Will move to ACPICA's include/acpi/actbl2.h once the spec
+ * is ratified.
+ */
+#ifndef _DRIVERS_ACPI_RISCV_RQSC_H
+#define _DRIVERS_ACPI_RISCV_RQSC_H
+
+#include <linux/types.h>
+#include <acpi/actbl.h>
+
+#define ACPI_SIG_RQSC	"RQSC"	/* RISC-V Quality of Service Controller */
+
+/*
+ * Byte-packed: u64 id1 would otherwise pad to 8-byte alignment and inflate
+ * sizeof(*res) from the spec's 20 bytes to 24, mis-sizing resource subtables.
+ */
+struct acpi_rqsc_resource {
+	u8 type;
+	u8 resv;
+	u16 length;
+	u16 flags;
+	u8 resv2;
+	u8 id_type;
+	u64 id1;
+	u32 id2;
+} __packed;
+
+struct acpi_rqsc_node {
+	u8 type;
+	u8 resv;
+	u16 length;
+	/* RQSC v0.9.2 section 2 Table 2: 12-byte GAS-format register interface address */
+	struct acpi_generic_address reg;
+	u16 rcid;
+	u16 mcid;
+	u16 flags;
+	u16 nres;
+	/*
+	 * Followed by nres acpi_rqsc_resource subtables. Walk them via
+	 * each resource's own length field so a future RQSC revision that
+	 * extends the resource layout cannot misalign older parsers.
+	 */
+} __packed;
+
+struct acpi_table_rqsc {
+	struct acpi_table_header header;	/* Common ACPI table header */
+	u32 num;
+} __packed;
+
+#endif /* _DRIVERS_ACPI_RISCV_RQSC_H */

-- 
2.43.0


^ permalink raw reply related

* [PATCH RFC v4 15/18] riscv_cbqri: resctrl: Add mbm_total_bytes bandwidth monitoring
From: Drew Fustini @ 2026-05-11  5:11 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Radim Krčmář, Samuel Holland, Adrien Ricciardi,
	Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
	Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
	Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
	Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
	Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
	Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
	Len Brown, Robert Moore, Sunil V L, Drew Fustini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	Jonathan Corbet
  Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
	devicetree, Paul Walmsley, Conor Dooley, linux-rt-devel,
	linux-doc, Palmer Dabbelt
In-Reply-To: <20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683@kernel.org>

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

mbm_local_bytes is not supported because the CBQRI spec has no way
to distinguish total versus local. Bandwidth monitoring is disabled
on platforms with more than one CBQRI bandwidth controller, since
the counter could not accurately attribute traffic across L3 domains.

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

diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
index 71ee8e610757..ccd48cac7ccd 100644
--- a/drivers/resctrl/cbqri_resctrl.c
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -30,6 +30,13 @@ struct cbqri_resctrl_res {
 struct cbqri_resctrl_dom {
 	struct rdt_ctrl_domain  resctrl_ctrl_dom;
 	struct cbqri_controller *hw_ctrl;
+	/*
+	 * For an L3 capacity controller paired with a bandwidth controller
+	 * of matching topology, paired_bc caches that BC so mbm_total_bytes
+	 * reads / resets don't have to walk cbqri_controllers on every hit.
+	 * NULL for non-L3 domains and L3s without a paired BC.
+	 */
+	struct cbqri_controller *paired_bc;
 };
 
 static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
@@ -38,7 +45,7 @@ static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
  * Per-event controller table. Only events CBQRI can back occupy a
  * slot, so other events do not bloat the array.
  */
-#define CBQRI_MAX_EVENT QOS_L3_OCCUP_EVENT_ID
+#define CBQRI_MAX_EVENT QOS_L3_MBM_TOTAL_EVENT_ID
 static struct cbqri_controller *cbqri_resctrl_counters[CBQRI_MAX_EVENT + 1];
 
 /*
@@ -239,6 +246,36 @@ void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d
 		mutex_unlock(&ctrl->lock);
 		return;
 
+	case QOS_L3_MBM_TOTAL_EVENT_ID: {
+		struct cbqri_controller *bc;
+
+		cd = cbqri_find_ctrl_domain(&r->ctrl_domains, d->hdr.id);
+		if (!cd)
+			return;
+		hw_dom = container_of(cd, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+		bc = hw_dom->paired_bc;
+		if (!bc)
+			return;
+		if (WARN_ON_ONCE(!bc->mbm_total_states))
+			return;
+		if (rmid >= bc->mcid_count)
+			return;
+
+		mutex_lock(&bc->lock);
+		/*
+		 * CONFIG_EVENT both resets and re-arms. Skip the accumulator
+		 * memset on failure. A stale hardware counter X with
+		 * prev_ctr=0 would inject overflow(0, X) on the next read.
+		 */
+		if (!cbqri_mon_op(bc, CBQRI_BC_MON_CTL_OFF,
+				  CBQRI_BC_MON_CTL_OP_CONFIG_EVENT, rmid,
+				  CBQRI_BC_EVT_ID_TOTAL_READ_WRITE, NULL))
+			memset(&bc->mbm_total_states[rmid], 0,
+			       sizeof(*bc->mbm_total_states));
+		mutex_unlock(&bc->lock);
+		return;
+	}
+
 	default:
 		return;
 	}
@@ -249,8 +286,11 @@ void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domai
 	int i;
 
 	/* Bound by max_rmid (system-wide minimum mcid_count). */
-	for (i = 0; i < max_rmid; i++)
+	for (i = 0; i < max_rmid; i++) {
 		resctrl_arch_reset_rmid(r, d, 0, i, QOS_L3_OCCUP_EVENT_ID);
+		/* mbm_total_bytes reset is a no-op for L3s without a paired BC. */
+		resctrl_arch_reset_rmid(r, d, 0, i, QOS_L3_MBM_TOTAL_EVENT_ID);
+	}
 }
 
 int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
@@ -308,6 +348,76 @@ int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
 		mutex_unlock(&ctrl->lock);
 		return err;
 
+	case QOS_L3_MBM_TOTAL_EVENT_ID: {
+		struct cbqri_controller *bc;
+
+		/*
+		 * The L3 monitoring domain's id is the L3 cache id. The
+		 * matching ctrl domain's hw_dom->paired_bc was cached at
+		 * add time to avoid walking cbqri_controllers on every read.
+		 */
+		d = cbqri_find_ctrl_domain(&r->ctrl_domains, hdr->id);
+		if (!d)
+			return -ENOENT;
+		hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+		bc = hw_dom->paired_bc;
+		if (!bc)
+			return -ENOENT;
+		if (WARN_ON_ONCE(!bc->mbm_total_states))
+			return -EIO;
+		if (rmid >= bc->mcid_count)
+			return -ERANGE;
+
+		mutex_lock(&bc->lock);
+		/* Pass EVT_ID explicitly. Same reason as the CC path above. */
+		err = cbqri_mon_op(bc, CBQRI_BC_MON_CTL_OFF,
+				   CBQRI_BC_MON_CTL_OP_READ_COUNTER, rmid,
+				   CBQRI_BC_EVT_ID_TOTAL_READ_WRITE, NULL);
+		if (err)
+			goto out_bc;
+
+		ctr_val = ioread64(bc->base + CBQRI_BC_MON_CTR_VAL_OFF);
+
+		if (ctr_val & CBQRI_BC_MON_CTR_VAL_INVALID) {
+			/*
+			 * Hardware marked the counter invalid (CBQRI 4.3:
+			 * controller could not establish an accurate count).
+			 * Return the last good total and leave prev_ctr so
+			 * the next valid sample resumes from there.
+			 */
+			*val = bc->mbm_total_states[rmid].chunks;
+		} else if (ctr_val & CBQRI_BC_MON_CTR_VAL_OVF) {
+			/*
+			 * CBQRI 4.3: OVF is sticky until next CONFIG_EVENT.
+			 * cbqri_bc_mon_overflow() can recover at most one
+			 * wrap. With OVF set the count is unknown, so re-arm
+			 * and re-anchor prev_ctr=0, losing one wrap-period.
+			 */
+			struct cbqri_bc_mon_state *s = &bc->mbm_total_states[rmid];
+
+			pr_warn_ratelimited("BC@%pa MCID %u: CTR overflow, bandwidth count loses ~one wrap-period; consider a wider CTR or a faster poll cadence\n",
+					    &bc->addr, rmid);
+			err = cbqri_mon_op(bc, CBQRI_BC_MON_CTL_OFF,
+					   CBQRI_BC_MON_CTL_OP_CONFIG_EVENT, rmid,
+					   CBQRI_BC_EVT_ID_TOTAL_READ_WRITE, NULL);
+			if (err)
+				goto out_bc;
+
+			s->prev_ctr = 0;
+			*val = s->chunks;
+		} else {
+			struct cbqri_bc_mon_state *s = &bc->mbm_total_states[rmid];
+			u64 cur = ctr_val & CBQRI_BC_MON_CTR_VAL_CTR_MASK;
+
+			s->chunks  += cbqri_bc_mon_overflow(s->prev_ctr, cur);
+			s->prev_ctr = cur;
+			*val        = s->chunks;
+		}
+out_bc:
+		mutex_unlock(&bc->lock);
+		return err;
+	}
+
 	default:
 		return -EINVAL;
 	}
@@ -730,6 +840,16 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 			res->mon.num_rmid = ctrl->mcid_count;
 			resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID,
 						 false, 0, NULL);
+
+			/*
+			 * Expose BC bandwidth monitoring as the L3's
+			 * mbm_total_bytes when a BC shares topology with this
+			 * L3 (MPAM "MB on L3" mapping).
+			 */
+			if (cbqri_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID])
+				resctrl_enable_mon_event(QOS_L3_MBM_TOTAL_EVENT_ID,
+							 false, 0, NULL);
+
 			res->mon_capable = true;
 		}
 		break;
@@ -818,8 +938,8 @@ static int cbqri_resctrl_pick_bw_alloc(void)
 }
 
 /*
- * Pick one controller per monitoring event.  L3 OCCUP comes from the
- * picked L3 CC (if mon_capable).
+ * Pick one controller per monitoring event. L3 OCCUP comes from the
+ * picked L3 CC (if mon_capable). MBM_TOTAL from the only mon-capable BC.
  */
 static void cbqri_resctrl_pick_counters(void)
 {
@@ -827,6 +947,9 @@ static void cbqri_resctrl_pick_counters(void)
 
 	if (l3->ctrl && l3->ctrl->mon_capable)
 		cbqri_resctrl_counters[QOS_L3_OCCUP_EVENT_ID] = l3->ctrl;
+
+	cbqri_resctrl_counters[QOS_L3_MBM_TOTAL_EVENT_ID] =
+		cbqri_find_only_mon_bc();
 }
 
 static void cbqri_resctrl_accumulate_caps(void)
@@ -949,6 +1072,29 @@ static int cbqri_attach_cpu_to_l3_mon(struct cbqri_controller *ctrl,
 	if (err)
 		goto err_offline;
 
+	/*
+	 * Pair this L3 domain with the system's mon-capable BC. The
+	 * cached pointer is consulted by every rmid_read / reset_rmid.
+	 * BC mon init is system-wide. Failure here means mbm_total_bytes
+	 * is unusable for any domain, so fail the attach.
+	 */
+	{
+		struct cbqri_resctrl_dom *hw_dom = container_of(ctrl_dom,
+								struct cbqri_resctrl_dom,
+								resctrl_ctrl_dom);
+
+		hw_dom->paired_bc = cbqri_find_only_mon_bc();
+		if (hw_dom->paired_bc) {
+			err = cbqri_init_bc_mon_counters(hw_dom->paired_bc);
+			if (err) {
+				pr_err("BC @%pa: mon init failed (%d)\n",
+				       &hw_dom->paired_bc->addr, err);
+				hw_dom->paired_bc = NULL;
+				goto err_offline;
+			}
+		}
+	}
+
 	return 0;
 
 err_offline:

-- 
2.43.0


^ permalink raw reply related

* [PATCH RFC v4 14/18] riscv_cbqri: resctrl: Add MB_WGHT bandwidth allocation via Mweight
From: Drew Fustini @ 2026-05-11  5:11 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Radim Krčmář, Samuel Holland, Adrien Ricciardi,
	Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
	Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
	Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
	Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
	Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
	Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
	Len Brown, Robert Moore, Sunil V L, Drew Fustini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	Jonathan Corbet
  Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
	devicetree, Paul Walmsley, Conor Dooley, linux-rt-devel,
	linux-doc, Palmer Dabbelt
In-Reply-To: <20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683@kernel.org>

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

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

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

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

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

diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
index bcd9367e3555..71ee8e610757 100644
--- a/drivers/resctrl/cbqri_resctrl.c
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -418,6 +418,8 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	case RDT_RESOURCE_MB_MIN:
 		/* sum(Rbwb) <= MRBWB validation runs inside cbqri_apply_rbwb(). */
 		return cbqri_apply_rbwb(dom->hw_ctrl, closid, cfg_val, true);
+	case RDT_RESOURCE_MB_WGHT:
+		return cbqri_apply_mweight_config(dom->hw_ctrl, closid, cfg_val);
 	default:
 		return -EINVAL;
 	}
@@ -478,6 +480,14 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 			val = (u32)rbwb;
 		break;
 	}
+	case RDT_RESOURCE_MB_WGHT: {
+		u64 mweight;
+
+		err = cbqri_read_mweight(ctrl, closid, &mweight);
+		if (err == 0)
+			val = (u32)mweight;
+		break;
+	}
 	default:
 		break;
 	}
@@ -526,6 +536,18 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 							   rcid, rerr);
 			}
 			break;
+		case RDT_RESOURCE_MB_WGHT:
+			/* All RCIDs start at max weight (the new-group default). */
+			for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
+				int rerr;
+
+				rerr = cbqri_apply_mweight_config(dom->hw_ctrl, i,
+								  default_ctrl);
+				if (rerr)
+					pr_err_ratelimited("Mweight reset RCID %u failed (%d)\n",
+							   i, rerr);
+			}
+			break;
 		default:
 			for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
 				for (t = 0; t < CDP_NUM_TYPES; t++) {
@@ -594,6 +616,11 @@ static int cbqri_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_dom
 			err = cbqri_apply_rbwb(dom->hw_ctrl, rcid, rbwb, false);
 			break;
 		}
+		case RDT_RESOURCE_MB_WGHT:
+			/* Match the new-group default: equal weights across RCIDs. */
+			err = cbqri_apply_mweight_config(dom->hw_ctrl, i,
+							 resctrl_get_default_ctrl(r));
+			break;
 		default:
 			/*
 			 * Seed both DATA and CODE staged slots so a later
@@ -731,6 +758,25 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 		INIT_LIST_HEAD(&res->mon_domains);
 		break;
 
+	case RDT_RESOURCE_MB_WGHT:
+		res->name = "MB_WGHT";
+		res->schema_fmt = RESCTRL_SCHEMA_RANGE;
+		res->ctrl_scope = RESCTRL_L3_CACHE;
+		/* Mweight is a dimensionless ratio. No delay/linear concept. */
+		res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+		/*
+		 * CBQRI section 4.5: Mweight is 0-255 (0 disables
+		 * work-conserving). No sum constraint, so leave
+		 * default_to_min false: groups default to max_bw.
+		 */
+		res->membw.min_bw = 0;
+		res->membw.max_bw = 255;
+		res->membw.bw_gran = 1;
+		res->alloc_capable = ctrl->alloc_capable;
+		INIT_LIST_HEAD(&res->ctrl_domains);
+		INIT_LIST_HEAD(&res->mon_domains);
+		break;
+
 	default:
 		break;
 	}
@@ -739,13 +785,14 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 }
 
 /*
- * Pick one BC to back MB_MIN.  Multiple BCs must agree on rcid_count
- * and mrbwb.  Mismatch is fatal because resctrl exposes a single set
- * of caps per rid.
+ * Pick one BC to back both MB_MIN and MB_WGHT (they share a controller).
+ * Multiple BCs must agree on rcid_count and mrbwb. Mismatch is fatal
+ * because resctrl exposes a single set of caps per rid.
  */
 static int cbqri_resctrl_pick_bw_alloc(void)
 {
 	struct cbqri_resctrl_res *mb_min = &cbqri_resctrl_resources[RDT_RESOURCE_MB_MIN];
+	struct cbqri_resctrl_res *mb_wght = &cbqri_resctrl_resources[RDT_RESOURCE_MB_WGHT];
 	struct cbqri_controller *ctrl;
 
 	list_for_each_entry(ctrl, &cbqri_controllers, list) {
@@ -764,6 +811,7 @@ static int cbqri_resctrl_pick_bw_alloc(void)
 		}
 
 		mb_min->ctrl = ctrl;
+		mb_wght->ctrl = ctrl;
 	}
 
 	return 0;
@@ -982,7 +1030,13 @@ static int cbqri_attach_cpu_to_one_bw_res(struct cbqri_controller *ctrl,
 static int cbqri_attach_cpu_to_bw_ctrl(struct cbqri_controller *ctrl,
 				       unsigned int cpu)
 {
-	return cbqri_attach_cpu_to_one_bw_res(ctrl, RDT_RESOURCE_MB_MIN, cpu);
+	int err;
+
+	err = cbqri_attach_cpu_to_one_bw_res(ctrl, RDT_RESOURCE_MB_MIN, cpu);
+	if (err)
+		return err;
+
+	return cbqri_attach_cpu_to_one_bw_res(ctrl, RDT_RESOURCE_MB_WGHT, cpu);
 }
 
 static void cbqri_detach_cpu_from_l3_mon(struct rdt_resource *res,

-- 
2.43.0


^ permalink raw reply related

* [PATCH RFC v4 13/18] riscv_cbqri: resctrl: Add MB_MIN bandwidth allocation via Rbwb
From: Drew Fustini @ 2026-05-11  5:11 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Radim Krčmář, Samuel Holland, Adrien Ricciardi,
	Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
	Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
	Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
	Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
	Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
	Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
	Len Brown, Robert Moore, Sunil V L, Drew Fustini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	Jonathan Corbet
  Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
	devicetree, Paul Walmsley, Conor Dooley, linux-rt-devel,
	linux-doc, Palmer Dabbelt
In-Reply-To: <20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683@kernel.org>

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

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

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

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

diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
index d8fd9b06703f..bcd9367e3555 100644
--- a/drivers/resctrl/cbqri_resctrl.c
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -415,6 +415,9 @@ int resctrl_arch_update_one(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 	case RDT_RESOURCE_L2:
 	case RDT_RESOURCE_L3:
 		return cbqri_apply_cache_config_dom(dom, r, closid, t, cfg_val);
+	case RDT_RESOURCE_MB_MIN:
+		/* sum(Rbwb) <= MRBWB validation runs inside cbqri_apply_rbwb(). */
+		return cbqri_apply_rbwb(dom->hw_ctrl, closid, cfg_val, true);
 	default:
 		return -EINVAL;
 	}
@@ -467,6 +470,14 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 		if (err < 0)
 			val = resctrl_get_default_ctrl(r);
 		break;
+	case RDT_RESOURCE_MB_MIN: {
+		u64 rbwb;
+
+		err = cbqri_read_rbwb(ctrl, closid, &rbwb);
+		if (err == 0)
+			val = (u32)rbwb;
+		break;
+	}
 	default:
 		break;
 	}
@@ -477,6 +488,7 @@ u32 resctrl_arch_get_config(struct rdt_resource *r, struct rdt_ctrl_domain *d,
 void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 {
 	struct cbqri_resctrl_res *hw_res;
+	struct cbqri_resctrl_dom *dom;
 	struct rdt_ctrl_domain *d;
 	enum resctrl_conf_type t;
 	u32 default_ctrl;
@@ -491,15 +503,42 @@ void resctrl_arch_reset_all_ctrls(struct rdt_resource *r)
 		return;
 
 	list_for_each_entry(d, &r->ctrl_domains, hdr.list) {
-		for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
-			for (t = 0; t < CDP_NUM_TYPES; t++) {
+		dom = container_of(d, struct cbqri_resctrl_dom,
+				   resctrl_ctrl_dom);
+
+		switch (r->rid) {
+		case RDT_RESOURCE_MB_MIN:
+			/*
+			 * CBQRI section 4.5: Rbwb >= 1, sum(Rbwb) <= MRBWB.
+			 * Walk N-1..1 first so the final sum lands at
+			 * MRBWB. Use the unchecked helper since the
+			 * intermediate sum may exceed MRBWB.
+			 */
+			for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
+				u32 rcid = (i + 1) % hw_res->ctrl->rcid_count;
+				u64 rbwb = (rcid == 0) ?
+					dom->hw_ctrl->bc.mrbwb - (hw_res->ctrl->rcid_count - 1) : 1;
 				int rerr;
 
-				rerr = resctrl_arch_update_one(r, d, i, t, default_ctrl);
+				rerr = cbqri_apply_rbwb(dom->hw_ctrl, rcid, rbwb, false);
 				if (rerr)
-					pr_err_ratelimited("rid=%d reset RCID %u type %u failed (%d)\n",
-							   r->rid, i, t, rerr);
+					pr_err_ratelimited("RBWB reset RCID %u failed (%d)\n",
+							   rcid, rerr);
+			}
+			break;
+		default:
+			for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
+				for (t = 0; t < CDP_NUM_TYPES; t++) {
+					int rerr;
+
+					rerr = resctrl_arch_update_one(r, d, i, t,
+								       default_ctrl);
+					if (rerr)
+						pr_err_ratelimited("rid=%d reset RCID %u type %u failed (%d)\n",
+								   r->rid, i, t, rerr);
+				}
 			}
+			break;
 		}
 	}
 }
@@ -524,24 +563,53 @@ static struct rdt_ctrl_domain *cbqri_new_domain(struct cbqri_controller *ctrl)
 static int cbqri_init_domain_ctrlval(struct rdt_resource *r, struct rdt_ctrl_domain *d)
 {
 	struct cbqri_resctrl_res *hw_res;
+	struct cbqri_resctrl_dom *dom;
 	enum resctrl_conf_type t;
 	int err = 0;
 	int i;
 
 	hw_res = container_of(r, struct cbqri_resctrl_res, resctrl_res);
+	dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
 
 	for (i = 0; i < hw_res->ctrl->rcid_count; i++) {
 		/*
-		 * Seed both DATA and CODE staged slots so a later mount
-		 * with -o cdp does not see stale CODE values.
-		 * CDP_NUM_TYPES is 1 on non-CDP controllers.
+		 * For MB_MIN walk RCIDs 1..N-1 then RCID 0 last so the sum
+		 * trends toward MRBWB during the walk. Other rids iterate
+		 * in natural order.
 		 */
-		for (t = 0; t < CDP_NUM_TYPES; t++) {
-			err = resctrl_arch_update_one(r, d, i, t,
-						      resctrl_get_default_ctrl(r));
-			if (err)
-				return err;
+		u32 rcid = (r->rid == RDT_RESOURCE_MB_MIN) ?
+				((i + 1) % hw_res->ctrl->rcid_count) : i;
+
+		switch (r->rid) {
+		case RDT_RESOURCE_MB_MIN: {
+			/*
+			 * CBQRI section 4.5: Rbwb >= 1, sum(Rbwb) <= MRBWB.
+			 * RCID 0 gets the remaining budget. Use the
+			 * unchecked helper since intermediate states
+			 * transiently exceed MRBWB.
+			 */
+			u64 rbwb = (rcid == 0) ?
+				dom->hw_ctrl->bc.mrbwb - (hw_res->ctrl->rcid_count - 1) : 1;
+
+			err = cbqri_apply_rbwb(dom->hw_ctrl, rcid, rbwb, false);
+			break;
 		}
+		default:
+			/*
+			 * Seed both DATA and CODE staged slots so a later
+			 * mount with -o cdp does not see stale CODE values.
+			 * CDP_NUM_TYPES is 1 on non-CDP controllers.
+			 */
+			for (t = 0; t < CDP_NUM_TYPES; t++) {
+				err = resctrl_arch_update_one(r, d, i, t,
+							      resctrl_get_default_ctrl(r));
+				if (err)
+					break;
+			}
+			break;
+		}
+		if (err)
+			return err;
 	}
 	return 0;
 }
@@ -638,6 +706,31 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 			res->mon_capable = true;
 		}
 		break;
+
+	case RDT_RESOURCE_MB_MIN:
+		res->name = "MB_MIN";
+		res->schema_fmt = RESCTRL_SCHEMA_RANGE;
+		/*
+		 * resctrl requires a cache scope for MBA-style domains.
+		 * Use L3 as a proxy until the framework supports non-cache
+		 * scopes for bandwidth resources.
+		 */
+		res->ctrl_scope = RESCTRL_L3_CACHE;
+		/* Rbwb is an integer block count, not a percentage. No MBA delay_linear. */
+		res->membw.throttle_mode = THREAD_THROTTLE_UNDEFINED;
+		res->membw.min_bw = 1;
+		res->membw.max_bw = ctrl->bc.mrbwb;
+		res->membw.bw_gran = 1;
+		/*
+		 * CBQRI section 4.5 caps sum(Rbwb) <= MRBWB. Default new
+		 * groups to min_bw so mkdir cannot overflow that sum.
+		 */
+		res->membw.default_to_min = true;
+		res->alloc_capable = ctrl->alloc_capable;
+		INIT_LIST_HEAD(&res->ctrl_domains);
+		INIT_LIST_HEAD(&res->mon_domains);
+		break;
+
 	default:
 		break;
 	}
@@ -645,6 +738,37 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 	return 0;
 }
 
+/*
+ * Pick one BC to back MB_MIN.  Multiple BCs must agree on rcid_count
+ * and mrbwb.  Mismatch is fatal because resctrl exposes a single set
+ * of caps per rid.
+ */
+static int cbqri_resctrl_pick_bw_alloc(void)
+{
+	struct cbqri_resctrl_res *mb_min = &cbqri_resctrl_resources[RDT_RESOURCE_MB_MIN];
+	struct cbqri_controller *ctrl;
+
+	list_for_each_entry(ctrl, &cbqri_controllers, list) {
+		if (ctrl->type != CBQRI_CONTROLLER_TYPE_BANDWIDTH)
+			continue;
+		if (!ctrl->alloc_capable)
+			continue;
+
+		if (mb_min->ctrl) {
+			if (mb_min->ctrl->rcid_count != ctrl->rcid_count ||
+			    mb_min->ctrl->bc.mrbwb != ctrl->bc.mrbwb) {
+				pr_err("BW controllers have mismatched capabilities\n");
+				return -EINVAL;
+			}
+			continue;
+		}
+
+		mb_min->ctrl = ctrl;
+	}
+
+	return 0;
+}
+
 /*
  * Pick one controller per monitoring event.  L3 OCCUP comes from the
  * picked L3 CC (if mon_capable).
@@ -830,6 +954,37 @@ static int cbqri_attach_cpu_to_cap_ctrl(struct cbqri_controller *ctrl,
 	return 0;
 }
 
+static int cbqri_attach_cpu_to_one_bw_res(struct cbqri_controller *ctrl,
+					  enum resctrl_res_level rid,
+					  unsigned int cpu)
+{
+	struct cbqri_resctrl_res *hw_res = &cbqri_resctrl_resources[rid];
+	struct rdt_resource *res = &hw_res->resctrl_res;
+	struct rdt_ctrl_domain *domain;
+	int dom_id = ctrl->mem.prox_dom;
+
+	if (!hw_res->ctrl)
+		return 0;
+
+	domain = cbqri_find_ctrl_domain(&res->ctrl_domains, dom_id);
+	if (domain) {
+		cpumask_set_cpu(cpu, &domain->hdr.cpu_mask);
+		return 0;
+	}
+
+	domain = cbqri_create_ctrl_domain(ctrl, res, cpu, dom_id);
+	if (IS_ERR(domain))
+		return PTR_ERR(domain);
+
+	return 0;
+}
+
+static int cbqri_attach_cpu_to_bw_ctrl(struct cbqri_controller *ctrl,
+				       unsigned int cpu)
+{
+	return cbqri_attach_cpu_to_one_bw_res(ctrl, RDT_RESOURCE_MB_MIN, cpu);
+}
+
 static void cbqri_detach_cpu_from_l3_mon(struct rdt_resource *res,
 					 unsigned int cpu)
 {
@@ -910,6 +1065,10 @@ static int cbqri_resctrl_setup(void)
 	if (err)
 		return err;
 
+	err = cbqri_resctrl_pick_bw_alloc();
+	if (err)
+		return err;
+
 	cbqri_resctrl_pick_counters();
 
 	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
@@ -941,14 +1100,24 @@ static int cbqri_resctrl_online_cpu(unsigned int cpu)
 	mutex_lock(&cbqri_domain_list_lock);
 
 	list_for_each_entry(ctrl, &cbqri_controllers, list) {
-		if (ctrl->type != CBQRI_CONTROLLER_TYPE_CAPACITY)
-			continue;
-		if (!cpumask_test_cpu(cpu, &ctrl->cache.cpu_mask))
-			continue;
-		if (!ctrl->alloc_capable)
+		switch (ctrl->type) {
+		case CBQRI_CONTROLLER_TYPE_CAPACITY:
+			if (!cpumask_test_cpu(cpu, &ctrl->cache.cpu_mask))
+				continue;
+			if (!ctrl->alloc_capable)
+				continue;
+			err = cbqri_attach_cpu_to_cap_ctrl(ctrl, cpu);
+			break;
+		case CBQRI_CONTROLLER_TYPE_BANDWIDTH:
+			if (!cpumask_test_cpu(cpu, &ctrl->mem.cpu_mask))
+				continue;
+			if (!ctrl->alloc_capable)
+				continue;
+			err = cbqri_attach_cpu_to_bw_ctrl(ctrl, cpu);
+			break;
+		default:
 			continue;
-
-		err = cbqri_attach_cpu_to_cap_ctrl(ctrl, cpu);
+		}
 		if (err)
 			break;
 	}

-- 
2.43.0


^ permalink raw reply related

* [PATCH RFC v4 12/18] riscv_cbqri: resctrl: Add L3 cache occupancy monitoring
From: Drew Fustini @ 2026-05-11  5:11 UTC (permalink / raw)
  To: Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Radim Krčmář, Samuel Holland, Adrien Ricciardi,
	Nicolas Pitre, Kornel Dulęba, Atish Patra, Atish Kumar Patra,
	Vasudevan Srinivasan, Ved Shanbhogue, Conor Dooley, yunhui cui,
	Chen Pei, Liu Zhiwei, Weiwei Li, guo.wenjia23, Gong Shuai,
	Gong Shuai, liu.qingtao2, Reinette Chatre, Tony Luck, Babu Moger,
	Peter Newman, Fenghua Yu, James Morse, Ben Horgan, Dave Martin,
	Rob Herring, Conor Dooley, Krzysztof Kozlowski, Rafael J. Wysocki,
	Len Brown, Robert Moore, Sunil V L, Drew Fustini, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, H. Peter Anvin,
	Sebastian Andrzej Siewior, Clark Williams, Steven Rostedt,
	Jonathan Corbet
  Cc: linux-kernel, linux-riscv, x86, linux-acpi, acpica-devel,
	devicetree, Paul Walmsley, Conor Dooley, linux-rt-devel,
	linux-doc, Palmer Dabbelt
In-Reply-To: <20260510-ssqosid-cbqri-rqsc-v7-0-v4-0-eb53831ef683@kernel.org>

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

resctrl_arch_reset_rmid() re-arms CONFIG_EVENT with EVT_ID=Occupancy.
CONFIG_EVENT both resets the counter to 0 and selects the event, so
re-arming with the same event keeps the MCID counting after reset rather
than relying on sticky-last-event semantics that the CBQRI register
definition does not guarantee.

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

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

diff --git a/drivers/resctrl/cbqri_resctrl.c b/drivers/resctrl/cbqri_resctrl.c
index 82b157d35576..d8fd9b06703f 100644
--- a/drivers/resctrl/cbqri_resctrl.c
+++ b/drivers/resctrl/cbqri_resctrl.c
@@ -10,6 +10,7 @@
 #include <linux/cpuhotplug.h>
 #include <linux/err.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/resctrl.h>
 #include <linux/slab.h>
 #include <linux/types.h>
@@ -33,6 +34,13 @@ struct cbqri_resctrl_dom {
 
 static struct cbqri_resctrl_res cbqri_resctrl_resources[RDT_NUM_RESOURCES];
 
+/*
+ * Per-event controller table. Only events CBQRI can back occupy a
+ * slot, so other events do not bloat the array.
+ */
+#define CBQRI_MAX_EVENT QOS_L3_OCCUP_EVENT_ID
+static struct cbqri_controller *cbqri_resctrl_counters[CBQRI_MAX_EVENT + 1];
+
 /*
  * cacheinfo populates the cache id <-> cpumask mapping from a
  * device_initcall(). cbqri_resctrl_setup() runs at late_initcall, which
@@ -44,6 +52,10 @@ static bool cacheinfo_ready;
 static DECLARE_WAIT_QUEUE_HEAD(wait_cacheinfo_ready);
 
 static bool exposed_alloc_capable;
+static bool exposed_mon_capable;
+
+/* Used by resctrl_arch_system_num_rmid_idx(). Narrowed by accumulate_caps. */
+static u32 max_rmid = U32_MAX;
 
 /* Protects ctrl_domain list mutations across CPU hotplug. */
 static DEFINE_MUTEX(cbqri_domain_list_lock);
@@ -56,6 +68,14 @@ cbqri_find_ctrl_domain(struct list_head *h, int id)
 	return hdr ? container_of(hdr, struct rdt_ctrl_domain, hdr) : NULL;
 }
 
+static struct rdt_l3_mon_domain *
+cbqri_find_l3_mon_domain(struct list_head *h, int id)
+{
+	struct rdt_domain_hdr *hdr = resctrl_find_domain(h, id, NULL);
+
+	return hdr ? container_of(hdr, struct rdt_l3_mon_domain, hdr) : NULL;
+}
+
 /*
  * Resctrl-side wrapper around the device-side cbqri_apply_cache_config().
  * Builds the hardware config struct from resctrl-side state (cdp flag, AT
@@ -84,7 +104,7 @@ bool resctrl_arch_alloc_capable(void)
 
 bool resctrl_arch_mon_capable(void)
 {
-	return false;
+	return exposed_mon_capable;
 }
 
 bool resctrl_arch_get_cdp_enabled(enum resctrl_res_level rid)
@@ -185,20 +205,112 @@ void resctrl_arch_mon_event_config_write(void *info)
 {
 }
 
-void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
+void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
+			     u32 unused, u32 rmid, enum resctrl_event_id eventid)
 {
+	struct cbqri_resctrl_dom *hw_dom;
+	struct cbqri_controller *ctrl;
+	struct rdt_ctrl_domain *cd;
+
+	/* Don't sleep with IRQs disabled. */
+	if (irqs_disabled())
+		return;
+
+	switch (eventid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+		cd = cbqri_find_ctrl_domain(&r->ctrl_domains, d->hdr.id);
+		if (!cd)
+			return;
+
+		hw_dom = container_of(cd, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+		ctrl = hw_dom->hw_ctrl;
+
+		mutex_lock(&ctrl->lock);
+		/*
+		 * Re-arm with EVT_ID=OCCUPANCY (not None) on RMID recycle:
+		 * this both zeros the counter and keeps the MCID counting,
+		 * since cbqri_init_mon_counters() only runs once.
+		 */
+		if (cbqri_mon_op(ctrl, CBQRI_CC_MON_CTL_OFF,
+				 CBQRI_CC_MON_CTL_OP_CONFIG_EVENT,
+				 rmid, CBQRI_CC_EVT_ID_OCCUPANCY, NULL))
+			pr_warn_ratelimited("CC@%pa MCID %u: occupancy reset failed\n",
+					    &ctrl->addr, rmid);
+		mutex_unlock(&ctrl->lock);
+		return;
+
+	default:
+		return;
+	}
 }
 
-void resctrl_arch_reset_rmid(struct rdt_resource *r, struct rdt_l3_mon_domain *d,
-			     u32 unused, u32 rmid, enum resctrl_event_id eventid)
+void resctrl_arch_reset_rmid_all(struct rdt_resource *r, struct rdt_l3_mon_domain *d)
 {
+	int i;
+
+	/* Bound by max_rmid (system-wide minimum mcid_count). */
+	for (i = 0; i < max_rmid; i++)
+		resctrl_arch_reset_rmid(r, d, 0, i, QOS_L3_OCCUP_EVENT_ID);
 }
 
 int resctrl_arch_rmid_read(struct rdt_resource *r, struct rdt_domain_hdr *hdr,
 			   u32 closid, u32 rmid, enum resctrl_event_id eventid,
 			   void *arch_priv, u64 *val, void *arch_mon_ctx)
 {
-	return -ENODATA;
+	struct cbqri_resctrl_dom *hw_dom;
+	struct cbqri_controller *ctrl;
+	struct rdt_ctrl_domain *d;
+	u64 ctr_val;
+	int err;
+
+	resctrl_arch_rmid_read_context_check();
+
+	/*
+	 * Each branch takes a sleeping mutex. Bail if called with IRQs
+	 * disabled (e.g. smp_call_function_any() from nohz_full CPUs).
+	 */
+	if (irqs_disabled())
+		return -EIO;
+
+	switch (eventid) {
+	case QOS_L3_OCCUP_EVENT_ID:
+		/* Mon domain id matches the ctrl_domain id. Look up to get hw_ctrl. */
+		d = cbqri_find_ctrl_domain(&r->ctrl_domains, hdr->id);
+		if (!d)
+			return -ENOENT;
+
+		hw_dom = container_of(d, struct cbqri_resctrl_dom, resctrl_ctrl_dom);
+		ctrl = hw_dom->hw_ctrl;
+
+		mutex_lock(&ctrl->lock);
+
+		/*
+		 * MCIDs are armed with Occupancy at init and re-armed on
+		 * RMID recycle. Pass EVT_ID explicitly: the CBQRI spec
+		 * does not guarantee sticky-last-configured-event for
+		 * READ_COUNTER.
+		 */
+		err = cbqri_mon_op(ctrl, CBQRI_CC_MON_CTL_OFF,
+				   CBQRI_CC_MON_CTL_OP_READ_COUNTER,
+				   rmid, CBQRI_CC_EVT_ID_OCCUPANCY, NULL);
+		if (err)
+			goto out_cc;
+
+		ctr_val = ioread64(ctrl->base + CBQRI_CC_MON_CTL_VAL_OFF);
+
+		/*
+		 * Capacity blocks to bytes. Multiply before divide so a
+		 * non-power-of-2 ncblks doesn't truncate. Both terms fit
+		 * in u64 with room to spare.
+		 */
+		*val = (u64)ctrl->cache.cache_size * ctr_val / ctrl->cc.ncblks;
+out_cc:
+		mutex_unlock(&ctrl->lock);
+		return err;
+
+	default:
+		return -EINVAL;
+	}
 }
 
 /*
@@ -225,7 +337,7 @@ u32 resctrl_arch_get_num_closid(struct rdt_resource *res)
 
 u32 resctrl_arch_system_num_rmid_idx(void)
 {
-	return 1;
+	return max_rmid;
 }
 
 u32 resctrl_arch_rmid_idx_encode(u32 closid, u32 rmid)
@@ -517,6 +629,14 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 		res->alloc_capable = ctrl->alloc_capable;
 		INIT_LIST_HEAD(&res->ctrl_domains);
 		INIT_LIST_HEAD(&res->mon_domains);
+
+		if (ctrl->mon_capable && res->rid == RDT_RESOURCE_L3) {
+			res->mon_scope = RESCTRL_L3_CACHE;
+			res->mon.num_rmid = ctrl->mcid_count;
+			resctrl_enable_mon_event(QOS_L3_OCCUP_EVENT_ID,
+						 false, 0, NULL);
+			res->mon_capable = true;
+		}
 		break;
 	default:
 		break;
@@ -525,8 +645,21 @@ static int cbqri_resctrl_control_init(struct cbqri_resctrl_res *cbqri_res)
 	return 0;
 }
 
+/*
+ * Pick one controller per monitoring event.  L3 OCCUP comes from the
+ * picked L3 CC (if mon_capable).
+ */
+static void cbqri_resctrl_pick_counters(void)
+{
+	struct cbqri_resctrl_res *l3 = &cbqri_resctrl_resources[RDT_RESOURCE_L3];
+
+	if (l3->ctrl && l3->ctrl->mon_capable)
+		cbqri_resctrl_counters[QOS_L3_OCCUP_EVENT_ID] = l3->ctrl;
+}
+
 static void cbqri_resctrl_accumulate_caps(void)
 {
+	struct cbqri_controller *ctrl;
 	int rid;
 
 	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
@@ -536,7 +669,22 @@ static void cbqri_resctrl_accumulate_caps(void)
 			continue;
 		if (hw_res->ctrl->alloc_capable)
 			exposed_alloc_capable = true;
+		if (hw_res->ctrl->mon_capable)
+			exposed_mon_capable = true;
 	}
+
+	/*
+	 * Narrow max_rmid against mon-capable controllers only. RQSC may
+	 * report mcid_count for non-mon-capable ones. Clamping the global
+	 * minimum against those would shrink the rmid space unnecessarily.
+	 */
+	list_for_each_entry(ctrl, &cbqri_controllers, list)
+		if (ctrl->mon_capable)
+			max_rmid = min(max_rmid, ctrl->mcid_count);
+
+	/* No mon-capable controller picked: leave max_rmid sentinel-narrowed. */
+	if (!exposed_mon_capable)
+		max_rmid = 1;
 }
 
 /*
@@ -577,6 +725,71 @@ static struct rdt_ctrl_domain *cbqri_create_ctrl_domain(struct cbqri_controller
 	return domain;
 }
 
+static int cbqri_attach_cpu_to_l3_mon(struct cbqri_controller *ctrl,
+				      struct rdt_resource *res, unsigned int cpu)
+{
+	struct rdt_l3_mon_domain *mon_dom;
+	struct rdt_ctrl_domain *ctrl_dom;
+	struct list_head *mon_pos = NULL;
+	int dom_id = ctrl->cache.cache_id;
+	int err;
+
+	lockdep_assert_held(&cbqri_domain_list_lock);
+
+	mon_dom = cbqri_find_l3_mon_domain(&res->mon_domains, dom_id);
+	if (mon_dom) {
+		cpumask_set_cpu(cpu, &mon_dom->hdr.cpu_mask);
+		return 0;
+	}
+
+	ctrl_dom = cbqri_find_ctrl_domain(&res->ctrl_domains, dom_id);
+	if (!ctrl_dom) {
+		pr_err("L3 mon attach for cpu %u: no ctrl_domain id %d\n",
+		       cpu, dom_id);
+		return -EINVAL;
+	}
+
+	mon_dom = kzalloc_obj(*mon_dom, GFP_KERNEL);
+	if (!mon_dom)
+		return -ENOMEM;
+
+	mon_dom->hdr.id = dom_id;
+	mon_dom->hdr.type = RESCTRL_MON_DOMAIN;
+	mon_dom->hdr.rid = RDT_RESOURCE_L3;
+	cpumask_set_cpu(cpu, &mon_dom->hdr.cpu_mask);
+	INIT_LIST_HEAD(&mon_dom->hdr.list);
+
+	if (resctrl_find_domain(&res->mon_domains, dom_id, &mon_pos)) {
+		pr_err("duplicate L3 mon_domain id %d\n", dom_id);
+		err = -EEXIST;
+		goto err_free;
+	}
+	if (mon_pos)
+		list_add_tail(&mon_dom->hdr.list, mon_pos);
+	else
+		list_add_tail(&mon_dom->hdr.list, &res->mon_domains);
+
+	err = resctrl_online_mon_domain(res, &mon_dom->hdr);
+	if (err)
+		goto err_listdel;
+
+	err = cbqri_init_mon_counters(ctrl);
+	if (err)
+		goto err_offline;
+
+	return 0;
+
+err_offline:
+	cancel_delayed_work_sync(&mon_dom->cqm_limbo);
+	cancel_delayed_work_sync(&mon_dom->mbm_over);
+	resctrl_offline_mon_domain(res, &mon_dom->hdr);
+err_listdel:
+	list_del(&mon_dom->hdr.list);
+err_free:
+	kfree(mon_dom);
+	return err;
+}
+
 static int cbqri_attach_cpu_to_cap_ctrl(struct cbqri_controller *ctrl,
 					unsigned int cpu)
 {
@@ -584,6 +797,7 @@ static int cbqri_attach_cpu_to_cap_ctrl(struct cbqri_controller *ctrl,
 	struct rdt_ctrl_domain *domain;
 	struct rdt_resource *res;
 	int dom_id;
+	int err;
 
 	if (ctrl->cache.cache_level == 2)
 		hw_res = &cbqri_resctrl_resources[RDT_RESOURCE_L2];
@@ -601,16 +815,42 @@ static int cbqri_attach_cpu_to_cap_ctrl(struct cbqri_controller *ctrl,
 	domain = cbqri_find_ctrl_domain(&res->ctrl_domains, dom_id);
 	if (domain) {
 		cpumask_set_cpu(cpu, &domain->hdr.cpu_mask);
-		return 0;
+	} else {
+		domain = cbqri_create_ctrl_domain(ctrl, res, cpu, dom_id);
+		if (IS_ERR(domain))
+			return PTR_ERR(domain);
 	}
 
-	domain = cbqri_create_ctrl_domain(ctrl, res, cpu, dom_id);
-	if (IS_ERR(domain))
-		return PTR_ERR(domain);
+	if (ctrl->mon_capable && ctrl->cache.cache_level == 3) {
+		err = cbqri_attach_cpu_to_l3_mon(ctrl, res, cpu);
+		if (err)
+			return err;
+	}
 
 	return 0;
 }
 
+static void cbqri_detach_cpu_from_l3_mon(struct rdt_resource *res,
+					 unsigned int cpu)
+{
+	struct rdt_l3_mon_domain *mon_dom, *tmp;
+
+	lockdep_assert_held(&cbqri_domain_list_lock);
+
+	list_for_each_entry_safe(mon_dom, tmp, &res->mon_domains, hdr.list) {
+		if (!cpumask_test_cpu(cpu, &mon_dom->hdr.cpu_mask))
+			continue;
+		cpumask_clear_cpu(cpu, &mon_dom->hdr.cpu_mask);
+		if (cpumask_empty(&mon_dom->hdr.cpu_mask)) {
+			cancel_delayed_work_sync(&mon_dom->cqm_limbo);
+			cancel_delayed_work_sync(&mon_dom->mbm_over);
+			resctrl_offline_mon_domain(res, &mon_dom->hdr);
+			list_del(&mon_dom->hdr.list);
+			kfree(mon_dom);
+		}
+	}
+}
+
 static void cbqri_detach_cpu_from_ctrl_domains(struct rdt_resource *res,
 					       unsigned int cpu)
 {
@@ -634,7 +874,7 @@ static bool cbqri_resctrl_inited;
 
 static void cbqri_resctrl_teardown(void)
 {
-	int rid;
+	int rid, evt;
 
 	if (!cbqri_resctrl_inited)
 		return;
@@ -647,7 +887,11 @@ static void cbqri_resctrl_teardown(void)
 		hw_res->ctrl = NULL;
 		hw_res->cdp_enabled = false;
 	}
+	for (evt = 0; evt <= CBQRI_MAX_EVENT; evt++)
+		cbqri_resctrl_counters[evt] = NULL;
 	exposed_alloc_capable = false;
+	exposed_mon_capable = false;
+	max_rmid = U32_MAX;
 	cbqri_resctrl_inited = false;
 }
 
@@ -666,6 +910,8 @@ static int cbqri_resctrl_setup(void)
 	if (err)
 		return err;
 
+	cbqri_resctrl_pick_counters();
+
 	for (rid = 0; rid < RDT_NUM_RESOURCES; rid++) {
 		err = cbqri_resctrl_control_init(&cbqri_resctrl_resources[rid]);
 		if (err)
@@ -674,7 +920,7 @@ static int cbqri_resctrl_setup(void)
 
 	cbqri_resctrl_accumulate_caps();
 
-	if (!exposed_alloc_capable) {
+	if (!exposed_alloc_capable && !exposed_mon_capable) {
 		pr_debug("no resctrl-capable CBQRI controllers found\n");
 		return -ENODEV;
 	}
@@ -723,6 +969,8 @@ static int cbqri_resctrl_offline_cpu(unsigned int cpu)
 		if (!hw_res->ctrl)
 			continue;
 		cbqri_detach_cpu_from_ctrl_domains(&hw_res->resctrl_res, cpu);
+		if (rid == RDT_RESOURCE_L3 && hw_res->ctrl->mon_capable)
+			cbqri_detach_cpu_from_l3_mon(&hw_res->resctrl_res, cpu);
 	}
 
 	mutex_unlock(&cbqri_domain_list_lock);

-- 
2.43.0


^ permalink raw reply related


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