* [PATCH v2 01/33] rust: kbuild: remove `--remap-path-prefix` workarounds
From: Miguel Ojeda @ 2026-04-05 23:52 UTC (permalink / raw)
To: Miguel Ojeda, Nathan Chancellor, Nicolas Schier, Danilo Krummrich,
Andreas Hindborg, Catalin Marinas, Will Deacon, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Courbot, David Airlie,
Simona Vetter, Brendan Higgins, David Gow, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Alice Ryhl, Jonathan Corbet
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Trevor Gross, rust-for-linux, linux-kbuild, Lorenzo Stoakes,
Vlastimil Babka, Liam R . Howlett, Uladzislau Rezki, linux-block,
moderated for non-subscribers, Alexandre Ghiti, linux-riscv,
nouveau, dri-devel, Rae Moar, linux-kselftest, kunit-dev,
Nick Desaulniers, Bill Wendling, Justin Stitt, llvm, linux-kernel,
Shuah Khan, linux-doc
In-Reply-To: <20260405235309.418950-1-ojeda@kernel.org>
Commit 8cf5b3f83614 ("Revert "kbuild, rust: use -fremap-path-prefix
to make paths relative"") removed `--remap-path-prefix` from the build
system, so the workarounds are not needed anymore.
Thus remove them.
Note that the flag has landed again in parallel in this cycle in
commit dda135077ecc ("rust: build: remap path to avoid absolute path"),
together with `--remap-path-scope=macro` [1]. However, they are gated on
`rustc-option-yn, --remap-path-scope=macro`, which means they are both
only passed starting with Rust 1.95.0 [2]:
`--remap-path-scope` is only stable in Rust 1.95, so use `rustc-option`
to detect its presence. This feature has been available as
`-Zremap-path-scope` for all versions that we support; however due to
bugs in the Rust compiler, it does not work reliably until 1.94. I opted
to not enable it for 1.94 as it's just a single version that we missed.
In turn, that means the workarounds removed here should not be needed
again (even with the flag added again above), since:
- `rustdoc` now recognizes the `--remap-path-prefix` flag since Rust
1.81.0 [3] (even if it is still an unstable feature [4]).
- The Internal Compiler Error [5] that the comment mentions was fixed in
Rust 1.87.0 [6]. We tested that was the case in a previous version
of this series by making the workaround conditional [7][8].
...which are both older versions than Rust 1.95.0.
We will still need to skip `--remap-path-scope` for `rustdoc` though,
since `rustdoc` does not support that one yet [4].
Link: https://github.com/rust-lang/rust/issues/111540 [1]
Link: https://github.com/rust-lang/rust/pull/147611 [2]
Link: https://github.com/rust-lang/rust/pull/107099 [3]
Link: https://doc.rust-lang.org/nightly/rustdoc/unstable-features.html#--remap-path-prefix-remap-source-code-paths-in-output [4]
Link: https://github.com/rust-lang/rust/issues/138520 [5]
Link: https://github.com/rust-lang/rust/pull/138556 [6]
Link: https://lore.kernel.org/rust-for-linux/20260401114540.30108-9-ojeda@kernel.org/ [7]
Link: https://lore.kernel.org/rust-for-linux/20260401114540.30108-10-ojeda@kernel.org/ [8]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
rust/Makefile | 8 ++------
1 file changed, 2 insertions(+), 6 deletions(-)
diff --git a/rust/Makefile b/rust/Makefile
index 96cd7d8e6ee9..16ea720e0a8e 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -145,14 +145,10 @@ rustdoc_modifiers_workaround := $(if $(call rustc-min-version,108800),-Cunsafe-a
# Similarly, for doctests (https://github.com/rust-lang/rust/issues/146465).
doctests_modifiers_workaround := $(rustdoc_modifiers_workaround)$(if $(call rustc-min-version,109100),$(comma)sanitizer)
-# `rustc` recognizes `--remap-path-prefix` since 1.26.0, but `rustdoc` only
-# since Rust 1.81.0. Moreover, `rustdoc` ICEs on out-of-tree builds since Rust
-# 1.82.0 (https://github.com/rust-lang/rust/issues/138520). Thus workaround both
-# issues skipping the flag. The former also applies to `RUSTDOC TK`.
quiet_cmd_rustdoc = RUSTDOC $(if $(rustdoc_host),H, ) $<
cmd_rustdoc = \
OBJTREE=$(abspath $(objtree)) \
- $(RUSTDOC) $(filter-out $(skip_flags) --remap-path-prefix=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
+ $(RUSTDOC) $(filter-out $(skip_flags),$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(rustc_target_flags) -L$(objtree)/$(obj) \
-Zunstable-options --generate-link-to-definition \
--output $(rustdoc_output) \
@@ -338,7 +334,7 @@ quiet_cmd_rustdoc_test_kernel = RUSTDOC TK $<
rm -rf $(objtree)/$(obj)/test/doctests/kernel; \
mkdir -p $(objtree)/$(obj)/test/doctests/kernel; \
OBJTREE=$(abspath $(objtree)) \
- $(RUSTDOC) --test $(filter-out --remap-path-prefix=%,$(rust_flags)) \
+ $(RUSTDOC) --test $(rust_flags) \
-L$(objtree)/$(obj) --extern ffi --extern pin_init \
--extern kernel --extern build_error --extern macros \
--extern bindings --extern uapi \
--
2.53.0
^ permalink raw reply related
* [PATCH v2 00/33] rust: bump minimum Rust and `bindgen` versions
From: Miguel Ojeda @ 2026-04-05 23:52 UTC (permalink / raw)
To: Miguel Ojeda, Nathan Chancellor, Nicolas Schier, Danilo Krummrich,
Andreas Hindborg, Catalin Marinas, Will Deacon, Paul Walmsley,
Palmer Dabbelt, Albert Ou, Alexandre Courbot, David Airlie,
Simona Vetter, Brendan Higgins, David Gow, Greg Kroah-Hartman,
Arve Hjønnevåg, Todd Kjos, Christian Brauner,
Carlos Llamas, Alice Ryhl, Jonathan Corbet
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Benno Lossin,
Trevor Gross, rust-for-linux, linux-kbuild, Lorenzo Stoakes,
Vlastimil Babka, Liam R . Howlett, Uladzislau Rezki, linux-block,
moderated for non-subscribers, Alexandre Ghiti, linux-riscv,
nouveau, dri-devel, Rae Moar, linux-kselftest, kunit-dev,
Nick Desaulniers, Bill Wendling, Justin Stitt, llvm, linux-kernel,
Shuah Khan, linux-doc
As proposed in the past in e.g. LPC 2025 and the Maintainers Summit [1],
we are going to follow Debian Stable's Rust versions as our minimum
supported version.
Debian Trixie was released with a Rust 1.85.0 toolchain [2], which it
still uses to this day [3] (i.e. no update to Rust 1.85.1).
Debian Trixie was released with `bindgen` 0.71.1, which it also still
uses to this day [4].
Debian Trixie's release happened on 2025-08-09 [5], which means that a
fair amount of time has passed since its release for kernel developers
to upgrade.
Thus bump the minimum to the new versions, i.e.
- Rust: 1.78.0 -> 1.85.0
- bindgen: 0.65.1 -> 0.71.1
There are a few main parts to the series, in this order:
- A few cleanups that can be performed before the bumps.
- The Rust bump (and its cleanups).
- The `bindgen` bump (and its cleanups).
- Documentation updates.
- The `cfi_encoding` patch, added here, which needs the bump.
- The per-version flags support and a Clippy cleanup on top.
Link: https://lwn.net/Articles/1050174/ [1]
Link: https://www.debian.org/releases/trixie/release-notes/whats-new.en.html#desktops-and-well-known-packages [2]
Link: https://packages.debian.org/trixie/rustc [3]
Link: https://packages.debian.org/trixie/bindgen [4]
Link: https://www.debian.org/releases/trixie/ [5]
---
v1: https://lore.kernel.org/rust-for-linux/20260401114540.30108-1-ojeda@kernel.org/
v2:
- Added patch to globally allow `incompatible_msrv` and removed the
last instance.
- Replaced `--remap-path-prefix` patches with one that drops the
workaround entirely (and place it as the first one) and summarizes
the discussion.
I also noticed that `--remap-path-prefix` for `rustdoc` is still
unstable (unlike `rustc`'s one), so I added it to our list as usual
(https://github.com/Rust-for-Linux/linux/issues/2). There does not
seem to be a tracking issue, so I asked upstream about it.
We will need these two lines as the resolution for the conflict:
$(RUSTDOC) $(filter-out $(skip_flags) --remap-path-scope=%,$(if $(rustdoc_host),$(rust_common_flags),$(rust_flags))) \
$(RUSTDOC) --test $(filter-out --remap-path-scope=%,$(rust_flags)) \
- Reworked the `extract_if` patch to use it (unstably). The feature
last major change happened in Rust 1.85.0, so that is fine.
- Moved `$(HOSTRUSTFLAGS)` below so that per-version flags (like
lints) can be overridden too. Please see the details in the commit
and my reply to v1.
- Added `feature(extract_if)` and `feature(non_null_convenience)`
items to https://github.com/Rust-for-Linux/linux/issues/1223.
Then reworded the commits accordingly to include the references
to tracking issues and PRs.
- Other rewords, e.g. the "beyond" typo.
- Rebased on top of `rust-next`.
- Picked up tags.
Alice Ryhl (1):
rust: declare cfi_encoding for lru_status
Miguel Ojeda (32):
rust: kbuild: remove `--remap-path-prefix` workarounds
rust: kbuild: remove "`try` keyword" workaround for `bindgen` < 0.59.2
rust: kbuild: remove unneeded old `allow`s for generated layout tests
gpu: nova-core: bindings: remove unneeded `cfg_attr`
rust: bump Rust minimum supported version to 1.85.0 (Debian Trixie)
rust: bump Clippy's MSRV and clean `incompatible_msrv` allows
rust: allow globally `clippy::incompatible_msrv`
rust: simplify `RUSTC_VERSION` Kconfig conditions
rust: remove `RUSTC_HAS_SLICE_AS_FLATTENED` and simplify code
rust: remove `RUSTC_HAS_COERCE_POINTEE` and simplify code
rust: kbuild: remove skipping of `-Wrustdoc::unescaped_backticks`
rust: kbuild: remove `feature(...)`s that are now stable
rust: transmute: simplify code with Rust 1.80.0 `split_at_*checked()`
rust: alloc: simplify with `NonNull::add()` now that it is stable
rust: macros: simplify code using `feature(extract_if)`
rust: block: update `const_refs_to_static` MSRV TODO comment
rust: bump `bindgen` minimum supported version to 0.71.1 (Debian
Trixie)
rust: rust_is_available: remove warning for `bindgen` 0.66.[01]
rust: rust_is_available: remove warning for `bindgen` < 0.69.5 &&
libclang >= 19.1
rust: kbuild: update `bindgen --rust-target` version and replace
comment
rust: kbuild: remove "dummy parameter" workaround for `bindgen` <
0.71.1
docs: rust: quick-start: openSUSE provides `rust-src` package nowadays
docs: rust: quick-start: update Ubuntu versioned packages
docs: rust: quick-start: update minimum Ubuntu version
docs: rust: quick-start: add Ubuntu 26.04 LTS and remove subsection
title
docs: rust: quick-start: remove Gentoo "testing" note
docs: rust: quick-start: remove Nix "unstable channel" note
docs: rust: quick-start: remove GDB/Binutils mention
docs: rust: general-information: simplify Kconfig example
docs: rust: general-information: use real example
rust: kbuild: support global per-version flags
rust: kbuild: allow `clippy::precedence` for Rust < 1.86.0
.clippy.toml | 2 +-
Documentation/process/changes.rst | 4 +-
Documentation/rust/general-information.rst | 4 +-
Documentation/rust/quick-start.rst | 52 +++++++----------
Makefile | 12 +++-
arch/Kconfig | 3 +-
arch/arm64/Kconfig | 8 ---
arch/riscv/Kconfig | 3 -
drivers/android/binder/Makefile | 3 +-
drivers/android/binder/page_range.rs | 6 +-
drivers/android/binder/page_range_helper.c | 24 --------
drivers/android/binder/page_range_helper.h | 15 -----
drivers/gpu/nova-core/gsp/cmdq.rs | 6 +-
drivers/gpu/nova-core/gsp/fw/r570_144.rs | 3 -
init/Kconfig | 15 +----
rust/Makefile | 31 ++--------
rust/bindgen_parameters | 8 +--
rust/bindings/bindings_helper.h | 1 -
rust/bindings/lib.rs | 5 +-
rust/kernel/alloc/allocator/iter.rs | 8 +--
rust/kernel/alloc/kbox.rs | 29 +---------
rust/kernel/block/mq/gen_disk.rs | 4 +-
rust/kernel/lib.rs | 30 +---------
rust/kernel/list/arc.rs | 22 +------
rust/kernel/prelude.rs | 3 -
rust/kernel/ptr.rs | 1 -
rust/kernel/slice.rs | 49 ----------------
rust/kernel/sync/arc.rs | 21 +------
rust/kernel/transmute.rs | 35 ++---------
rust/macros/helpers.rs | 1 -
rust/macros/kunit.rs | 9 +--
rust/macros/lib.rs | 3 +
rust/uapi/lib.rs | 5 +-
scripts/Makefile.build | 6 +-
scripts/min-tool-version.sh | 4 +-
scripts/rust_is_available.sh | 36 +-----------
scripts/rust_is_available_bindgen_0_66.h | 2 -
...ust_is_available_bindgen_libclang_concat.h | 3 -
scripts/rust_is_available_test.py | 58 +------------------
39 files changed, 83 insertions(+), 451 deletions(-)
delete mode 100644 drivers/android/binder/page_range_helper.c
delete mode 100644 drivers/android/binder/page_range_helper.h
delete mode 100644 rust/kernel/slice.rs
delete mode 100644 scripts/rust_is_available_bindgen_0_66.h
delete mode 100644 scripts/rust_is_available_bindgen_libclang_concat.h
base-commit: 36f5a2b09e650b82d7b2a106e3b93af48c2010d9
--
2.53.0
^ permalink raw reply
* Re: [PATCH 1/2] pmdomain/rockchip: skip QoS operations for idle-only domains
From: Jonas Karlman @ 2026-04-05 23:29 UTC (permalink / raw)
To: Shawn Lin, Daniel Bozeman, finley.xiao@rock-chips.com
Cc: ulf.hansson@linaro.org, heiko@sntech.de, linux-pm@vger.kernel.org,
linux-arm-kernel@lists.infradead.org,
linux-rockchip@lists.infradead.org, linux-kernel@vger.kernel.org
In-Reply-To: <f1b9a97a-f1f9-0757-5dc7-33960318be61@rock-chips.com>
Hi,
On 4/4/2026 1:40 PM, Shawn Lin wrote:
> + Jonas
>
> 在 2026/04/04 星期六 5:27, Daniel Bozeman 写道:
>> I ran both tests you requested:
>>
>> Test 1: Added pr_err to rockchip_pd_power_on/off to identify
>> the crashing domain. With patch 2 only (skip EPROBE_DEFER),
>> the crash occurs on PD_VO:
>
> Thanks for fing the PD_VO, and I'm still requesting more docs internally
> to check what's going on. I see there are several qos nodes under PD_VO,
> but I'm not sure if they all belong to PD_VO and even not sure if their
> registers are define correctly.
>
> Perhaps, could you help dig more by removing the qos one by one from
> PD_VO to narrow down the broken qos?
>
> I also loop in Jonas who submited the code, to have a look.(I'm also
> surprised to see there aren't any Qos nodes under PD_VO in vendor
> kernel for reference, but upstream code has...)
Upstream included all QoS that seemed to be related to each power domains
based on e.g. vendor DTs, clock driver and other hints.
Vendor kernel mostly seemed to take the easy way out and flagged all
rk3528 power domains as always on or similar, if I recall correctly.
For upstream we have instead tried to describe all power domains without
any always on flag and instead ensure all devices belong to a power
domain.
I do not have access to any rk3528 TRM or similar, so I would not be
surprised if there could be some wrong details. However, runtime
testing at time of patches was sent upstream did not show any issues.
I was however able to reproduce a crash using next-20260403 + rk3528 usb
series [1][2]. Such crash was not happening at the original submission
of the pmdomain or usb series.
Looking at pmdomain core and rk pmdomain driver changes since rk3528
merge I see that there are some changes that may have changed behavior
of the driver since initial rk3528 merge. I.e. GENPD_FLAG_NO_STAY_ON.
Following quick diff seem to remove any changed behavior introduced in
commit 2bc12a8199a0 ("pmdomain: rockchip: Fix regulator dependency with
GENPD_FLAG_NO_STAY_ON"), and fixes the crash for me.
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c
index 490bbb1d1d8e..4d69b9f68886 100644
--- a/drivers/pmdomain/rockchip/pm-domains.c
+++ b/drivers/pmdomain/rockchip/pm-domains.c
@@ -892,7 +892,9 @@ static int rockchip_pm_add_one_domain(struct rockchip_pmu *pmu,
pd->genpd.power_on = rockchip_pd_power_on;
pd->genpd.attach_dev = rockchip_pd_attach_dev;
pd->genpd.detach_dev = rockchip_pd_detach_dev;
- pd->genpd.flags = GENPD_FLAG_PM_CLK | GENPD_FLAG_NO_STAY_ON;
+ pd->genpd.flags = GENPD_FLAG_PM_CLK;
+ if (pd->info->pwr_mask || pd->info->status_mask)
+ pd->genpd.flags |= GENPD_FLAG_NO_STAY_ON;
if (pd_info->active_wakeup)
pd->genpd.flags |= GENPD_FLAG_ACTIVE_WAKEUP;
pm_genpd_init(&pd->genpd, NULL,
Could also be that GENPD_FLAG_NO_STAY_ON only need to be applied to
need_regulator domains?
[1] https://lore.kernel.org/r/20250723122323.2344916-1-jonas@kwiboo.se/
[2] https://github.com/Kwiboo/linux-rockchip/commits/next-20260403-rk3528/
Regards,
Jonas
>
>>
>> rockchip_pd_power_off: vo pwr_mask=0x0
>> Internal error: synchronous external abort: 0000000096000010
>> Workqueue: pm genpd_power_off_work_fn
>> Call trace:
>> regmap_mmio_read32le+0x8/0x20
>> _regmap_bus_reg_read+0x6c/0xac
>> _regmap_read+0x60/0xd8
>> regmap_read+0x4c/0x7c
>> rockchip_pmu_set_idle_request.isra.0+0x98/0x16c
>> rockchip_pd_power+0x130/0x48c
>> rockchip_pd_power_off+0x38/0x48
>> genpd_power_off.isra.0+0x1f0/0x2f0
>> genpd_power_off_work_fn+0x34/0x54
>>
>> Test 2: Same debug build, booted with clk_ignore_unused
>> added to kernel cmdline via U-Boot. Same crash, same domain:
>>
>> rockchip_pd_power_off: vo pwr_mask=0x0
>> Internal error: synchronous external abort: 0000000096000010
>> (identical call trace)
>>
>> The crash occurs even with clk_ignore_unused. The QoS
>> registers for PD_VO are inaccessible when genpd attempts
>> to power off this idle-only domain.
>>
^ permalink raw reply related
* Re: [PATCH 32/33] rust: kbuild: support global per-version flags
From: Miguel Ojeda @ 2026-04-05 23:15 UTC (permalink / raw)
To: Gary Guo, Nathan Chancellor, Nicolas Schier
Cc: Miguel Ojeda, Danilo Krummrich, Andreas Hindborg, Catalin Marinas,
Will Deacon, Paul Walmsley, Palmer Dabbelt, Albert Ou,
Alexandre Courbot, David Airlie, Simona Vetter, Brendan Higgins,
David Gow, Greg Kroah-Hartman, Arve Hjønnevåg,
Todd Kjos, Christian Brauner, Carlos Llamas, Alice Ryhl,
Jonathan Corbet, Boqun Feng, Björn Roy Baron, Benno Lossin,
Trevor Gross, rust-for-linux, linux-kbuild, Lorenzo Stoakes,
Vlastimil Babka, Liam R . Howlett, Uladzislau Rezki, linux-block,
moderated for non-subscribers, Alexandre Ghiti, linux-riscv,
nouveau, dri-devel, Rae Moar, linux-kselftest, kunit-dev,
Nick Desaulniers, Bill Wendling, Justin Stitt, llvm, linux-kernel,
Shuah Khan, linux-doc
In-Reply-To: <DHHX9O7V06VZ.G0N1CQ7BUKFO@garyguo.net>
On Thu, Apr 2, 2026 at 12:28 AM Gary Guo <gary@garyguo.net> wrote:
>
> I think I would prefer moving these down.
>
> The current approach append the flags to all variables, which will cause the
> following equivalence to stop holding after the flag update.
>
> KBUILD_HOSTRUSTFLAGS := $(rust_common_flags) -O -Cstrip=debuginfo \
> -Zallow-features= $(HOSTRUSTFLAGS)
>
> (Per version flags doesn't go before -O anymore, it comes after HOSTRUSTFLAGS).
[ For context for others, Sashiko reported the same and we also talked
about it in a Rust for Linux call. ]
I have been thinking about this, and about potential other ways to
achieve the same thing. I think the best at the moment is to move just
the `$(HOSTRUSTFLAGS)` below, but not the rest.
The reason is that it is closer to what we do with other user (kernel)
flags (e.g. arch flags come after the general ones). But I am
wondering if we should/could set all the user variables later in the
`Makefile` in general `HOST*FLAGS` later in the `Makefile`.
In fact, there is already a limitation with the host flags: `-Werror`,
i.e. that one gets appended later, and so users cannot override it.
This may be considered a bug, because commit 7ded7d37e5f5
("scripts/Makefile.extrawarn: Respect CONFIG_WERROR / W=e for
hostprogs") says:
While it is
possible to avoid this behavior by passing HOSTCFLAGS=-w or
HOSTCFLAGS=-Wno-error, it may not be the most intuitive for regular
users not intimately familiar with Kbuild.
But passing `HOSTCFLAGS=-Wno-error` doesn't work, since it comes
earlier (`-w` does work, but because it turns off everything).
I am also a bit confused with:
While this means there is a small portion of
the build that does not have -Werror enabled (namely scripts/kconfig/*
and scripts/basic/fixdep)
because it gets enabled in the build (I think it is referring to other
targets like the config ones).
Anyway, for now I moved the expansion of `HOSTRUSTFLAGS` in v2. If
Kbuild (Nathan, Nicolas) think it is a good idea to do one of the
bigger changes (e.g. for more `HOST*` flags, appending it even later),
then we can do it afterwards.
Cheers,
Miguel
^ permalink raw reply
* Re: [PATCH 3/3] arm64: dts: broadcom: rp1: Add PWM node
From: Uwe Kleine-König @ 2026-04-05 21:48 UTC (permalink / raw)
To: Andrea della Porta
Cc: linux-pwm, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Florian Fainelli, Broadcom internal kernel review list,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov
In-Reply-To: <ef79e974c6680202294a4cfde7cc791753bf1b3e.1775223441.git.andrea.porta@suse.com>
[-- Attachment #1: Type: text/plain, Size: 149 bytes --]
Hello,
The "rp1" in the Subject is very irritating. Better make this:
arm64: dts: broadcom: rpi-5: Add rp1 PWM node
or similar.
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: [PATCH 2/3] pwm: rp1: Add RP1 PWM controller driver
From: Uwe Kleine-König @ 2026-04-05 21:45 UTC (permalink / raw)
To: Andrea della Porta
Cc: linux-pwm, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Florian Fainelli, Broadcom internal kernel review list,
devicetree, linux-rpi-kernel, linux-arm-kernel, linux-kernel,
Naushir Patuck, Stanimir Varbanov
In-Reply-To: <28e29fbfc20c0b8a115d006233c2759d8f49e639.1775223441.git.andrea.porta@suse.com>
[-- Attachment #1: Type: text/plain, Size: 10393 bytes --]
Hello Andrea,
On Fri, Apr 03, 2026 at 04:31:55PM +0200, Andrea della Porta wrote:
> From: Naushir Patuck <naush@raspberrypi.com>
>
> The Raspberry Pi RP1 southbridge features an embedded PWM
> controller with 4 output channels, alongside an RPM interface
> to read the fan speed on the Raspberry Pi 5.
>
> Add the supporting driver.
>
> Signed-off-by: Naushir Patuck <naush@raspberrypi.com>
> Co-developed-by: Stanimir Varbanov <svarbanov@suse.de>
> Signed-off-by: Stanimir Varbanov <svarbanov@suse.de>
> Signed-off-by: Andrea della Porta <andrea.porta@suse.com>
> ---
> drivers/pwm/Kconfig | 10 ++
> drivers/pwm/Makefile | 1 +
> drivers/pwm/pwm-rp1.c | 244 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 255 insertions(+)
> create mode 100644 drivers/pwm/pwm-rp1.c
>
> diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
> index 6f3147518376a..22e4fc6385da2 100644
> --- a/drivers/pwm/Kconfig
> +++ b/drivers/pwm/Kconfig
> @@ -625,6 +625,16 @@ config PWM_ROCKCHIP
> Generic PWM framework driver for the PWM controller found on
> Rockchip SoCs.
>
> +config PWM_RP1
I prefer PWM_RASPBERRYPI1, or PWM_RASPBERRYPI_RP1 here.
> + tristate "RP1 PWM support"
> + depends on MISC_RP1 || COMPILE_TEST
> + depends on HWMON
> + help
> + PWM framework driver for Raspberry Pi RP1 controller
> +
> + To compile this driver as a module, choose M here: the module
> + will be called pwm-rp1.
> +
> config PWM_SAMSUNG
> tristate "Samsung PWM support"
> depends on PLAT_SAMSUNG || ARCH_S5PV210 || ARCH_EXYNOS || COMPILE_TEST
> diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
> index 0dc0d2b69025d..895a7c42fe9c0 100644
> --- a/drivers/pwm/Makefile
> +++ b/drivers/pwm/Makefile
> @@ -56,6 +56,7 @@ obj-$(CONFIG_PWM_RENESAS_RZG2L_GPT) += pwm-rzg2l-gpt.o
> obj-$(CONFIG_PWM_RENESAS_RZ_MTU3) += pwm-rz-mtu3.o
> obj-$(CONFIG_PWM_RENESAS_TPU) += pwm-renesas-tpu.o
> obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
> +obj-$(CONFIG_PWM_RP1) += pwm-rp1.o
> obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
> obj-$(CONFIG_PWM_SIFIVE) += pwm-sifive.o
> obj-$(CONFIG_PWM_SL28CPLD) += pwm-sl28cpld.o
> diff --git a/drivers/pwm/pwm-rp1.c b/drivers/pwm/pwm-rp1.c
> new file mode 100644
> index 0000000000000..0a1c1c1dd27e9
> --- /dev/null
> +++ b/drivers/pwm/pwm-rp1.c
> @@ -0,0 +1,244 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * pwm-rp1.c
> + *
> + * Raspberry Pi RP1 PWM.
> + *
> + * Copyright © 2026 Raspberry Pi Ltd.
> + *
> + * Author: Naushir Patuck (naush@raspberrypi.com)
> + *
> + * Based on the pwm-bcm2835 driver by:
> + * Bart Tanghe <bart.tanghe@thomasmore.be>
> + */
Please add a paragraph here named "Limitations" in the same format as
several other drivers describing how the driver behaves on disable and
configuration changes (can glitches occur? Is the currently running
period completed or aborted?)
> +#include <linux/bitops.h>
> +#include <linux/clk.h>
> +#include <linux/err.h>
> +#include <linux/hwmon.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pwm.h>
> +
> +#define PWM_GLOBAL_CTRL 0x000
> +#define PWM_CHANNEL_CTRL(x) (0x014 + ((x) * 0x10))
> +#define PWM_RANGE(x) (0x018 + ((x) * 0x10))
> +#define PWM_PHASE(x) (0x01C + ((x) * 0x10))
> +#define PWM_DUTY(x) (0x020 + ((x) * 0x10))
> +
> +/* 8:FIFO_POP_MASK + 0:Trailing edge M/S modulation */
> +#define PWM_CHANNEL_DEFAULT (BIT(8) + BIT(0))
> +#define PWM_CHANNEL_ENABLE(x) BIT(x)
> +#define PWM_POLARITY BIT(3)
> +#define SET_UPDATE BIT(31)
> +#define PWM_MODE_MASK GENMASK(1, 0)
> +
> +#define NUM_PWMS 4
Please prefix all #defines by something driver specific (e.g. RP1_PWM_).
> +
> +struct rp1_pwm {
> + void __iomem *base;
> + struct clk *clk;
> +};
> +
> +static const struct hwmon_channel_info * const rp1_fan_hwmon_info[] = {
> + HWMON_CHANNEL_INFO(fan, HWMON_F_INPUT),
> + NULL
> +};
> +
> +static umode_t rp1_fan_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
> + u32 attr, int channel)
> +{
> + umode_t mode = 0;
> +
> + if (type == hwmon_fan && attr == hwmon_fan_input)
> + mode = 0444;
> +
> + return mode;
> +}
> +
> +static int rp1_fan_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
> + u32 attr, int channel, long *val)
> +{
> + struct rp1_pwm *rp1 = dev_get_drvdata(dev);
> +
> + if (type != hwmon_fan || attr != hwmon_fan_input)
> + return -EOPNOTSUPP;
> +
> + *val = readl(rp1->base + PWM_PHASE(2));
> +
> + return 0;
> +}
I don't like having hwmon bits in pwm drivers. Is the PWM only usable
for a fan? I guess the hwmon parts should be dropped and a pwm-fan
defined in dt.
> +static const struct hwmon_ops rp1_fan_hwmon_ops = {
> + .is_visible = rp1_fan_hwmon_is_visible,
> + .read = rp1_fan_hwmon_read,
> +};
> +
> +static const struct hwmon_chip_info rp1_fan_hwmon_chip_info = {
> + .ops = &rp1_fan_hwmon_ops,
> + .info = rp1_fan_hwmon_info,
> +};
> +
> +static void rp1_pwm_apply_config(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> + struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
> + u32 value;
> +
> + value = readl(rp1->base + PWM_GLOBAL_CTRL);
> + value |= SET_UPDATE;
> + writel(value, rp1->base + PWM_GLOBAL_CTRL);
> +}
> +
> +static int rp1_pwm_request(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> + struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
> +
> + writel(PWM_CHANNEL_DEFAULT, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
Please add a comment about what this does.
> + return 0;
> +}
> +
> +static void rp1_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
> +{
> + struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
> + u32 value;
> +
> + value = readl(rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
> + value &= ~PWM_MODE_MASK;
> + writel(value, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
> +
> + rp1_pwm_apply_config(chip, pwm);
What is the purpose of this call?
> +}
> +
> +static int rp1_pwm_apply(struct pwm_chip *chip, struct pwm_device *pwm,
> + const struct pwm_state *state)
> +{
> + struct rp1_pwm *rp1 = pwmchip_get_drvdata(chip);
> + unsigned long clk_rate = clk_get_rate(rp1->clk);
> + unsigned long clk_period;
> + u32 value;
> +
> + if (!clk_rate) {
> + dev_err(&chip->dev, "failed to get clock rate\n");
> + return -EINVAL;
> + }
> +
> + /* set period and duty cycle */
> + clk_period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, clk_rate);
DIV_ROUND_CLOSEST is wrong here. (I don't go into details as .apply()
should be dropped.)
> + writel(DIV_ROUND_CLOSEST(state->duty_cycle, clk_period),
Dividing by the result of a division loses precision.
> + rp1->base + PWM_DUTY(pwm->hwpwm));
> +
> + writel(DIV_ROUND_CLOSEST(state->period, clk_period),
> + rp1->base + PWM_RANGE(pwm->hwpwm));
> +
> + /* set polarity */
> + value = readl(rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
> + if (state->polarity == PWM_POLARITY_NORMAL)
> + value &= ~PWM_POLARITY;
> + else
> + value |= PWM_POLARITY;
> + writel(value, rp1->base + PWM_CHANNEL_CTRL(pwm->hwpwm));
> +
> + /* enable/disable */
> + value = readl(rp1->base + PWM_GLOBAL_CTRL);
> + if (state->enabled)
> + value |= PWM_CHANNEL_ENABLE(pwm->hwpwm);
> + else
> + value &= ~PWM_CHANNEL_ENABLE(pwm->hwpwm);
> + writel(value, rp1->base + PWM_GLOBAL_CTRL);
> +
> + rp1_pwm_apply_config(chip, pwm);
> +
> + return 0;
> +}
> +
> +static const struct pwm_ops rp1_pwm_ops = {
> + .request = rp1_pwm_request,
> + .free = rp1_pwm_free,
> + .apply = rp1_pwm_apply,
Please implement the waveform callbacks instead of .apply().
> +};
> +
> +static int rp1_pwm_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device *hwmon_dev;
> + struct pwm_chip *chip;
> + struct rp1_pwm *rp1;
> + int ret;
> +
> + chip = devm_pwmchip_alloc(dev, NUM_PWMS, sizeof(*rp1));
> + if (IS_ERR(chip))
> + return PTR_ERR(chip);
> +
> + rp1 = pwmchip_get_drvdata(chip);
> +
> + rp1->base = devm_platform_ioremap_resource(pdev, 0);
> + if (IS_ERR(rp1->base))
> + return PTR_ERR(rp1->base);
> +
> + rp1->clk = devm_clk_get_enabled(dev, NULL);
> + if (IS_ERR(rp1->clk))
> + return dev_err_probe(dev, PTR_ERR(rp1->clk), "clock not found\n");
Please start error messages with a capital letter.
> +
> + ret = devm_clk_rate_exclusive_get(dev, rp1->clk);
After this call you can determine the rate just once and fail if it's ==
0.
> + if (ret)
> + return dev_err_probe(dev, ret, "fail to get exclusive rate\n");
> +
> + chip->ops = &rp1_pwm_ops;
> +
> + platform_set_drvdata(pdev, chip);
> +
> + ret = devm_pwmchip_add(dev, chip);
> + if (ret)
> + return dev_err_probe(dev, ret, "failed to register PWM chip\n");
> +
> + hwmon_dev = devm_hwmon_device_register_with_info(dev, "rp1_fan_tach", rp1,
> + &rp1_fan_hwmon_chip_info,
> + NULL);
> +
> + if (IS_ERR(hwmon_dev))
> + return dev_err_probe(dev, PTR_ERR(hwmon_dev),
> + "failed to register hwmon fan device\n");
> +
> + return 0;
> +}
> +
> +static int rp1_pwm_suspend(struct device *dev)
> +{
> + struct rp1_pwm *rp1 = dev_get_drvdata(dev);
> +
> + clk_disable_unprepare(rp1->clk);
> +
> + return 0;
> +}
> +
> +static int rp1_pwm_resume(struct device *dev)
> +{
> + struct rp1_pwm *rp1 = dev_get_drvdata(dev);
> +
> + return clk_prepare_enable(rp1->clk);
Hmm, if this fails and then the driver is unbound, the clk operations
are not balanced.
> +}
> +
> +static DEFINE_SIMPLE_DEV_PM_OPS(rp1_pwm_pm_ops, rp1_pwm_suspend, rp1_pwm_resume);
> +
> +static const struct of_device_id rp1_pwm_of_match[] = {
> + { .compatible = "raspberrypi,rp1-pwm" },
> + { /* sentinel */ }
> +};
> +MODULE_DEVICE_TABLE(of, rp1_pwm_of_match);
> +
> +static struct platform_driver rp1_pwm_driver = {
> + .probe = rp1_pwm_probe,
> + .driver = {
> + .name = "rp1-pwm",
> + .of_match_table = rp1_pwm_of_match,
> + .pm = pm_ptr(&rp1_pwm_pm_ops),
> + },
> +};
> +module_platform_driver(rp1_pwm_driver);
> +
> +MODULE_DESCRIPTION("RP1 PWM driver");
> +MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>");
> +MODULE_LICENSE("GPL");
> --
> 2.35.3
>
Best regards
Uwe
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply
* Re: (subset) [PATCH v6 0/5] Add CCI and imx577 sensor support for Talos evk
From: Bjorn Andersson @ 2026-04-05 19:40 UTC (permalink / raw)
To: Loic Poulain, Andi Shyti, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Konrad Dybcio, Robert Foss, Todor Tomov,
Bryan O'Donoghue, Vladimir Zapolskiy, Shawn Guo, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Frank Li, Wenmeng Liu
Cc: linux-i2c, linux-arm-msm, devicetree, linux-kernel, linux-media,
imx, linux-arm-kernel, Krzysztof Kozlowski, Konrad Dybcio,
Dmitry Baryshkov
In-Reply-To: <20260305-sm6150_evk-v6-0-38ce4360d5e0@oss.qualcomm.com>
On Thu, 05 Mar 2026 17:48:11 +0800, Wenmeng Liu wrote:
> Talos EVK is based on the Qualcomm SM6150 SoC.
> It lacks a camera sensor in its default configuration.
> This series adds CCI support and enables the IMX577 sensor via CSIPHY1
> through device tree overlay.
>
> We have tested IMX577 Sensor on CCI1 with following commands:
> - media-ctl -d /dev/media0 --reset
> - media-ctl -d /dev/media0 -V '"imx577 1-001a":0[fmt:SRGGB10/4056x3040 field:none]'
> - media-ctl -d /dev/media0 -V '"msm_csiphy1":0[fmt:SRGGB10/4056x3040]'
> - media-ctl -d /dev/media0 -V '"msm_csid0":0[fmt:SRGGB10/4056x3040]'
> - media-ctl -d /dev/media0 -V '"msm_vfe0_rdi0":0[fmt:SRGGB10/4056x3040]'
> - media-ctl -d /dev/media0 -l '"msm_csiphy1":1->"msm_csid0":0[1]'
> - media-ctl -d /dev/media0 -l '"msm_csid0":1->"msm_vfe0_rdi0":0[1]'
> - yavta -B capture-mplane -n 5 -f SRGGB10P -s 4056x3040 -F /dev/video0 --capture=5
>
> [...]
Applied, thanks!
[2/5] arm64: dts: qcom: talos: Add camss node
commit: c0b357d5d059812e5b48fab81270d8f4c8f62162
[3/5] arm64: dts: qcom: talos: Add CCI definitions
commit: 17ba0a3c874684c9ca5a41ddf9f167648b10aad2
[4/5] arm64: dts: qcom: talos: Add camera MCLK pinctrl
commit: fd3850cde71f284ca69f70b904df78f561ece103
[5/5] arm64: dts: qcom: talos-evk-camera: Add DT overlay
commit: 594be93cdc9dcfec5d10882ed3fccce1e3af9015
Best regards,
--
Bjorn Andersson <andersson@kernel.org>
^ permalink raw reply
* Re: (subset) [PATCH 1/2] clk: qcom: Constify qcom_cc_driver_data
From: Bjorn Andersson @ 2026-04-05 19:40 UTC (permalink / raw)
To: Michael Turquette, Stephen Boyd, Maxime Coquelin,
Alexandre Torgue, linux-arm-msm, linux-clk, linux-kernel,
linux-stm32, linux-arm-kernel, Krzysztof Kozlowski
In-Reply-To: <20260331091721.61613-3-krzysztof.kozlowski@oss.qualcomm.com>
On Tue, 31 Mar 2026 11:17:22 +0200, Krzysztof Kozlowski wrote:
> The static 'struct qcom_cc_driver_data' contains probe match-like data
> and is not modified: neither by the driver defining it nor by common.c
> code using it.
>
> Make it const for code safety and code readability.
>
>
> [...]
Applied, thanks!
[2/2] clk: qcom: Constify list of critical CBCR registers
commit: 87df31ea43eef5f6b9e7be0fa2555e58a9455e05
Best regards,
--
Bjorn Andersson <andersson@kernel.org>
^ permalink raw reply
* Re: [PATCH v2 1/3] pinctrl: sunxi: a523: Remove unneeded IRQ remuxing flag
From: Andre Przywara @ 2026-04-05 15:27 UTC (permalink / raw)
To: Chen-Yu Tsai
Cc: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Jernej Skrabec,
Samuel Holland, linux-gpio, devicetree, linux-arm-kernel,
linux-sunxi, linux-kernel
In-Reply-To: <CAGb2v64A0rgiMkTCdvq-pVfzCTqWKqc=nx69B9tD7A8_E7vHUg@mail.gmail.com>
On Fri, 27 Mar 2026 19:38:57 +0800
Chen-Yu Tsai <wens@kernel.org> wrote:
Hi Linus,
> On Fri, Mar 27, 2026 at 7:30 PM Andre Przywara <andre.przywara@arm.com> wrote:
> >
> > The Allwinner A10 and H3 SoCs cannot read the state of a GPIO line when
> > that line is muxed for IRQ triggering (muxval 6), but only if it's
> > explicitly muxed for GPIO input (muxval 0). Other SoCs do not show this
> > behaviour, so we added a optional workaround, triggered by a quirk bit,
> > which triggers remuxing the pin when it's configured for IRQ, while we
> > need to read its value.
> >
> > For some reasons this quirk flag was copied over to newer SoCs, even
> > though they don't show this behaviour, and the GPIO data register
> > reflects the true GPIO state even with a pin muxed to IRQ trigger.
> >
> > Remove the unneeded quirk from the A523 family, where it's definitely
> > not needed (confirmed by experiments), and where it actually breaks,
> > because the workaround is not compatible with the newer generation
> > pinctrl IP used in that chip.
> >
> > Together with a DT change this fixes GPIO IRQ operation on the A523
> > family of SoCs, as for instance used for the SD card detection.
> >
> > Signed-off-by: Andre Przywara <andre.przywara@arm.com>
> > Fixes: b8a51e95b376 ("pinctrl: sunxi: Add support for the secondary A523 GPIO ports")
>
> Acked-by: Chen-Yu Tsai <wens@kernel.org>
Can you possibly take this patch and maybe the binding (PATCH v2 2/3)?
Ideally still for v7.0? IIUC Chen-Yu would take the DT patch, but
relies on those two here.
Thanks,
Andre
>
> > ---
> > drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c | 1 -
> > drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c | 1 -
> > 2 files changed, 2 deletions(-)
> >
> > diff --git a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c
> > index 69cd2b4ebd7d..462aa1c4a5fa 100644
> > --- a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c
> > +++ b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523-r.c
> > @@ -26,7 +26,6 @@ static const u8 a523_r_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] =
> > static struct sunxi_pinctrl_desc a523_r_pinctrl_data = {
> > .irq_banks = ARRAY_SIZE(a523_r_irq_bank_map),
> > .irq_bank_map = a523_r_irq_bank_map,
> > - .irq_read_needs_mux = true,
> > .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
> > .pin_base = PL_BASE,
> > };
> > diff --git a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c
> > index 7d2308c37d29..b6f78f1f30ac 100644
> > --- a/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c
> > +++ b/drivers/pinctrl/sunxi/pinctrl-sun55i-a523.c
> > @@ -26,7 +26,6 @@ static const u8 a523_irq_bank_muxes[SUNXI_PINCTRL_MAX_BANKS] =
> > static struct sunxi_pinctrl_desc a523_pinctrl_data = {
> > .irq_banks = ARRAY_SIZE(a523_irq_bank_map),
> > .irq_bank_map = a523_irq_bank_map,
> > - .irq_read_needs_mux = true,
> > .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_SEL,
> > };
> >
> > --
> > 2.43.0
> >
>
^ permalink raw reply
* [PATCH v10 19/20] coresight: Move CPU hotplug callbacks to core layer
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
This commit moves CPU hotplug callbacks from ETMv4 driver to core layer.
The motivation is the core layer can control all components on an
activated path rather but not only managing tracer in ETMv4 driver.
The perf event layer will disable CoreSight PMU event 'cs_etm' when
hotplug off a CPU. That means a perf mode will be always converted to
disabled mode in CPU hotplug. Arm CoreSight CPU hotplug callbacks only
need to handle the Sysfs mode and ignore the perf mode.
Change CPUHP_AP_ARM_CORESIGHT_STARTING to CPUHP_AP_ARM_CORESIGHT_ONLINE
so that the CPU hotplug callback runs in the online state and thread
context, allowing coresight_disable_sysfs() to be called directly to
disable the path.
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 42 +++++++++++++++++++++-
drivers/hwtracing/coresight/coresight-etm3x-core.c | 40 ---------------------
drivers/hwtracing/coresight/coresight-etm4x-core.c | 37 -------------------
include/linux/cpuhotplug.h | 2 +-
4 files changed, 42 insertions(+), 79 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index a918bf6398a932de30fe9b4947020cc4c1cfb2f7..af0ec6d1df7baea2a7beb9ee0a28bb969eb4ccf2 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1889,13 +1889,53 @@ static struct notifier_block coresight_cpu_pm_nb = {
.notifier_call = coresight_cpu_pm_notify,
};
+static int coresight_dying_cpu(unsigned int cpu)
+{
+ struct coresight_device *source;
+ struct coresight_path *path;
+
+ /* Disable interrupt to avoid race with perf session */
+ scoped_guard(irqsave) {
+ path = coresight_get_percpu_local_path();
+ if (!path)
+ return 0;
+
+ source = coresight_get_source(path);
+ if (!source)
+ return 0;
+
+ /*
+ * The perf event layer will disable PMU events in the CPU
+ * hotplug. Here only handles SYSFS case.
+ */
+ if (coresight_get_mode(source) != CS_MODE_SYSFS)
+ return 0;
+ }
+
+ coresight_disable_sysfs(source);
+ return 0;
+}
+
static int __init coresight_pm_setup(void)
{
- return cpu_pm_register_notifier(&coresight_cpu_pm_nb);
+ int ret;
+
+ ret = cpu_pm_register_notifier(&coresight_cpu_pm_nb);
+ if (ret)
+ return ret;
+
+ ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_ONLINE,
+ "arm/coresight-core:starting",
+ NULL, coresight_dying_cpu);
+ if (ret)
+ cpu_pm_unregister_notifier(&coresight_cpu_pm_nb);
+
+ return ret;
}
static void coresight_pm_cleanup(void)
{
+ cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_ONLINE);
cpu_pm_unregister_notifier(&coresight_cpu_pm_nb);
}
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index 46ea66b5cf1985bd7129688f175f6f92372d04ad..5c6b131465c52fd8ab9161bf36fc78ba9a7dd99b 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -699,35 +699,6 @@ static int etm_online_cpu(unsigned int cpu)
return 0;
}
-static int etm_starting_cpu(unsigned int cpu)
-{
- if (!etmdrvdata[cpu])
- return 0;
-
- spin_lock(&etmdrvdata[cpu]->spinlock);
- if (!etmdrvdata[cpu]->os_unlock) {
- etm_os_unlock(etmdrvdata[cpu]);
- etmdrvdata[cpu]->os_unlock = true;
- }
-
- if (coresight_get_mode(etmdrvdata[cpu]->csdev))
- etm_enable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
- return 0;
-}
-
-static int etm_dying_cpu(unsigned int cpu)
-{
- if (!etmdrvdata[cpu])
- return 0;
-
- spin_lock(&etmdrvdata[cpu]->spinlock);
- if (coresight_get_mode(etmdrvdata[cpu]->csdev))
- etm_disable_hw(etmdrvdata[cpu]);
- spin_unlock(&etmdrvdata[cpu]->spinlock);
- return 0;
-}
-
static bool etm_arch_supported(u8 arch)
{
switch (arch) {
@@ -795,13 +766,6 @@ static int __init etm_hp_setup(void)
{
int ret;
- ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING,
- "arm/coresight:starting",
- etm_starting_cpu, etm_dying_cpu);
-
- if (ret)
- return ret;
-
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"arm/coresight:online",
etm_online_cpu, NULL);
@@ -812,15 +776,11 @@ static int __init etm_hp_setup(void)
return 0;
}
- /* failed dyn state - remove others */
- cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
-
return ret;
}
static void etm_hp_clear(void)
{
- cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
if (hp_online) {
cpuhp_remove_state_nocalls(hp_online);
hp_online = 0;
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 5ccbf792fe71bec7d5b74c24288c5313afdb7cd0..879950ec0f527c0151f00266f6bf5d569ad460d8 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -1829,33 +1829,6 @@ static int etm4_online_cpu(unsigned int cpu)
return 0;
}
-static int etm4_starting_cpu(unsigned int cpu)
-{
- if (!etmdrvdata[cpu])
- return 0;
-
- raw_spin_lock(&etmdrvdata[cpu]->spinlock);
- if (!etmdrvdata[cpu]->os_unlock)
- etm4_os_unlock(etmdrvdata[cpu]);
-
- if (coresight_get_mode(etmdrvdata[cpu]->csdev))
- etm4_enable_hw(etmdrvdata[cpu]);
- raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
- return 0;
-}
-
-static int etm4_dying_cpu(unsigned int cpu)
-{
- if (!etmdrvdata[cpu])
- return 0;
-
- raw_spin_lock(&etmdrvdata[cpu]->spinlock);
- if (coresight_get_mode(etmdrvdata[cpu]->csdev))
- etm4_disable_hw(etmdrvdata[cpu]);
- raw_spin_unlock(&etmdrvdata[cpu]->spinlock);
- return 0;
-}
-
static inline bool etm4_pm_save_needed(void)
{
return pm_save_enable == PARAM_PM_SAVE_SELF_HOSTED;
@@ -2116,13 +2089,6 @@ static int __init etm4_pm_setup(void)
{
int ret;
- ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING,
- "arm/coresight4:starting",
- etm4_starting_cpu, etm4_dying_cpu);
-
- if (ret)
- return ret;
-
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"arm/coresight4:online",
etm4_online_cpu, NULL);
@@ -2133,14 +2099,11 @@ static int __init etm4_pm_setup(void)
return 0;
}
- /* failed dyn state - remove others */
- cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
return ret;
}
static void etm4_pm_clear(void)
{
- cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
if (hp_online) {
cpuhp_remove_state_nocalls(hp_online);
hp_online = 0;
diff --git a/include/linux/cpuhotplug.h b/include/linux/cpuhotplug.h
index 62cd7b35a29c94f214fec3b55f9462eceffad694..b9196ef6d83471400bb8bc5a8c4fd486c0acd4cc 100644
--- a/include/linux/cpuhotplug.h
+++ b/include/linux/cpuhotplug.h
@@ -181,7 +181,6 @@ enum cpuhp_state {
CPUHP_AP_DUMMY_TIMER_STARTING,
CPUHP_AP_ARM_XEN_STARTING,
CPUHP_AP_ARM_XEN_RUNSTATE_STARTING,
- CPUHP_AP_ARM_CORESIGHT_STARTING,
CPUHP_AP_ARM_CORESIGHT_CTI_STARTING,
CPUHP_AP_ARM64_ISNDEP_STARTING,
CPUHP_AP_SMPCFD_DYING,
@@ -201,6 +200,7 @@ enum cpuhp_state {
CPUHP_AP_IRQ_AFFINITY_ONLINE,
CPUHP_AP_BLK_MQ_ONLINE,
CPUHP_AP_ARM_MVEBU_SYNC_CLOCKS,
+ CPUHP_AP_ARM_CORESIGHT_ONLINE,
CPUHP_AP_X86_INTEL_EPB_ONLINE,
CPUHP_AP_PERF_ONLINE,
CPUHP_AP_PERF_X86_ONLINE,
--
2.34.1
^ permalink raw reply related
* [PATCH v10 20/20] coresight: sysfs: Validate CPU online status for per-CPU sources
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
The current SysFS flow first enables the links and sink, then rolls back
to disable them if the source fails to enable. This failure can occur if
the associated CPU is offline, which causes the SMP call to fail.
Validate whether the associated CPU is online for a per-CPU tracer. If
the CPU is offline, return -ENODEV and bail out.
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-sysfs.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index 75dd8c9f78174b7e604fbad6e8735656a2d643a0..b79c0abfeb77ed6f8fa299f083e0b6c656e0e6c1 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -184,6 +184,9 @@ static int coresight_validate_source_sysfs(struct coresight_device *csdev,
return -EINVAL;
}
+ if (coresight_is_percpu_source(csdev) && !cpu_online(csdev->cpu))
+ return -ENODEV;
+
return 0;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v10 18/20] coresight: sysfs: Increment refcount only for system tracers
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Except for system tracers (e.g. STM), other sources treat multiple
enables as equivalent to a single enable. The device mode already
tracks the binary state, so it is redundant to operate refcount.
Refactor to maintain the refcount only for system sources. This
simplifies future CPU PM handling without refcount logic.
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-sysfs.c | 34 ++++++++++++++++++++-------
1 file changed, 25 insertions(+), 9 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index 9449de66ba3941614928924086100866f3c88a54..75dd8c9f78174b7e604fbad6e8735656a2d643a0 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -53,6 +53,28 @@ ssize_t coresight_simple_show32(struct device *_dev,
}
EXPORT_SYMBOL_GPL(coresight_simple_show32);
+static void coresight_source_get_refcnt(struct coresight_device *csdev)
+{
+ /*
+ * There could be multiple applications driving the software
+ * source. So keep the refcount for each such user when the
+ * source is already enabled.
+ *
+ * No need to increment the reference counter for other source
+ * types, as multiple enables are the same as a single enable.
+ */
+ if (csdev->subtype.source_subtype ==
+ CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
+ csdev->refcnt++;
+}
+
+static void coresight_source_put_refcnt(struct coresight_device *csdev)
+{
+ if (csdev->subtype.source_subtype ==
+ CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
+ csdev->refcnt--;
+}
+
static int coresight_enable_source_sysfs(struct coresight_device *csdev,
enum cs_mode mode,
struct coresight_path *path)
@@ -71,7 +93,7 @@ static int coresight_enable_source_sysfs(struct coresight_device *csdev,
return ret;
}
- csdev->refcnt++;
+ coresight_source_get_refcnt(csdev);
return 0;
}
@@ -93,7 +115,7 @@ static bool coresight_disable_source_sysfs(struct coresight_device *csdev,
if (coresight_get_mode(csdev) != CS_MODE_SYSFS)
return false;
- csdev->refcnt--;
+ coresight_source_put_refcnt(csdev);
if (csdev->refcnt == 0) {
coresight_disable_source(csdev, data);
return true;
@@ -188,13 +210,7 @@ int coresight_enable_sysfs(struct coresight_device *csdev)
* doesn't hold coresight_mutex.
*/
if (coresight_get_mode(csdev) == CS_MODE_SYSFS) {
- /*
- * There could be multiple applications driving the software
- * source. So keep the refcount for each such user when the
- * source is already enabled.
- */
- if (subtype == CORESIGHT_DEV_SUBTYPE_SOURCE_SOFTWARE)
- csdev->refcnt++;
+ coresight_source_get_refcnt(csdev);
goto out;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v10 17/20] coresight: trbe: Save and restore state across CPU low power state
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
From: Yabin Cui <yabinc@google.com>
TRBE context can be lost when a CPU enters low power states. If a trace
source is restored while TRBE is not, tracing may run without an active
sink, which can lead to hangs on some devices (e.g., Pixel 9).
The save and restore flows are described in the section K5.5 "Context
switching" of Arm ARM (ARM DDI 0487 L.a). This commit adds save and
restore callbacks with following the software usages defined in the
architecture manual.
During the restore flow, since TRBLIMITR_EL1.E resets to 0 on a warm
reset, the trace buffer unit is disabled when idle resume, it is safe to
restore base/pointer/status registers first and program TRBLIMITR_EL1
last.
Signed-off-by: Yabin Cui <yabinc@google.com>
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Co-developed-by: Leo Yan <leo.yan@arm.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-trbe.c | 59 +++++++++++++++++++++++++++-
1 file changed, 58 insertions(+), 1 deletion(-)
diff --git a/drivers/hwtracing/coresight/coresight-trbe.c b/drivers/hwtracing/coresight/coresight-trbe.c
index 14e35b9660d76e47619cc6026b94929b3bb3e02b..c7cbca45f2debd4047b93283ea9fe5dd9e1f2ebf 100644
--- a/drivers/hwtracing/coresight/coresight-trbe.c
+++ b/drivers/hwtracing/coresight/coresight-trbe.c
@@ -116,6 +116,20 @@ static int trbe_errata_cpucaps[] = {
*/
#define TRBE_WORKAROUND_OVERWRITE_FILL_MODE_SKIP_BYTES 256
+/*
+ * struct trbe_save_state: Register values representing TRBE state
+ * @trblimitr - Trace Buffer Limit Address Register value
+ * @trbbaser - Trace Buffer Base Register value
+ * @trbptr - Trace Buffer Write Pointer Register value
+ * @trbsr - Trace Buffer Status Register value
+ */
+struct trbe_save_state {
+ u64 trblimitr;
+ u64 trbbaser;
+ u64 trbptr;
+ u64 trbsr;
+};
+
/*
* struct trbe_cpudata: TRBE instance specific data
* @trbe_flag - TRBE dirty/access flag support
@@ -134,6 +148,7 @@ struct trbe_cpudata {
enum cs_mode mode;
struct trbe_buf *buf;
struct trbe_drvdata *drvdata;
+ struct trbe_save_state save_state;
DECLARE_BITMAP(errata, TRBE_ERRATA_MAX);
};
@@ -1189,6 +1204,46 @@ static irqreturn_t arm_trbe_irq_handler(int irq, void *dev)
return IRQ_HANDLED;
}
+static int arm_trbe_save(struct coresight_device *csdev)
+{
+ struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
+ struct trbe_save_state *state = &cpudata->save_state;
+
+ state->trblimitr = read_sysreg_s(SYS_TRBLIMITR_EL1);
+
+ /* Disable the unit, ensure the writes to memory are complete */
+ if (state->trblimitr & TRBLIMITR_EL1_E)
+ trbe_drain_and_disable_local(cpudata);
+
+ state->trbbaser = read_sysreg_s(SYS_TRBBASER_EL1);
+ state->trbptr = read_sysreg_s(SYS_TRBPTR_EL1);
+ state->trbsr = read_sysreg_s(SYS_TRBSR_EL1);
+ return 0;
+}
+
+static void arm_trbe_restore(struct coresight_device *csdev)
+{
+ struct trbe_cpudata *cpudata = dev_get_drvdata(&csdev->dev);
+ struct trbe_save_state *state = &cpudata->save_state;
+
+ write_sysreg_s(state->trbbaser, SYS_TRBBASER_EL1);
+ write_sysreg_s(state->trbptr, SYS_TRBPTR_EL1);
+ write_sysreg_s(state->trbsr, SYS_TRBSR_EL1);
+
+ if (!(state->trblimitr & TRBLIMITR_EL1_E)) {
+ write_sysreg_s(state->trblimitr, SYS_TRBLIMITR_EL1);
+ } else {
+ /*
+ * The section K5.5 Context switching, Arm ARM (ARM DDI 0487
+ * L.a), S_PKLXF requires a Context synchronization event to
+ * guarantee the Trace Buffer Unit will observe the new values
+ * of the system registers.
+ */
+ isb();
+ set_trbe_enabled(cpudata, state->trblimitr);
+ }
+}
+
static const struct coresight_ops_sink arm_trbe_sink_ops = {
.enable = arm_trbe_enable,
.disable = arm_trbe_disable,
@@ -1198,7 +1253,9 @@ static const struct coresight_ops_sink arm_trbe_sink_ops = {
};
static const struct coresight_ops arm_trbe_cs_ops = {
- .sink_ops = &arm_trbe_sink_ops,
+ .pm_save_disable = arm_trbe_save,
+ .pm_restore_enable = arm_trbe_restore,
+ .sink_ops = &arm_trbe_sink_ops,
};
static ssize_t align_show(struct device *dev, struct device_attribute *attr, char *buf)
--
2.34.1
^ permalink raw reply related
* [PATCH v10 16/20] coresight: Add PM callbacks for sink device
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Unlike system level sinks, per-CPU sinks may lose power during CPU idle
states. Currently, this applies specifically to TRBE. This commit
invokes save and restore callbacks for the sink in the CPU PM notifier.
If the sink provides PM callbacks but the source does not, this is
unsafe because the sink cannot be disabled safely unless the source
can also be controlled, so veto low power entry to avoid lockups.
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 46 ++++++++++++++++++++++++++--
1 file changed, 43 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index c1e8debc76aba7eb5ecf7efe2a3b9b8b3e11b10c..a918bf6398a932de30fe9b4947020cc4c1cfb2f7 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -1736,14 +1736,15 @@ static void coresight_release_device_list(void)
/* Return: 1 if PM is required, 0 if skip, <0 on error */
static int coresight_pm_check(struct coresight_path *path)
{
- struct coresight_device *source;
- bool source_has_cb;
+ struct coresight_device *source, *sink;
+ bool source_has_cb, sink_has_cb;
if (!path)
return 0;
source = coresight_get_source(path);
- if (!source)
+ sink = coresight_get_sink(path);
+ if (!source || !sink)
return 0;
/* Don't save and restore if the source is inactive */
@@ -1759,16 +1760,36 @@ static int coresight_pm_check(struct coresight_path *path)
if (source_has_cb)
return 1;
+ sink_has_cb = coresight_ops(sink)->pm_save_disable &&
+ coresight_ops(sink)->pm_restore_enable;
+ /*
+ * It is not permitted that the source has no callbacks while the sink
+ * does, as the sink cannot be disabled without disabling the source,
+ * which may lead to lockups. Alternatively, the ETM driver should
+ * enable self-hosted PM mode at probe (see etm4_probe()).
+ */
+ if (sink_has_cb) {
+ pr_warn_once("coresight PM failed: source has no PM callbacks; "
+ "cannot safely control sink\n");
+ return -EINVAL;
+ }
+
return 0;
}
static int coresight_pm_device_save(struct coresight_device *csdev)
{
+ if (!csdev || !coresight_ops(csdev)->pm_save_disable)
+ return 0;
+
return coresight_ops(csdev)->pm_save_disable(csdev);
}
static void coresight_pm_device_restore(struct coresight_device *csdev)
{
+ if (!csdev || !coresight_ops(csdev)->pm_restore_enable)
+ return;
+
coresight_ops(csdev)->pm_restore_enable(csdev);
}
@@ -1787,15 +1808,32 @@ static int coresight_pm_save(struct coresight_path *path)
to = list_prev_entry(coresight_path_last_node(path), link);
coresight_disable_path_from_to(path, from, to);
+ ret = coresight_pm_device_save(coresight_get_sink(path));
+ if (ret)
+ goto sink_failed;
+
return 0;
+
+sink_failed:
+ if (!coresight_enable_path_from_to(path, coresight_get_mode(source),
+ from, to))
+ coresight_pm_device_restore(source);
+
+ pr_err("Failed in coresight PM save on CPU%d: %d\n",
+ smp_processor_id(), ret);
+ this_cpu_write(percpu_pm_failed, true);
+ return ret;
}
static void coresight_pm_restore(struct coresight_path *path)
{
struct coresight_device *source = coresight_get_source(path);
+ struct coresight_device *sink = coresight_get_sink(path);
struct coresight_node *from, *to;
int ret;
+ coresight_pm_device_restore(sink);
+
from = coresight_path_first_node(path);
/* Up to the node before sink to avoid latency */
to = list_prev_entry(coresight_path_last_node(path), link);
@@ -1808,6 +1846,8 @@ static void coresight_pm_restore(struct coresight_path *path)
return;
path_failed:
+ coresight_pm_device_save(sink);
+
pr_err("Failed in coresight PM restore on CPU%d: %d\n",
smp_processor_id(), ret);
--
2.34.1
^ permalink raw reply related
* [PATCH v10 15/20] coresight: Control path during CPU idle
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Extend the CPU PM flow to control the path: disable from source up to
the node before the sink, then re-enable the same range on restore.
To avoid latency, control it up to the node before the sink.
Track per-CPU PM restore failures using percpu_pm_failed. Once a CPU
hits a restore failure, set the percpu_pm_failed and return NOTIFY_BAD
on subsequent notifications to avoid repeating half-completed
transitions.
Setting percpu_pm_failed permanently blocks CPU PM on that CPU. Such
failures are typically seen during development; disabling PM operations
simplifies the implementation, and a warning highlights the issue.
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 47 +++++++++++++++++++++++++---
1 file changed, 43 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 02d26dd0171ebf4e884bb3e0028b9a21588f061a..c1e8debc76aba7eb5ecf7efe2a3b9b8b3e11b10c 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -37,6 +37,7 @@ DEFINE_MUTEX(coresight_mutex);
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
static DEFINE_PER_CPU(struct coresight_path *, percpu_path);
+static DEFINE_PER_CPU(bool, percpu_pm_failed);
/**
* struct coresight_node - elements of a path, from source to sink
@@ -1732,7 +1733,7 @@ static void coresight_release_device_list(void)
}
}
-/* Return: 1 if PM is required, 0 if skip */
+/* Return: 1 if PM is required, 0 if skip, <0 on error */
static int coresight_pm_check(struct coresight_path *path)
{
struct coresight_device *source;
@@ -1749,6 +1750,9 @@ static int coresight_pm_check(struct coresight_path *path)
if (coresight_get_mode(source) == CS_MODE_DISABLED)
return 0;
+ if (this_cpu_read(percpu_pm_failed))
+ return -EIO;
+
/* pm_save_disable() and pm_restore_enable() must be paired */
source_has_cb = coresight_ops(source)->pm_save_disable &&
coresight_ops(source)->pm_restore_enable;
@@ -1771,24 +1775,59 @@ static void coresight_pm_device_restore(struct coresight_device *csdev)
static int coresight_pm_save(struct coresight_path *path)
{
struct coresight_device *source = coresight_get_source(path);
+ struct coresight_node *from, *to;
+ int ret;
+
+ ret = coresight_pm_device_save(source);
+ if (ret)
+ return ret;
+
+ from = coresight_path_first_node(path);
+ /* Up to the node before sink to avoid latency */
+ to = list_prev_entry(coresight_path_last_node(path), link);
+ coresight_disable_path_from_to(path, from, to);
- return coresight_pm_device_save(source);
+ return 0;
}
static void coresight_pm_restore(struct coresight_path *path)
{
struct coresight_device *source = coresight_get_source(path);
+ struct coresight_node *from, *to;
+ int ret;
+
+ from = coresight_path_first_node(path);
+ /* Up to the node before sink to avoid latency */
+ to = list_prev_entry(coresight_path_last_node(path), link);
+ ret = coresight_enable_path_from_to(path, coresight_get_mode(source),
+ from, to);
+ if (ret)
+ goto path_failed;
coresight_pm_device_restore(source);
+ return;
+
+path_failed:
+ pr_err("Failed in coresight PM restore on CPU%d: %d\n",
+ smp_processor_id(), ret);
+
+ /*
+ * Once PM fails on a CPU, set percpu_pm_failed and leave it set until
+ * reboot. This prevents repeated partial transitions during idle
+ * entry and exit.
+ */
+ this_cpu_write(percpu_pm_failed, true);
}
static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
void *v)
{
struct coresight_path *path = coresight_get_percpu_local_path();
+ int ret;
- if (!coresight_pm_check(path))
- return NOTIFY_DONE;
+ ret = coresight_pm_check(path);
+ if (ret <= 0)
+ return ret ? NOTIFY_BAD : NOTIFY_DONE;
switch (cmd) {
case CPU_PM_ENTER:
--
2.34.1
^ permalink raw reply related
* [PATCH v10 14/20] coresight: Introduce coresight_enable_source() helper
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Introduce the coresight_enable_source() helper for enabling source
device.
Add validation to ensure the device is a source before proceeding with
further operations.
Reviewed-by: James Clark <james.clark@linaro.org>
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 18 ++++++++++++++++--
drivers/hwtracing/coresight/coresight-etm-perf.c | 2 +-
drivers/hwtracing/coresight/coresight-priv.h | 3 +++
drivers/hwtracing/coresight/coresight-sysfs.c | 2 +-
4 files changed, 21 insertions(+), 4 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 3d2876d37c5bc371dd5a88640e080f6e52af5294..02d26dd0171ebf4e884bb3e0028b9a21588f061a 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -411,11 +411,25 @@ static void coresight_disable_helpers(struct coresight_device *csdev,
}
/*
- * coresight_disable_source() only disables the source, but do nothing for
- * the associated helpers, which are controlled as part of the path.
+ * coresight_enable_source() and coresight_disable_source() only enable and
+ * disable the source, but do nothing for the associated helpers, which are
+ * controlled as part of the path.
*/
+int coresight_enable_source(struct coresight_device *csdev,
+ struct perf_event *event, enum cs_mode mode,
+ struct coresight_path *path)
+{
+ if (!coresight_is_device_source(csdev))
+ return -EINVAL;
+
+ return source_ops(csdev)->enable(csdev, event, mode, path);
+}
+
void coresight_disable_source(struct coresight_device *csdev, void *data)
{
+ if (!coresight_is_device_source(csdev))
+ return;
+
source_ops(csdev)->disable(csdev, data);
}
EXPORT_SYMBOL_GPL(coresight_disable_source);
diff --git a/drivers/hwtracing/coresight/coresight-etm-perf.c b/drivers/hwtracing/coresight/coresight-etm-perf.c
index cae6738e9906c35d291e4b0f3feae37306b95c06..b23c8c4b87972ed530743ef93bea69544c2c5ebf 100644
--- a/drivers/hwtracing/coresight/coresight-etm-perf.c
+++ b/drivers/hwtracing/coresight/coresight-etm-perf.c
@@ -533,7 +533,7 @@ static void etm_event_start(struct perf_event *event, int flags)
goto fail_end_stop;
/* Finally enable the tracer */
- if (source_ops(csdev)->enable(csdev, event, CS_MODE_PERF, path))
+ if (coresight_enable_source(csdev, event, CS_MODE_PERF, path))
goto fail_disable_path;
/*
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index ff8a720339deb854ac3b4eb916f49e844f442d34..43ce810ad5deab339f0a336266b6018ddaf8c4fd 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -248,6 +248,9 @@ void coresight_add_helper(struct coresight_device *csdev,
void coresight_set_percpu_sink(int cpu, struct coresight_device *csdev);
struct coresight_device *coresight_get_percpu_sink(int cpu);
+int coresight_enable_source(struct coresight_device *csdev,
+ struct perf_event *event, enum cs_mode mode,
+ struct coresight_path *path);
void coresight_disable_source(struct coresight_device *csdev, void *data);
void coresight_pause_source(struct coresight_device *csdev);
int coresight_resume_source(struct coresight_device *csdev);
diff --git a/drivers/hwtracing/coresight/coresight-sysfs.c b/drivers/hwtracing/coresight/coresight-sysfs.c
index f398dbfbcb8de0c5a873837c19b3fdcf97b64abe..9449de66ba3941614928924086100866f3c88a54 100644
--- a/drivers/hwtracing/coresight/coresight-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-sysfs.c
@@ -66,7 +66,7 @@ static int coresight_enable_source_sysfs(struct coresight_device *csdev,
*/
lockdep_assert_held(&coresight_mutex);
if (coresight_get_mode(csdev) != CS_MODE_SYSFS) {
- ret = source_ops(csdev)->enable(csdev, NULL, mode, path);
+ ret = coresight_enable_source(csdev, NULL, mode, path);
if (ret)
return ret;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v10 13/20] coresight: Use helpers to fetch first and last nodes
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Replace open code with coresight_path_first_node() and
coresight_path_last_node() for fetching the nodes.
Check that the node is not NULL before accessing csdev field.
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 14 ++++++++++++--
1 file changed, 12 insertions(+), 2 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 752fe3b4b90fce34c4d245ff994a8afdb8ece463..3d2876d37c5bc371dd5a88640e080f6e52af5294 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -106,11 +106,16 @@ EXPORT_SYMBOL_GPL(coresight_get_percpu_sink);
static struct coresight_device *coresight_get_source(struct coresight_path *path)
{
struct coresight_device *csdev;
+ struct coresight_node *nd;
if (!path)
return NULL;
- csdev = list_first_entry(&path->path_list, struct coresight_node, link)->csdev;
+ nd = coresight_path_first_node(path);
+ if (!nd)
+ return NULL;
+
+ csdev = nd->csdev;
if (!coresight_is_device_source(csdev))
return NULL;
@@ -644,11 +649,16 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
struct coresight_device *coresight_get_sink(struct coresight_path *path)
{
struct coresight_device *csdev;
+ struct coresight_node *nd;
if (!path)
return NULL;
- csdev = list_last_entry(&path->path_list, struct coresight_node, link)->csdev;
+ nd = coresight_path_last_node(path);
+ if (!nd)
+ return NULL;
+
+ csdev = nd->csdev;
if (csdev->type != CORESIGHT_DEV_TYPE_SINK &&
csdev->type != CORESIGHT_DEV_TYPE_LINKSINK)
return NULL;
--
2.34.1
^ permalink raw reply related
* [PATCH v10 12/20] coresight: Control path with range
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Add parameters @from and @to for path enabling and disabling, allowing
finer-grained control of a path. The range is [@from..@to], where both
@from and @to are inclusive, introduce coresight_path_nodes_in_order()
to validate the given range if is ordered.
The helpers coresight_path_{first|last}_node() are provided for
conveniently fetching the first and last nodes on the path.
A minor refactoring removes the local variable "source" from
coresight_enable_path_from_to(), deferring reading the source until it
is needed.
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 95 ++++++++++++++++++++++------
1 file changed, 77 insertions(+), 18 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 348eb16a23ad7606ede9f26ae6820ea102ddb8cd..752fe3b4b90fce34c4d245ff994a8afdb8ece463 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -61,6 +61,24 @@ static LIST_HEAD(coresight_dev_idx_list);
static const struct cti_assoc_op *cti_assoc_ops;
+static struct coresight_node *
+coresight_path_first_node(struct coresight_path *path)
+{
+ if (list_empty(&path->path_list))
+ return NULL;
+
+ return list_first_entry(&path->path_list, struct coresight_node, link);
+}
+
+static struct coresight_node *
+coresight_path_last_node(struct coresight_path *path)
+{
+ if (list_empty(&path->path_list))
+ return NULL;
+
+ return list_last_entry(&path->path_list, struct coresight_node, link);
+}
+
void coresight_set_cti_ops(const struct cti_assoc_op *cti_op)
{
cti_assoc_ops = cti_op;
@@ -431,19 +449,41 @@ static struct coresight_path *coresight_get_percpu_local_path(void)
}
/*
- * coresight_disable_path_from : Disable components in the given path beyond
- * @nd in the list. If @nd is NULL, all the components, except the SOURCE are
- * disabled.
+ * Callers must fetch nodes from the path and pass @from and @to to the path
+ * enable/disable functions. Walk the path from @from to locate @to. If @to
+ * is found, it indicates @from and @to are in order. Otherwise, they are out
+ * of order.
*/
-static void coresight_disable_path_from(struct coresight_path *path,
- struct coresight_node *nd)
+static bool coresight_path_nodes_in_order(struct coresight_path *path,
+ struct coresight_node *from,
+ struct coresight_node *to)
+{
+ struct coresight_node *nd;
+
+ if (WARN_ON_ONCE(!from || !to))
+ return false;
+
+ nd = from;
+ list_for_each_entry_from(nd, &path->path_list, link) {
+ if (nd == to)
+ return true;
+ }
+
+ return false;
+}
+
+static void coresight_disable_path_from_to(struct coresight_path *path,
+ struct coresight_node *from,
+ struct coresight_node *to)
{
u32 type;
struct coresight_device *csdev, *parent, *child;
+ struct coresight_node *nd;
- if (!nd)
- nd = list_first_entry(&path->path_list, struct coresight_node, link);
+ if (!coresight_path_nodes_in_order(path, from, to))
+ return;
+ nd = from;
list_for_each_entry_from(nd, &path->path_list, link) {
csdev = nd->csdev;
type = csdev->type;
@@ -477,12 +517,18 @@ static void coresight_disable_path_from(struct coresight_path *path,
/* Disable all helpers adjacent along the path last */
coresight_disable_helpers(csdev, path);
+
+ /* Iterate up to and including @to */
+ if (nd == to)
+ break;
}
}
void coresight_disable_path(struct coresight_path *path)
{
- coresight_disable_path_from(path, NULL);
+ coresight_disable_path_from_to(path,
+ coresight_path_first_node(path),
+ coresight_path_last_node(path));
}
EXPORT_SYMBOL_GPL(coresight_disable_path);
@@ -506,19 +552,20 @@ static int coresight_enable_helpers(struct coresight_device *csdev,
return 0;
}
-int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
+static int coresight_enable_path_from_to(struct coresight_path *path,
+ enum cs_mode mode,
+ struct coresight_node *from,
+ struct coresight_node *to)
{
int ret = 0;
u32 type;
- struct coresight_node *nd, *last;
+ struct coresight_node *nd;
struct coresight_device *csdev, *parent, *child;
- struct coresight_device *source;
- source = coresight_get_source(path);
-
- last = list_last_entry(&path->path_list, struct coresight_node, link);
+ if (!coresight_path_nodes_in_order(path, from, to))
+ return -EINVAL;
- nd = last;
+ nd = to;
list_for_each_entry_from_reverse(nd, &path->path_list, link) {
csdev = nd->csdev;
type = csdev->type;
@@ -558,7 +605,8 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
case CORESIGHT_DEV_TYPE_LINK:
parent = list_prev_entry(nd, link)->csdev;
child = list_next_entry(nd, link)->csdev;
- ret = coresight_enable_link(csdev, parent, child, source);
+ ret = coresight_enable_link(csdev, parent, child,
+ coresight_get_source(path));
if (ret)
goto err_disable_helpers;
break;
@@ -566,6 +614,10 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
ret = -EINVAL;
goto err_disable_helpers;
}
+
+ /* Iterate down to and including @from */
+ if (nd == from)
+ break;
}
out:
@@ -574,14 +626,21 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
coresight_disable_helpers(csdev, path);
err_disable_path:
/* No device is actually enabled */
- if (nd == last)
+ if (nd == to)
goto out;
nd = list_next_entry(nd, link);
- coresight_disable_path_from(path, nd);
+ coresight_disable_path_from_to(path, nd, to);
goto out;
}
+int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
+{
+ return coresight_enable_path_from_to(path, mode,
+ coresight_path_first_node(path),
+ coresight_path_last_node(path));
+}
+
struct coresight_device *coresight_get_sink(struct coresight_path *path)
{
struct coresight_device *csdev;
--
2.34.1
^ permalink raw reply related
* [PATCH v10 11/20] coresight: Move source helper disabling to coresight_disable_path()
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Move source helper disabling to coresight_disable_path() to pair it with
coresight_enable_path().
In coresight_enable_path(), if enabling a node fails, iterate to the
next node (which is the last successfully enabled node) and pass it to
coresight_disable_path() for rollback. If the failed node is the last
node on the path, no device is actually enabled, so bail out directly.
As a result, coresight_disable_source() only controls the source,
leaving the associated helpers to be managed as part of path. Update
the comment to reflect this change.
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 32 ++++++++++++----------------
1 file changed, 14 insertions(+), 18 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 967eac5027a1f02cde29fb3a7be36304c90320b2..348eb16a23ad7606ede9f26ae6820ea102ddb8cd 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -388,19 +388,12 @@ static void coresight_disable_helpers(struct coresight_device *csdev,
}
/*
- * Helper function to call source_ops(csdev)->disable and also disable the
- * helpers.
- *
- * There is an imbalance between coresight_enable_path() and
- * coresight_disable_path(). Enabling also enables the source's helpers as part
- * of the path, but disabling always skips the first item in the path (which is
- * the source), so sources and their helpers don't get disabled as part of that
- * function and we need the extra step here.
+ * coresight_disable_source() only disables the source, but do nothing for
+ * the associated helpers, which are controlled as part of the path.
*/
void coresight_disable_source(struct coresight_device *csdev, void *data)
{
source_ops(csdev)->disable(csdev, data);
- coresight_disable_helpers(csdev, NULL);
}
EXPORT_SYMBOL_GPL(coresight_disable_source);
@@ -451,7 +444,7 @@ static void coresight_disable_path_from(struct coresight_path *path,
if (!nd)
nd = list_first_entry(&path->path_list, struct coresight_node, link);
- list_for_each_entry_continue(nd, &path->path_list, link) {
+ list_for_each_entry_from(nd, &path->path_list, link) {
csdev = nd->csdev;
type = csdev->type;
@@ -471,12 +464,6 @@ static void coresight_disable_path_from(struct coresight_path *path,
coresight_disable_sink(csdev);
break;
case CORESIGHT_DEV_TYPE_SOURCE:
- /*
- * We skip the first node in the path assuming that it
- * is the source. So we don't expect a source device in
- * the middle of a path.
- */
- WARN_ON(1);
break;
case CORESIGHT_DEV_TYPE_LINK:
parent = list_prev_entry(nd, link)->csdev;
@@ -523,12 +510,16 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
{
int ret = 0;
u32 type;
- struct coresight_node *nd;
+ struct coresight_node *nd, *last;
struct coresight_device *csdev, *parent, *child;
struct coresight_device *source;
source = coresight_get_source(path);
- list_for_each_entry_reverse(nd, &path->path_list, link) {
+
+ last = list_last_entry(&path->path_list, struct coresight_node, link);
+
+ nd = last;
+ list_for_each_entry_from_reverse(nd, &path->path_list, link) {
csdev = nd->csdev;
type = csdev->type;
@@ -582,6 +573,11 @@ int coresight_enable_path(struct coresight_path *path, enum cs_mode mode)
err_disable_helpers:
coresight_disable_helpers(csdev, path);
err_disable_path:
+ /* No device is actually enabled */
+ if (nd == last)
+ goto out;
+
+ nd = list_next_entry(nd, link);
coresight_disable_path_from(path, nd);
goto out;
}
--
2.34.1
^ permalink raw reply related
* [PATCH v10 10/20] coresight: syscfg: Use IRQ-safe spinlock to protect active variables
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
cscfg_config_sysfs_get_active_cfg() will be used from idle flows, while
sleeping locks are not allowed. Introduce sysfs_store_lock to replace
the mutex to protect sysfs_active_config and sysfs_active_preset
accesses, with IRQ-safe locking to avoid lockdep complaint.
Refactor cscfg_config_sysfs_activate() to handle errors first and use
finer-grained locking only for sysfs_active_config.
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-syscfg.c | 35 +++++++++++++-------------
drivers/hwtracing/coresight/coresight-syscfg.h | 2 ++
2 files changed, 20 insertions(+), 17 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.c b/drivers/hwtracing/coresight/coresight-syscfg.c
index d7f5037953d6ba7fb7f83a8012a1abc5ffd0a147..2ccd7659b472e4993a16be408d0647b5993c5ec7 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.c
+++ b/drivers/hwtracing/coresight/coresight-syscfg.c
@@ -953,39 +953,40 @@ int cscfg_config_sysfs_activate(struct cscfg_config_desc *config_desc, bool acti
unsigned long cfg_hash;
int err = 0;
- mutex_lock(&cscfg_mutex);
+ guard(mutex)(&cscfg_mutex);
cfg_hash = (unsigned long)config_desc->event_ea->var;
if (activate) {
/* cannot be a current active value to activate this */
- if (cscfg_mgr->sysfs_active_config) {
- err = -EBUSY;
- goto exit_unlock;
- }
+ if (cscfg_mgr->sysfs_active_config)
+ return -EBUSY;
+
err = _cscfg_activate_config(cfg_hash);
- if (!err)
+ if (err)
+ return err;
+
+ scoped_guard(raw_spinlock_irqsave, &cscfg_mgr->sysfs_store_lock)
cscfg_mgr->sysfs_active_config = cfg_hash;
} else {
+ if (cscfg_mgr->sysfs_active_config != cfg_hash)
+ return -EINVAL;
+
/* disable if matching current value */
- if (cscfg_mgr->sysfs_active_config == cfg_hash) {
- _cscfg_deactivate_config(cfg_hash);
+ _cscfg_deactivate_config(cfg_hash);
+
+ scoped_guard(raw_spinlock_irqsave, &cscfg_mgr->sysfs_store_lock)
cscfg_mgr->sysfs_active_config = 0;
- } else
- err = -EINVAL;
}
-exit_unlock:
- mutex_unlock(&cscfg_mutex);
- return err;
+ return 0;
}
/* set the sysfs preset value */
void cscfg_config_sysfs_set_preset(int preset)
{
- mutex_lock(&cscfg_mutex);
+ guard(raw_spinlock_irqsave)(&cscfg_mgr->sysfs_store_lock);
cscfg_mgr->sysfs_active_preset = preset;
- mutex_unlock(&cscfg_mutex);
}
/*
@@ -994,10 +995,9 @@ void cscfg_config_sysfs_set_preset(int preset)
*/
void cscfg_config_sysfs_get_active_cfg(unsigned long *cfg_hash, int *preset)
{
- mutex_lock(&cscfg_mutex);
+ guard(raw_spinlock_irqsave)(&cscfg_mgr->sysfs_store_lock);
*preset = cscfg_mgr->sysfs_active_preset;
*cfg_hash = cscfg_mgr->sysfs_active_config;
- mutex_unlock(&cscfg_mutex);
}
EXPORT_SYMBOL_GPL(cscfg_config_sysfs_get_active_cfg);
@@ -1201,6 +1201,7 @@ static int cscfg_create_device(void)
INIT_LIST_HEAD(&cscfg_mgr->load_order_list);
atomic_set(&cscfg_mgr->sys_active_cnt, 0);
cscfg_mgr->load_state = CSCFG_NONE;
+ raw_spin_lock_init(&cscfg_mgr->sysfs_store_lock);
/* setup the device */
dev = cscfg_device();
diff --git a/drivers/hwtracing/coresight/coresight-syscfg.h b/drivers/hwtracing/coresight/coresight-syscfg.h
index 66e2db890d8203853a0c3c907b48aa66dd8014e6..658e93c3705f1cb3ba3523d0bc27ac704697dd70 100644
--- a/drivers/hwtracing/coresight/coresight-syscfg.h
+++ b/drivers/hwtracing/coresight/coresight-syscfg.h
@@ -42,6 +42,7 @@ enum cscfg_load_ops {
* @sysfs_active_config:Active config hash used if CoreSight controlled from sysfs.
* @sysfs_active_preset:Active preset index used if CoreSight controlled from sysfs.
* @load_state: A multi-stage load/unload operation is in progress.
+ * @sysfs_store_lock: Exclusive access sysfs stored variables.
*/
struct cscfg_manager {
struct device dev;
@@ -54,6 +55,7 @@ struct cscfg_manager {
u32 sysfs_active_config;
int sysfs_active_preset;
enum cscfg_load_ops load_state;
+ raw_spinlock_t sysfs_store_lock;
};
/* get reference to dev in cscfg_manager */
--
2.34.1
^ permalink raw reply related
* [PATCH v10 09/20] coresight: etm4x: Remove redundant checks in PM save and restore
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan, Mike Leach
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
ETMv4 driver save/restore callbacks still re-check conditions that are
already validated by the core layer before the callbacks are invoked.
Remove the duplicated checks and fold the two-level functions into
direct callback implementations. The obsolete WARN_ON() checks are
removed as well.
Reviewed-by: Mike Leach <mike.leach@linaro.org>
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-etm4x-core.c | 41 +++-------------------
1 file changed, 4 insertions(+), 37 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 3fe9ebf31fe19738c8cfa3cfe6d3464ab96726ce..5ccbf792fe71bec7d5b74c24288c5313afdb7cd0 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -1861,17 +1861,14 @@ static inline bool etm4_pm_save_needed(void)
return pm_save_enable == PARAM_PM_SAVE_SELF_HOSTED;
}
-static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
+static int etm4_cpu_save(struct coresight_device *csdev)
{
int i, ret = 0;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct etmv4_save_state *state;
- struct coresight_device *csdev = drvdata->csdev;
struct csdev_access *csa;
struct device *etm_dev;
- if (WARN_ON(!csdev))
- return -ENODEV;
-
etm_dev = &csdev->dev;
csa = &csdev->access;
@@ -2003,32 +2000,13 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
return ret;
}
-static int etm4_cpu_save(struct coresight_device *csdev)
-{
- struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
- int ret = 0;
-
- if (!etm4_pm_save_needed())
- return 0;
-
- /*
- * Save and restore the ETM Trace registers only if
- * the ETM is active.
- */
- if (coresight_get_mode(drvdata->csdev))
- ret = __etm4_cpu_save(drvdata);
- return ret;
-}
-
-static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
+static void etm4_cpu_restore(struct coresight_device *csdev)
{
int i;
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
struct etmv4_save_state *state = drvdata->save_state;
struct csdev_access *csa = &drvdata->csdev->access;
- if (WARN_ON(!drvdata->csdev))
- return;
-
etm4_cs_unlock(drvdata, csa);
etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
@@ -2121,17 +2099,6 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
etm4_cs_lock(drvdata, csa);
}
-static void etm4_cpu_restore(struct coresight_device *csdev)
-{
- struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
-
- if (!etm4_pm_save_needed())
- return;
-
- if (coresight_get_mode(drvdata->csdev))
- __etm4_cpu_restore(drvdata);
-}
-
static const struct coresight_ops etm4_cs_ops = {
.trace_id = coresight_etm_get_trace_id,
.source_ops = &etm4_source_ops,
--
2.34.1
^ permalink raw reply related
* [PATCH v10 08/20] coresight: etm4x: Hook CPU PM callbacks
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Add a helper etm4_pm_save_needed() to detect if need save context for
self-hosted PM mode and hook pm_save_disable() and pm_restore_enable()
callbacks through etm4_cs_pm_ops structure. With this, ETMv4 PM
save/restore is integrated into the core layer's CPU PM.
Organize etm4_cs_ops and etm4_cs_pm_ops together for more readable.
The CPU PM notifier in the ETMv4 driver is no longer needed, remove it
along with its registration and unregistration code.
Reviewed-by: James Clark <james.clark@linaro.org>
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-etm4x-core.c | 75 +++++++---------------
1 file changed, 24 insertions(+), 51 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 7b91fab9895d7b2a65ebb1161b117d9d3f5fca1b..3fe9ebf31fe19738c8cfa3cfe6d3464ab96726ce 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -1203,11 +1203,6 @@ static const struct coresight_ops_source etm4_source_ops = {
.pause_perf = etm4_pause_perf,
};
-static const struct coresight_ops etm4_cs_ops = {
- .trace_id = coresight_etm_get_trace_id,
- .source_ops = &etm4_source_ops,
-};
-
static bool cpu_supports_sysreg_trace(void)
{
u64 dfr0 = read_sysreg_s(SYS_ID_AA64DFR0_EL1);
@@ -1861,6 +1856,11 @@ static int etm4_dying_cpu(unsigned int cpu)
return 0;
}
+static inline bool etm4_pm_save_needed(void)
+{
+ return pm_save_enable == PARAM_PM_SAVE_SELF_HOSTED;
+}
+
static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
{
int i, ret = 0;
@@ -2003,11 +2003,12 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
return ret;
}
-static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
+static int etm4_cpu_save(struct coresight_device *csdev)
{
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
int ret = 0;
- if (pm_save_enable != PARAM_PM_SAVE_SELF_HOSTED)
+ if (!etm4_pm_save_needed())
return 0;
/*
@@ -2120,47 +2121,27 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
etm4_cs_lock(drvdata, csa);
}
-static void etm4_cpu_restore(struct etmv4_drvdata *drvdata)
+static void etm4_cpu_restore(struct coresight_device *csdev)
{
- if (pm_save_enable != PARAM_PM_SAVE_SELF_HOSTED)
+ struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+
+ if (!etm4_pm_save_needed())
return;
if (coresight_get_mode(drvdata->csdev))
__etm4_cpu_restore(drvdata);
}
-static int etm4_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
- void *v)
-{
- struct etmv4_drvdata *drvdata;
- unsigned int cpu = smp_processor_id();
-
- if (!etmdrvdata[cpu])
- return NOTIFY_OK;
-
- drvdata = etmdrvdata[cpu];
-
- if (WARN_ON_ONCE(drvdata->cpu != cpu))
- return NOTIFY_BAD;
-
- switch (cmd) {
- case CPU_PM_ENTER:
- if (etm4_cpu_save(drvdata))
- return NOTIFY_BAD;
- break;
- case CPU_PM_EXIT:
- case CPU_PM_ENTER_FAILED:
- etm4_cpu_restore(drvdata);
- break;
- default:
- return NOTIFY_DONE;
- }
-
- return NOTIFY_OK;
-}
+static const struct coresight_ops etm4_cs_ops = {
+ .trace_id = coresight_etm_get_trace_id,
+ .source_ops = &etm4_source_ops,
+};
-static struct notifier_block etm4_cpu_pm_nb = {
- .notifier_call = etm4_cpu_pm_notify,
+static const struct coresight_ops etm4_cs_pm_ops = {
+ .trace_id = coresight_etm_get_trace_id,
+ .source_ops = &etm4_source_ops,
+ .pm_save_disable = etm4_cpu_save,
+ .pm_restore_enable = etm4_cpu_restore,
};
/* Setup PM. Deals with error conditions and counts */
@@ -2168,16 +2149,12 @@ static int __init etm4_pm_setup(void)
{
int ret;
- ret = cpu_pm_register_notifier(&etm4_cpu_pm_nb);
- if (ret)
- return ret;
-
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING,
"arm/coresight4:starting",
etm4_starting_cpu, etm4_dying_cpu);
if (ret)
- goto unregister_notifier;
+ return ret;
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"arm/coresight4:online",
@@ -2191,15 +2168,11 @@ static int __init etm4_pm_setup(void)
/* failed dyn state - remove others */
cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
-
-unregister_notifier:
- cpu_pm_unregister_notifier(&etm4_cpu_pm_nb);
return ret;
}
static void etm4_pm_clear(void)
{
- cpu_pm_unregister_notifier(&etm4_cpu_pm_nb);
cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
if (hp_online) {
cpuhp_remove_state_nocalls(hp_online);
@@ -2251,7 +2224,7 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
desc.type = CORESIGHT_DEV_TYPE_SOURCE;
desc.subtype.source_subtype = CORESIGHT_DEV_SUBTYPE_SOURCE_PROC;
- desc.ops = &etm4_cs_ops;
+ desc.ops = etm4_pm_save_needed() ? &etm4_cs_pm_ops : &etm4_cs_ops;
desc.pdata = pdata;
desc.dev = dev;
desc.groups = coresight_etmv4_groups;
@@ -2306,7 +2279,7 @@ static int etm4_probe(struct device *dev)
pm_save_enable = coresight_loses_context_with_cpu(dev) ?
PARAM_PM_SAVE_SELF_HOSTED : PARAM_PM_SAVE_NEVER;
- if (pm_save_enable != PARAM_PM_SAVE_NEVER) {
+ if (etm4_pm_save_needed()) {
drvdata->save_state = devm_kmalloc(dev,
sizeof(struct etmv4_save_state), GFP_KERNEL);
if (!drvdata->save_state)
--
2.34.1
^ permalink raw reply related
* [PATCH v10 07/20] coresight: Register CPU PM notifier in core layer
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
The current implementation only saves and restores the context for ETM
sources while ignoring the context of links. However, if funnels or
replicators on a linked path resides in a CPU or cluster power domain,
the hardware context for the link will be lost after resuming from low
power states.
To support context management for links during CPU low power modes, a
better way is to implement CPU PM callbacks in the Arm CoreSight core
layer. As the core layer has sufficient information for linked paths,
from tracers to links, which can be used for power management.
As a first step, this patch registers CPU PM notifier in the core layer.
If a source device provides callbacks for saving and restoring context,
these callbacks will be invoked in CPU suspend and resume.
Reviewed-by: James Clark <james.clark@linaro.org>
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 101 +++++++++++++++++++++++++++
include/linux/coresight.h | 2 +
2 files changed, 103 insertions(+)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 74c9f0dd43784dd735885249c1e50fc86f610582..967eac5027a1f02cde29fb3a7be36304c90320b2 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -6,6 +6,7 @@
#include <linux/acpi.h>
#include <linux/bitfield.h>
#include <linux/build_bug.h>
+#include <linux/cpu_pm.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/types.h>
@@ -431,6 +432,11 @@ void coresight_set_percpu_local_path(struct coresight_path *path)
}
EXPORT_SYMBOL_GPL(coresight_set_percpu_local_path);
+static struct coresight_path *coresight_get_percpu_local_path(void)
+{
+ return this_cpu_read(percpu_path);
+}
+
/*
* coresight_disable_path_from : Disable components in the given path beyond
* @nd in the list. If @nd is NULL, all the components, except the SOURCE are
@@ -1647,6 +1653,94 @@ static void coresight_release_device_list(void)
}
}
+/* Return: 1 if PM is required, 0 if skip */
+static int coresight_pm_check(struct coresight_path *path)
+{
+ struct coresight_device *source;
+ bool source_has_cb;
+
+ if (!path)
+ return 0;
+
+ source = coresight_get_source(path);
+ if (!source)
+ return 0;
+
+ /* Don't save and restore if the source is inactive */
+ if (coresight_get_mode(source) == CS_MODE_DISABLED)
+ return 0;
+
+ /* pm_save_disable() and pm_restore_enable() must be paired */
+ source_has_cb = coresight_ops(source)->pm_save_disable &&
+ coresight_ops(source)->pm_restore_enable;
+ if (source_has_cb)
+ return 1;
+
+ return 0;
+}
+
+static int coresight_pm_device_save(struct coresight_device *csdev)
+{
+ return coresight_ops(csdev)->pm_save_disable(csdev);
+}
+
+static void coresight_pm_device_restore(struct coresight_device *csdev)
+{
+ coresight_ops(csdev)->pm_restore_enable(csdev);
+}
+
+static int coresight_pm_save(struct coresight_path *path)
+{
+ struct coresight_device *source = coresight_get_source(path);
+
+ return coresight_pm_device_save(source);
+}
+
+static void coresight_pm_restore(struct coresight_path *path)
+{
+ struct coresight_device *source = coresight_get_source(path);
+
+ coresight_pm_device_restore(source);
+}
+
+static int coresight_cpu_pm_notify(struct notifier_block *nb, unsigned long cmd,
+ void *v)
+{
+ struct coresight_path *path = coresight_get_percpu_local_path();
+
+ if (!coresight_pm_check(path))
+ return NOTIFY_DONE;
+
+ switch (cmd) {
+ case CPU_PM_ENTER:
+ if (coresight_pm_save(path))
+ return NOTIFY_BAD;
+ break;
+ case CPU_PM_EXIT:
+ case CPU_PM_ENTER_FAILED:
+ coresight_pm_restore(path);
+ break;
+ default:
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block coresight_cpu_pm_nb = {
+ .notifier_call = coresight_cpu_pm_notify,
+};
+
+static int __init coresight_pm_setup(void)
+{
+ return cpu_pm_register_notifier(&coresight_cpu_pm_nb);
+}
+
+static void coresight_pm_cleanup(void)
+{
+ cpu_pm_unregister_notifier(&coresight_cpu_pm_nb);
+}
+
const struct bus_type coresight_bustype = {
.name = "coresight",
};
@@ -1701,9 +1795,15 @@ static int __init coresight_init(void)
/* initialise the coresight syscfg API */
ret = cscfg_init();
+ if (ret)
+ goto exit_notifier;
+
+ ret = coresight_pm_setup();
if (!ret)
return 0;
+ cscfg_exit();
+exit_notifier:
atomic_notifier_chain_unregister(&panic_notifier_list,
&coresight_notifier);
exit_perf:
@@ -1715,6 +1815,7 @@ static int __init coresight_init(void)
static void __exit coresight_exit(void)
{
+ coresight_pm_cleanup();
cscfg_exit();
atomic_notifier_chain_unregister(&panic_notifier_list,
&coresight_notifier);
diff --git a/include/linux/coresight.h b/include/linux/coresight.h
index e9c20ceb9016fa3db256b8c1147c1fd2027b7b0d..5f9d7ea9f5941ab01eb6a084ca558a9417c7727f 100644
--- a/include/linux/coresight.h
+++ b/include/linux/coresight.h
@@ -438,6 +438,8 @@ struct coresight_ops_panic {
struct coresight_ops {
int (*trace_id)(struct coresight_device *csdev, enum cs_mode mode,
struct coresight_device *sink);
+ int (*pm_save_disable)(struct coresight_device *csdev);
+ void (*pm_restore_enable)(struct coresight_device *csdev);
const struct coresight_ops_sink *sink_ops;
const struct coresight_ops_link *link_ops;
const struct coresight_ops_source *source_ops;
--
2.34.1
^ permalink raw reply related
* [PATCH v10 06/20] coresight: etm3x: Set per-CPU path on local CPU
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Set the path pointer on the local CPU during ETMv3 enable and disable
operations.
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-etm3x-core.c | 17 ++++++++++++++---
1 file changed, 14 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index aeeb284abdbe4b6a0960da45baa1138e203f3e3c..46ea66b5cf1985bd7129688f175f6f92372d04ad 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -441,6 +441,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
struct etm_enable_arg {
struct etm_drvdata *drvdata;
+ struct coresight_path *path;
int rc;
};
@@ -462,8 +463,12 @@ static void etm_enable_sysfs_smp_call(void *info)
arg->rc = etm_enable_hw(arg->drvdata);
/* The tracer didn't start */
- if (arg->rc)
+ if (arg->rc) {
coresight_set_mode(csdev, CS_MODE_DISABLED);
+ return;
+ }
+
+ coresight_set_percpu_local_path(arg->path);
}
void etm_release_trace_id(struct etm_drvdata *drvdata)
@@ -492,10 +497,13 @@ static int etm_enable_perf(struct coresight_device *csdev,
ret = etm_enable_hw(drvdata);
/* Failed to start tracer; roll back to DISABLED mode */
- if (ret)
+ if (ret) {
coresight_set_mode(csdev, CS_MODE_DISABLED);
+ return ret;
+ }
- return ret;
+ coresight_set_percpu_local_path(path);
+ return 0;
}
static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_path *path)
@@ -514,6 +522,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
*/
if (cpu_online(drvdata->cpu)) {
arg.drvdata = drvdata;
+ arg.path = path;
ret = smp_call_function_single(drvdata->cpu,
etm_enable_sysfs_smp_call, &arg, 1);
if (!ret)
@@ -583,6 +592,7 @@ static void etm_disable_sysfs_smp_call(void *info)
etm_disable_hw(drvdata);
+ coresight_set_percpu_local_path(NULL);
coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
}
@@ -607,6 +617,7 @@ static void etm_disable_perf(struct coresight_device *csdev)
CS_LOCK(drvdata->csa.base);
+ coresight_set_percpu_local_path(NULL);
coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
/*
--
2.34.1
^ permalink raw reply related
* [PATCH v10 05/20] coresight: etm4x: Set per-CPU path on local CPU
From: Leo Yan @ 2026-04-05 15:02 UTC (permalink / raw)
To: Suzuki K Poulose, Mike Leach, James Clark, Yeoreum Yun,
Mark Rutland, Will Deacon, Yabin Cui, Keita Morisaki,
Yuanfang Zhang, Greg Kroah-Hartman, Alexander Shishkin,
Tamas Petz, Thomas Gleixner, Peter Zijlstra
Cc: coresight, linux-arm-kernel, Leo Yan
In-Reply-To: <20260405-arm_coresight_path_power_management_improvement-v10-0-13e94754a8be@arm.com>
Introduce the coresight_set_percpu_local_path() helper to set the path
pointer on the local CPU. This helper is used during ETMv4 enable and
disable operations.
Tested-by: James Clark <james.clark@linaro.org>
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
Reviewed-by: James Clark <james.clark@linaro.org>
Signed-off-by: Leo Yan <leo.yan@arm.com>
---
drivers/hwtracing/coresight/coresight-core.c | 8 ++++++++
drivers/hwtracing/coresight/coresight-etm4x-core.c | 18 +++++++++++++++---
drivers/hwtracing/coresight/coresight-priv.h | 1 +
3 files changed, 24 insertions(+), 3 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-core.c b/drivers/hwtracing/coresight/coresight-core.c
index 6907da35ed02fa58f8d30f5576627a6ce3b88362..74c9f0dd43784dd735885249c1e50fc86f610582 100644
--- a/drivers/hwtracing/coresight/coresight-core.c
+++ b/drivers/hwtracing/coresight/coresight-core.c
@@ -35,6 +35,8 @@
DEFINE_MUTEX(coresight_mutex);
static DEFINE_PER_CPU(struct coresight_device *, csdev_sink);
+static DEFINE_PER_CPU(struct coresight_path *, percpu_path);
+
/**
* struct coresight_node - elements of a path, from source to sink
* @csdev: Address of an element.
@@ -423,6 +425,12 @@ int coresight_resume_source(struct coresight_device *csdev)
}
EXPORT_SYMBOL_GPL(coresight_resume_source);
+void coresight_set_percpu_local_path(struct coresight_path *path)
+{
+ this_cpu_write(percpu_path, path);
+}
+EXPORT_SYMBOL_GPL(coresight_set_percpu_local_path);
+
/*
* coresight_disable_path_from : Disable components in the given path beyond
* @nd in the list. If @nd is NULL, all the components, except the SOURCE are
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index a776ebb3b2b0360c99a8dadacfde4c2303dd59d6..7b91fab9895d7b2a65ebb1161b117d9d3f5fca1b 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -234,6 +234,7 @@ void etm4_release_trace_id(struct etmv4_drvdata *drvdata)
struct etm4_enable_arg {
struct etmv4_drvdata *drvdata;
+ struct coresight_path *path;
int rc;
};
@@ -621,8 +622,12 @@ static void etm4_enable_sysfs_smp_call(void *info)
arg->rc = etm4_enable_hw(arg->drvdata);
/* The tracer didn't start */
- if (arg->rc)
+ if (arg->rc) {
coresight_set_mode(csdev, CS_MODE_DISABLED);
+ return;
+ }
+
+ coresight_set_percpu_local_path(arg->path);
}
/*
@@ -890,9 +895,13 @@ static int etm4_enable_perf(struct coresight_device *csdev,
out:
/* Failed to start tracer; roll back to DISABLED mode */
- if (ret)
+ if (ret) {
coresight_set_mode(csdev, CS_MODE_DISABLED);
- return ret;
+ return ret;
+ }
+
+ coresight_set_percpu_local_path(path);
+ return 0;
}
static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_path *path)
@@ -922,6 +931,7 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
* ensures that register writes occur when cpu is powered.
*/
arg.drvdata = drvdata;
+ arg.path = path;
ret = smp_call_function_single(drvdata->cpu,
etm4_enable_sysfs_smp_call, &arg, 1);
if (!ret)
@@ -1063,6 +1073,7 @@ static void etm4_disable_sysfs_smp_call(void *info)
etm4_disable_hw(drvdata);
+ coresight_set_percpu_local_path(NULL);
coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
}
@@ -1092,6 +1103,7 @@ static int etm4_disable_perf(struct coresight_device *csdev,
/* TRCVICTLR::SSSTATUS, bit[9] */
filters->ssstatus = (control & BIT(9));
+ coresight_set_percpu_local_path(NULL);
coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
/*
diff --git a/drivers/hwtracing/coresight/coresight-priv.h b/drivers/hwtracing/coresight/coresight-priv.h
index 1ea882dffd703b2873e41b4ce0c2564d2ce9bbad..ff8a720339deb854ac3b4eb916f49e844f442d34 100644
--- a/drivers/hwtracing/coresight/coresight-priv.h
+++ b/drivers/hwtracing/coresight/coresight-priv.h
@@ -251,5 +251,6 @@ struct coresight_device *coresight_get_percpu_sink(int cpu);
void coresight_disable_source(struct coresight_device *csdev, void *data);
void coresight_pause_source(struct coresight_device *csdev);
int coresight_resume_source(struct coresight_device *csdev);
+void coresight_set_percpu_local_path(struct coresight_path *path);
#endif
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox