* [PATCH v3 7/8] arm64: dts: amlogic: t7: Add i2c controller node
From: Ronald Claveau @ 2026-04-17 16:27 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@aliel.fr>
Add the T7 i2c controller node used by the Khadas VIM4
for MCU communication.
Use amlogic,meson-axg-i2c as fallback compatible.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
index e96fe10b251a0..560c9dce35266 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7.dtsi
@@ -711,6 +711,16 @@ pwm_ao_cd: pwm@60000 {
status = "disabled";
};
+ i2c_m_ao_a: i2c@76000 {
+ compatible = "amlogic,t7-i2c", "amlogic,meson-axg-i2c";
+ reg = <0x0 0x76000 0x0 0x48>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 330 IRQ_TYPE_EDGE_RISING>;
+ clocks = <&clkc_periphs CLKID_SYS_I2C_AO_A>;
+ status = "disabled";
+ };
+
sd_emmc_a: mmc@88000 {
compatible = "amlogic,t7-mmc", "amlogic,meson-axg-mmc";
reg = <0x0 0x88000 0x0 0x800>;
--
2.49.0
^ permalink raw reply related
* [PATCH v3 8/8] arm64: dts: amlogic: t7: khadas-vim4: Add i2c MCU fan node
From: Ronald Claveau @ 2026-04-17 16:27 UTC (permalink / raw)
To: Neil Armstrong, Lee Jones, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Andi Shyti, Kevin Hilman, Jerome Brunet,
Martin Blumenstingl, Beniamino Galvani, Rafael J. Wysocki,
Daniel Lezcano, Zhang Rui, Lukasz Luba, Liam Girdwood, Mark Brown
Cc: linux-amlogic, devicetree, linux-kernel, linux-i2c,
linux-arm-kernel, linux-pm, Ronald Claveau
In-Reply-To: <20260417-add-mcu-fan-khadas-vim4-v3-0-a6a7f570b11b@aliel.fr>
Enable and configure i2c MCU node to get fan working on Khadas VIM4.
Signed-off-by: Ronald Claveau <linux-kernel-dev@aliel.fr>
---
.../boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
index 69d6118ba57e7..5d7f5390f3a66 100644
--- a/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
+++ b/arch/arm64/boot/dts/amlogic/amlogic-t7-a311d2-khadas-vim4.dts
@@ -157,6 +157,19 @@ wifi32k: wifi32k {
};
};
+&i2c_m_ao_a {
+ status = "okay";
+ pinctrl-0 = <&i2c0_ao_d_pins>;
+ pinctrl-names = "default";
+
+ khadas_mcu: system-controller@18 {
+ compatible = "khadas,vim4-mcu";
+ reg = <0x18>;
+ fan-supply = <&vcc5v>;
+ #cooling-cells = <2>;
+ };
+};
+
&pwm_ab {
status = "okay";
pinctrl-0 = <&pwm_a_pins>;
--
2.49.0
^ permalink raw reply related
* Re: [PATCH] dt-bindings: cpufreq: add mt8189 cpufreq hw dt-bindings
From: Conor Dooley @ 2026-04-17 16:40 UTC (permalink / raw)
To: Binbin Shi
Cc: Rafael J . Wysocki, Viresh Kumar, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Matthias Brugger,
AngeloGioacchino Del Regno, Hector Yuan, linux-pm, devicetree,
linux-kernel, linux-arm-kernel, linux-mediatek,
Project_Global_Chrome_Upstream_Group, vince-wl.liu
In-Reply-To: <20260417080648.3692438-1-binbin.shi@mediatek.com>
[-- Attachment #1: Type: text/plain, Size: 1144 bytes --]
On Fri, Apr 17, 2026 at 04:06:17PM +0800, Binbin Shi wrote:
> Add mt8189 cpufreq hw compatible in dt-bindings.
Why's this not compatible with the existing device? You've got no driver
change with this so I can't even guess as why. The incompatibility should
be explained in the commit message.
pw-bot: changes-requested
Cheers,
Conor.
>
> Signed-off-by: Binbin Shi <binbin.shi@mediatek.com>
> ---
> .../devicetree/bindings/cpufreq/cpufreq-mediatek-hw.yaml | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek-hw.yaml b/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek-hw.yaml
> index d0aecde2b89b..cff52fffc6b8 100644
> --- a/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek-hw.yaml
> +++ b/Documentation/devicetree/bindings/cpufreq/cpufreq-mediatek-hw.yaml
> @@ -16,7 +16,9 @@ description:
>
> properties:
> compatible:
> - const: mediatek,cpufreq-hw
> + enum:
> + - mediatek,cpufreq-hw
> + - mediatek,mt8189-cpufreq-hw
>
> reg:
> minItems: 1
> --
> 2.45.2
>
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH] pmdomain: core: Fix detach procedure for virtual devices in genpd
From: Geert Uytterhoeven @ 2026-04-17 18:36 UTC (permalink / raw)
To: Ulf Hansson
Cc: Ulf Hansson, linux-pm, Frank Binns, Matt Coster, Marek Vasut,
Rafael J . Wysocki, linux-arm-kernel, linux-kernel, stable
In-Reply-To: <20260417111331.158190-1-ulf.hansson@linaro.org>
Hi Ulf,
On Fri, 17 Apr 2026 at 13:13, Ulf Hansson <ulf.hansson@linaro.org> wrote:
> If a device is attached to a PM domain through genpd_dev_pm_attach_by_id(),
> genpd calls pm_runtime_enable() for the corresponding virtual device that
> it registers. While this avoids boilerplate code in drivers, there is no
> corresponding call to pm_runtime_disable() in genpd_dev_pm_detach().
>
> This means these virtual devices are typically detached from its genpd,
> while runtime PM remains enabled for them, which is not how things are
> designed to work. In worst cases it may lead to critical errors, like a
> NULL pointer dereference bug in genpd_runtime_suspend(), which was recently
> reported. For another case, we may end up keeping an unnecessary vote for a
> performance state for the device.
>
> To fix these problems, let's add this missing call to pm_runtime_disable()
> in genpd_dev_pm_detach().
>
> Reported-by: Geert Uytterhoeven <geert@linux-m68k.org>
> Fixes: 3c095f32a92b ("PM / Domains: Add support for multi PM domains per device to genpd")
> Cc: stable@vger.kernel.org
> Closes: https://lore.kernel.org/all/CAMuHMdWapT40hV3c+CSBqFOW05aWcV1a6v_NiJYgoYi0i9_PDQ@mail.gmail.com/
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Thanks for your patch!
This survived more than 160000 bind/unbind attempts[1] on R-Car M3-W
and M3-N, so
Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> --- a/drivers/pmdomain/core.c
> +++ b/drivers/pmdomain/core.c
> @@ -3089,6 +3089,7 @@ static const struct bus_type genpd_bus_type = {
> static void genpd_dev_pm_detach(struct device *dev, bool power_off)
> {
> struct generic_pm_domain *pd;
> + bool is_virt_dev;
> unsigned int i;
> int ret = 0;
>
> @@ -3098,6 +3099,13 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
>
> dev_dbg(dev, "removing from PM domain %s\n", pd->name);
>
> + /* Check if the device was created by genpd at attach. */
> + is_virt_dev = dev->bus == &genpd_bus_type;
> +
> + /* Disable runtime PM if we enabled it at attach. */
> + if (is_virt_dev)
> + pm_runtime_disable(dev);
> +
> /* Drop the default performance state */
> if (dev_gpd_data(dev)->default_pstate) {
> dev_pm_genpd_set_performance_state(dev, 0);
> @@ -3123,7 +3131,7 @@ static void genpd_dev_pm_detach(struct device *dev, bool power_off)
Above, out of context, there is an error return.
Should we call pm_runtime_enable() again, to keep the reference count
balanced? Or can we just ignore this? It's probably futile anyway.
> genpd_queue_power_off_work(pd);
>
> /* Unregister the device if it was created by genpd. */
> - if (dev->bus == &genpd_bus_type)
> + if (is_virt_dev)
> device_unregister(dev);
> }
>
> --
> 2.43.0
>
[1] https://lore.kernel.org/15510cee649959281d9554965cacd0c06531c1f3.1773308898.git.geert+renesas@glider.be/
Gr{oetje,eeting}s,
Geert
--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert@linux-m68k.org
In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds
^ permalink raw reply
* Re: [GIT PULL] power-supply changes for 7.1
From: pr-tracker-bot @ 2026-04-17 18:49 UTC (permalink / raw)
To: Sebastian Reichel; +Cc: Linus Torvalds, linux-kernel, linux-pm
In-Reply-To: <aeJTAaRJ6lh1wBZr@venus>
The pull request you sent on Fri, 17 Apr 2026 17:41:25 +0200:
> https://git.kernel.org/pub/scm/linux/kernel/git/sre/linux-power-supply.git tags/for-v7.1
has been merged into torvalds/linux.git:
https://git.kernel.org/torvalds/c/59bd5ae0db22566e2b961742126269c151d587c7
Thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/prtracker.html
^ permalink raw reply
* [PATCH] cpufreq: clean up dead dependencies on X86 in Kconfig
From: Julian Braha @ 2026-04-17 23:06 UTC (permalink / raw)
To: rafael, viresh.kumar
Cc: gautham.shenoy, superm1, Perry.Yuan, skhan, ray.huang, linux-pm,
linux-kernel, Julian Braha
The Kconfig in the parent directory already has an 'if X86'
condition wrapping the inclusion of this file, meaning that each of the
individual 'depends on' statements in this file is a duplicate dependency
(dead code).
I propose leaving the outer 'if X86...endif' and removing
the individual 'depends on X86' statement from each option.
This dead code was found by kconfirm, a static analysis tool for Kconfig.
Signed-off-by: Julian Braha <julianbraha@gmail.com>
---
drivers/cpufreq/Kconfig.x86 | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 027e6ea2e038..9afceb1143df 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -5,7 +5,6 @@
config X86_INTEL_PSTATE
bool "Intel P state control"
- depends on X86
select ACPI_PROCESSOR if ACPI
select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO
select CPU_FREQ_GOV_PERFORMANCE
@@ -36,7 +35,7 @@ config X86_PCC_CPUFREQ
config X86_AMD_PSTATE
bool "AMD Processor P-State driver"
- depends on X86 && ACPI
+ depends on ACPI
select ACPI_PROCESSOR
select ACPI_CPPC_LIB if X86_64
select CPU_FREQ_GOV_SCHEDUTIL if SMP
@@ -84,7 +83,7 @@ config X86_AMD_PSTATE_DYNAMIC_EPP
config X86_AMD_PSTATE_UT
tristate "selftest for AMD Processor P-State driver"
- depends on X86 && ACPI_PROCESSOR
+ depends on ACPI_PROCESSOR
depends on X86_AMD_PSTATE
default n
help
--
2.53.0
^ permalink raw reply related
* Re: [PATCH v2 0/9] driver core / pmdomain: Add support for fined grained sync_state
From: Danilo Krummrich @ 2026-04-18 11:23 UTC (permalink / raw)
To: Ulf Hansson
Cc: Saravana Kannan, Rafael J . Wysocki, Greg Kroah-Hartman, linux-pm,
Sudeep Holla, Cristian Marussi, Kevin Hilman, Stephen Boyd,
Marek Szyprowski, Bjorn Andersson, Abel Vesa, Peng Fan,
Tomi Valkeinen, Maulik Shah, Konrad Dybcio, Thierry Reding,
Jonathan Hunter, Geert Uytterhoeven, Dmitry Baryshkov,
linux-arm-kernel, linux-kernel, driver-core
In-Reply-To: <CAPDyKFrPz9gaBBp6xV1=KkoemEfapc0p3POZxuBTvDw7Vamxtg@mail.gmail.com>
On Fri Apr 17, 2026 at 1:27 PM CEST, Ulf Hansson wrote:
> + Danilo (for the driver core changes)
Thanks -- please also remember to Cc: driver-core@lists.linux.dev.
^ permalink raw reply
* Re: [PATCH v2 1/9] driver core: Enable suppliers to implement fine grained sync_state support
From: Danilo Krummrich @ 2026-04-18 11:23 UTC (permalink / raw)
To: Ulf Hansson
Cc: Saravana Kannan, Rafael J . Wysocki, Greg Kroah-Hartman, linux-pm,
Sudeep Holla, Cristian Marussi, Kevin Hilman, Stephen Boyd,
Marek Szyprowski, Bjorn Andersson, Abel Vesa, Peng Fan,
Tomi Valkeinen, Maulik Shah, Konrad Dybcio, Thierry Reding,
Jonathan Hunter, Geert Uytterhoeven, Dmitry Baryshkov,
linux-arm-kernel, linux-kernel, Geert Uytterhoeven, driver-core
In-Reply-To: <20260410104058.83748-2-ulf.hansson@linaro.org>
On Fri Apr 10, 2026 at 12:40 PM CEST, Ulf Hansson wrote:
> The common sync_state support isn't fine grained enough for some types of
> suppliers, like power domains for example. Especially when a supplier
> provides multiple independent power domains, each with their own set of
> consumers. In these cases we need to wait for all consumers for all the
> provided power domains before invoking the supplier's ->sync_state().
>
> To allow a more fine grained sync_state support to be implemented on per
> supplier's driver basis, let's add a new optional callback. As soon as
> there is an update worth to consider in regards to managing sync_state for
> a supplier device, __device_links_queue_sync_state() invokes the callback.
>
> Tested-by: Geert Uytterhoeven <geert+renesas@glider.be>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> ---
> drivers/base/core.c | 7 ++++++-
> include/linux/device/driver.h | 7 +++++++
> 2 files changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/base/core.c b/drivers/base/core.c
> index 09b98f02f559..4085a011d8ca 100644
> --- a/drivers/base/core.c
> +++ b/drivers/base/core.c
> @@ -1106,7 +1106,9 @@ int device_links_check_suppliers(struct device *dev)
> * Queues a device for a sync_state() callback when the device links write lock
> * isn't held. This allows the sync_state() execution flow to use device links
> * APIs. The caller must ensure this function is called with
> - * device_links_write_lock() held.
> + * device_links_write_lock() held. Note, if the optional queue_sync_state()
> + * callback has been assigned too, it gets called for every update to allowing a
s/allowing/allow/
> + * more fine grained support to be implemented on per supplier basis.
> *
> * This function does a get_device() to make sure the device is not freed while
> * on this list.
> @@ -1126,6 +1128,9 @@ static void __device_links_queue_sync_state(struct device *dev,
> if (dev->state_synced)
> return;
>
> + if (dev->driver && dev->driver->queue_sync_state)
> + dev->driver->queue_sync_state(dev);
This seems to be called without the device lock being held, which seems to allow
the queue_sync_state() callback to execute concurrently with remove(). This
opens the door for all kinds of UAF conditions in drivers.
This also made me aware that the above dev_has_sync_state() is probably broken,
as it also performs the following check without the device lock being held.
dev->driver && dev->driver->sync_state
I think nothing prevents dev->driver to become NULL concurrently; in this case
READ_ONCE() should be sufficient though as it doesn't execute the callback.
I will send a patch for this.
> +
> list_for_each_entry(link, &dev->links.consumers, s_node) {
> if (!device_link_test(link, DL_FLAG_MANAGED))
> continue;
> diff --git a/include/linux/device/driver.h b/include/linux/device/driver.h
> index bbc67ec513ed..bc9ae1cbe03c 100644
> --- a/include/linux/device/driver.h
> +++ b/include/linux/device/driver.h
> @@ -68,6 +68,12 @@ enum probe_type {
> * be called at late_initcall_sync level. If the device has
> * consumers that are never bound to a driver, this function
> * will never get called until they do.
> + * @queue_sync_state: Similar to the ->sync_state() callback, but called to
> + * allow syncing device state to software state in a more fine
> + * grained way. It is called when there is an updated state that
> + * may be worth to consider for any of the consumers linked to
> + * this device. If implemented, the ->sync_state() callback is
> + * required too.
What happens if this is not the case? Maybe worth to check and warn about this
in driver_register().
> * @remove: Called when the device is removed from the system to
> * unbind a device from this driver.
> * @shutdown: Called at shut-down time to quiesce the device.
> @@ -110,6 +116,7 @@ struct device_driver {
>
> int (*probe) (struct device *dev);
> void (*sync_state)(struct device *dev);
> + void (*queue_sync_state)(struct device *dev);
> int (*remove) (struct device *dev);
> void (*shutdown) (struct device *dev);
> int (*suspend) (struct device *dev, pm_message_t state);
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH v2 2/9] driver core: Add dev_set_drv_queue_sync_state()
From: Danilo Krummrich @ 2026-04-18 11:23 UTC (permalink / raw)
To: Ulf Hansson
Cc: Saravana Kannan, Rafael J . Wysocki, Greg Kroah-Hartman, linux-pm,
Sudeep Holla, Cristian Marussi, Kevin Hilman, Stephen Boyd,
Marek Szyprowski, Bjorn Andersson, Abel Vesa, Peng Fan,
Tomi Valkeinen, Maulik Shah, Konrad Dybcio, Thierry Reding,
Jonathan Hunter, Geert Uytterhoeven, Dmitry Baryshkov,
linux-arm-kernel, linux-kernel, Geert Uytterhoeven, driver-core
In-Reply-To: <20260410104058.83748-3-ulf.hansson@linaro.org>
On Fri Apr 10, 2026 at 12:40 PM CEST, Ulf Hansson wrote:
> diff --git a/include/linux/device.h b/include/linux/device.h
> index e65d564f01cd..f812e70bdf22 100644
> --- a/include/linux/device.h
> +++ b/include/linux/device.h
> @@ -994,6 +994,18 @@ static inline int dev_set_drv_sync_state(struct device *dev,
> return 0;
> }
>
> +static inline int dev_set_drv_queue_sync_state(struct device *dev,
> + void (*fn)(struct device *dev))
As this is a public function, please add some documentation.
> +{
> + if (!dev || !dev->driver)
> + return 0;
> + if (dev->driver->queue_sync_state && dev->driver->queue_sync_state != fn)
> + return -EBUSY;
> + if (!dev->driver->queue_sync_state)
> + dev->driver->queue_sync_state = fn;
I think this follows dev_set_drv_sync_state(), but I think it is worth pointing
out that it is yet another blocker for moving towards
const struct device_driver.
> + return 0;
> +}
> +
> static inline void dev_set_removable(struct device *dev,
> enum device_removable removable)
> {
> --
> 2.43.0
^ permalink raw reply
* [PATCH] treewide: fix occured typo in drivers
From: wooridge @ 2026-04-18 12:58 UTC (permalink / raw)
To: Alex Deucher, Christian Konig, Greg KH
Cc: linux-kernel, amd-gfx, dri-devel, linux-cxl, linux-rdma, linux-pm,
linux-watchdog
From 6f5ab6262d3077bc7163575d2f66cd355f18f912 Mon Sep 17 00:00:00 2001
From: wooridge <yurenwang152@gmail.com>
Date: Sat, 18 Apr 2026 20:56:36 +0800
Subject: [PATCH] treewide: fix "occured" typo in drivers/
Fix the common misspelling "occured" -> "occurred" across multiple
driver subsystems. This typo appears in comments, kernel-doc, string
literals, and one struct field name (timeout_occured -> timeout_occurred
in amdgpu dmub_srv).
Found via: grep -r "occured" drivers/
Signed-off-by: wooridge <yurenwang152@gmail.com>
---
drivers/cxl/cxlmem.h | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c | 2 +-
drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c | 4 ++--
drivers/gpu/drm/amd/amdgpu/amdgpu_job.h | 2 +-
drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 4 ++--
drivers/gpu/drm/amd/display/dmub/dmub_srv.h | 4 ++--
drivers/gpu/drm/radeon/radeon_fence.c | 4 ++--
drivers/i2c/busses/i2c-bcm-kona.c | 2 +-
drivers/iio/magnetometer/ak8975.c | 2 +-
drivers/infiniband/hw/qedr/verbs.c | 2 +-
drivers/misc/genwqe/card_base.c | 2 +-
drivers/misc/genwqe/card_ddcb.c | 2 +-
drivers/misc/vmw_vmci/vmci_queue_pair.c | 4 ++--
drivers/mtd/ubi/wl.c | 2 +-
drivers/nfc/microread/i2c.c | 2 +-
drivers/nfc/pn544/i2c.c | 2 +-
drivers/nfc/st21nfca/i2c.c | 2 +-
drivers/power/supply/ab8500_fg.c | 2 +-
drivers/power/supply/smb347-charger.c | 2 +-
drivers/target/iscsi/iscsi_target.c | 2 +-
drivers/video/backlight/ktd253-backlight.c | 2 +-
drivers/watchdog/davinci_wdt.c | 2 +-
22 files changed, 27 insertions(+), 27 deletions(-)
diff --git a/drivers/cxl/cxlmem.h b/drivers/cxl/cxlmem.h
index e21d744d639b..99592ea795a8 100644
--- a/drivers/cxl/cxlmem.h
+++ b/drivers/cxl/cxlmem.h
@@ -163,7 +163,7 @@ static inline struct cxl_ep *cxl_ep_load(struct cxl_port *port,
C(MBUNSUPPORTED, -ENXIO, "unsupported on the mailbox it was issued on"),\
C(PAYLOADLEN, -ENXIO, "invalid payload length"), \
C(LOG, -ENXIO, "invalid or unsupported log page"), \
- C(INTERRUPTED, -ENXIO, "asynchronous event occured"), \
+ C(INTERRUPTED, -ENXIO, "asynchronous event occurred"), \
C(FEATUREVERSION, -ENXIO, "unsupported feature version"), \
C(FEATURESELVALUE, -ENXIO, "unsupported feature selection value"), \
C(FEATURETRANSFERIP, -ENXIO, "feature transfer in progress"), \
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
index f2c038c91c70..1d3d0c09d8ad 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ctx.c
@@ -559,7 +559,7 @@ static int amdgpu_ctx_query(struct amdgpu_device *adev,
out->state.flags = 0x0;
out->state.hangs = 0x0;
- /* determine if a GPU reset has occured since the last call */
+ /* determine if a GPU reset has occurred since the last call */
reset_counter = atomic_read(&adev->gpu_reset_counter);
/* TODO: this should ideally return NO, GUILTY, or INNOCENT. */
if (ctx->reset_counter_query == reset_counter)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
index 64c519cd7395..ed1fbf957d73 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ids.c
@@ -150,12 +150,12 @@ void amdgpu_pasid_free_delayed(struct dma_resv *resv,
*/
/**
- * amdgpu_vmid_had_gpu_reset - check if reset occured since last use
+ * amdgpu_vmid_had_gpu_reset - check if reset occurred since last use
*
* @adev: amdgpu_device pointer
* @id: VMID structure
*
- * Check if GPU reset occured since last use of the VMID.
+ * Check if GPU reset occurred since last use of the VMID.
*/
bool amdgpu_vmid_had_gpu_reset(struct amdgpu_device *adev,
struct amdgpu_vmid *id)
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
index 56a88e14a044..bc011b4639f2 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_job.h
@@ -31,7 +31,7 @@
#define AMDGPU_PREAMBLE_IB_PRESENT (1 << 0)
/* bit set means preamble IB is first presented in belonging context */
#define AMDGPU_PREAMBLE_IB_PRESENT_FIRST (1 << 1)
-/* bit set means context switch occured */
+/* bit set means context switch occurred */
#define AMDGPU_HAVE_CTX_SWITCH (1 << 2)
/* bit set means IB is preempted */
#define AMDGPU_IB_PREEMPTED (1 << 3)
diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
index b15360bcdacf..29ec031cae7e 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -285,8 +285,8 @@ bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
if (status != DMUB_STATUS_OK) {
DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status);
- if (!dmub->debug.timeout_info.timeout_occured) {
- dmub->debug.timeout_info.timeout_occured = true;
+ if (!dmub->debug.timeout_info.timeout_occurred) {
+ dmub->debug.timeout_info.timeout_occurred = true;
if (cmd_list)
dmub->debug.timeout_info.timeout_cmd = *cmd_list;
dmub->debug.timeout_info.timestamp = dm_get_timestamp(dc_dmub_srv->ctx);
diff --git a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
index 3b6bba017040..9ce60a47068d 100644
--- a/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dmub/dmub_srv.h
@@ -353,11 +353,11 @@ struct dmub_srv_hw_params {
/**
* struct dmub_srv_debug - Debug info for dmub_srv
- * @timeout_occured: Indicates a timeout occured on any message from driver to dmub
+ * @timeout_occurred: Indicates a timeout occurred on any message from driver to dmub
* @timeout_cmd: first cmd sent from driver that timed out - subsequent timeouts are not stored
*/
struct dmub_timeout_info {
- bool timeout_occured;
+ bool timeout_occurred;
union dmub_rb_cmd timeout_cmd;
unsigned long long timestamp;
};
diff --git a/drivers/gpu/drm/radeon/radeon_fence.c b/drivers/gpu/drm/radeon/radeon_fence.c
index 02a40e4750c7..943861b62ee9 100644
--- a/drivers/gpu/drm/radeon/radeon_fence.c
+++ b/drivers/gpu/drm/radeon/radeon_fence.c
@@ -191,7 +191,7 @@ static int radeon_fence_check_signaled(wait_queue_entry_t *wait,
* @ring: ring index the fence is associated with
*
* Checks the current fence value and calculates the last
- * signalled fence value. Returns true if activity occured
+ * signalled fence value. Returns true if activity occurred
* on the ring, and the fence_queue should be waken up.
*/
static bool radeon_fence_activity(struct radeon_device *rdev, int ring)
@@ -262,7 +262,7 @@ static bool radeon_fence_activity(struct radeon_device *rdev, int ring)
* @work: delayed work item
*
* Checks for fence activity and if there is none probe
- * the hardware if a lockup occured.
+ * the hardware if a lockup occurred.
*/
static void radeon_fence_check_lockup(struct work_struct *work)
{
diff --git a/drivers/i2c/busses/i2c-bcm-kona.c b/drivers/i2c/busses/i2c-bcm-kona.c
index 9d8838bbd938..d4f287b31fd7 100644
--- a/drivers/i2c/busses/i2c-bcm-kona.c
+++ b/drivers/i2c/busses/i2c-bcm-kona.c
@@ -427,7 +427,7 @@ static int bcm_kona_i2c_write_fifo_single(struct bcm_kona_i2c_dev *dev,
return -EREMOTEIO;
}
- /* Check if a timeout occured */
+ /* Check if a timeout occurred */
if (!time_left) {
dev_err(dev->device, "completion timed out\n");
return -EREMOTEIO;
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index d30315ad85de..d959e1bbeb36 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -697,7 +697,7 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
return read_status;
}
-/* Returns 0 if the end of conversion interrupt occured or -ETIME otherwise */
+/* Returns 0 if the end of conversion interrupt occurred or -ETIME otherwise */
static int wait_conversion_complete_interrupt(struct ak8975_data *data)
{
int ret;
diff --git a/drivers/infiniband/hw/qedr/verbs.c b/drivers/infiniband/hw/qedr/verbs.c
index 33b4a0e6d3a8..80e8345a9954 100644
--- a/drivers/infiniband/hw/qedr/verbs.c
+++ b/drivers/infiniband/hw/qedr/verbs.c
@@ -1095,7 +1095,7 @@ int qedr_destroy_cq(struct ib_cq *ibcq, struct ib_udata *udata)
/* We don't want the IRQ handler to handle a non-existing CQ so we
* wait until all CNQ interrupts, if any, are received. This will always
* happen and will always happen very fast. If not, then a serious error
- * has occured. That is why we can use a long delay.
+ * has occurred. That is why we can use a long delay.
* We spin for a short time so we don’t lose time on context switching
* in case all the completions are handled in that span. Otherwise
* we sleep for a while and check again. Since the CNQ may be
diff --git a/drivers/misc/genwqe/card_base.c b/drivers/misc/genwqe/card_base.c
index 86bfa82723ff..df94c6af9550 100644
--- a/drivers/misc/genwqe/card_base.c
+++ b/drivers/misc/genwqe/card_base.c
@@ -922,7 +922,7 @@ static int genwqe_reload_bistream(struct genwqe_dev *cd)
*
* Condition for the health-thread to trigger:
* a) when a kthread_stop() request comes in or
- * b) a critical GFIR occured
+ * b) a critical GFIR occurred
*
* Informational GFIRs are checked and potentially printed in
* GENWQE_HEALTH_CHECK_INTERVAL seconds.
diff --git a/drivers/misc/genwqe/card_ddcb.c b/drivers/misc/genwqe/card_ddcb.c
index 969178573940..97de35231042 100644
--- a/drivers/misc/genwqe/card_ddcb.c
+++ b/drivers/misc/genwqe/card_ddcb.c
@@ -543,7 +543,7 @@ int __genwqe_wait_ddcb(struct genwqe_dev *cd, struct ddcb_requ *req)
return -EINVAL;
}
- /* Severe error occured. Driver is forced to stop operation */
+ /* Severe error occurred. Driver is forced to stop operation */
if (cd->card_state != GENWQE_CARD_USED) {
dev_err(&pci_dev->dev,
"[%s] err: DDCB#%d forced to stop (rc=%d)\n",
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index 872aad355dbe..b777bc3fdde2 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -2532,7 +2532,7 @@ static bool qp_wait_for_ready_queue(struct vmci_qp *qpair)
* VMCI_ERROR_QUEUEPAIR_NOSPACE if no space was available to enqueue
* data, VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the
* queue (as defined by the queue size), VMCI_ERROR_INVALID_ARGS, if
- * an error occured when accessing the buffer,
+ * an error occurred when accessing the buffer,
* VMCI_ERROR_QUEUEPAIR_NOTATTACHED, if the queue pair pages aren't
* available. Otherwise, the number of bytes written to the queue is
* returned. Updates the tail pointer of the produce queue.
@@ -2598,7 +2598,7 @@ static ssize_t qp_enqueue_locked(struct vmci_queue *produce_q,
* VMCI_ERROR_QUEUEPAIR_NODATA if no data was available to dequeue.
* VMCI_ERROR_INVALID_SIZE, if any queue pointer is outside the queue
* (as defined by the queue size).
- * VMCI_ERROR_INVALID_ARGS, if an error occured when accessing the buffer.
+ * VMCI_ERROR_INVALID_ARGS, if an error occurred when accessing the buffer.
* Otherwise the number of bytes dequeued is returned.
* Side effects:
* Updates the head pointer of the consume queue.
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index e3705db8e570..e8ceee6735db 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -1504,7 +1504,7 @@ static bool scrub_possible(struct ubi_device *ubi, struct ubi_wl_entry *e)
* @pnum: the physical eraseblock to schedule
* @force: don't read the block, assume bitflips happened and take action.
*
- * This function reads the given eraseblock and checks if bitflips occured.
+ * This function reads the given eraseblock and checks if bitflips occurred.
* In case of bitflips, the eraseblock is scheduled for scrubbing.
* If scrubbing is forced with @force, the eraseblock is not read,
* but scheduled for scrubbing right away.
diff --git a/drivers/nfc/microread/i2c.c b/drivers/nfc/microread/i2c.c
index 113b2e306e35..fd1ccb6cf7cc 100644
--- a/drivers/nfc/microread/i2c.c
+++ b/drivers/nfc/microread/i2c.c
@@ -40,7 +40,7 @@ struct microread_i2c_phy {
struct nfc_hci_dev *hdev;
int hard_fault; /*
- * < 0 if hardware error occured (e.g. i2c err)
+ * < 0 if hardware error occurred (e.g. i2c err)
* and prevents normal operation.
*/
};
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index a0dfb3f98d5a..1ecef0acaa50 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -171,7 +171,7 @@ struct pn544_i2c_phy {
int run_mode;
int hard_fault; /*
- * < 0 if hardware error occured (e.g. i2c err)
+ * < 0 if hardware error occurred (e.g. i2c err)
* and prevents normal operation.
*/
};
diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c
index 6d7861383806..3db5427753e9 100644
--- a/drivers/nfc/st21nfca/i2c.c
+++ b/drivers/nfc/st21nfca/i2c.c
@@ -66,7 +66,7 @@ struct st21nfca_i2c_phy {
int run_mode;
/*
- * < 0 if hardware error occured (e.g. i2c err)
+ * < 0 if hardware error occurred (e.g. i2c err)
* and prevents normal operation.
*/
int hard_fault;
diff --git a/drivers/power/supply/ab8500_fg.c b/drivers/power/supply/ab8500_fg.c
index 9dd99722667a..eb5c1ae68e44 100644
--- a/drivers/power/supply/ab8500_fg.c
+++ b/drivers/power/supply/ab8500_fg.c
@@ -2037,7 +2037,7 @@ static irqreturn_t ab8500_fg_cc_convend_handler(int irq, void *_di)
}
/**
- * ab8500_fg_batt_ovv_handler() - Battery OVV occured
+ * ab8500_fg_batt_ovv_handler() - Battery OVV occurred
* @irq: interrupt number
* @_di: pointer to the ab8500_fg structure
*
diff --git a/drivers/power/supply/smb347-charger.c b/drivers/power/supply/smb347-charger.c
index 8b95f7e8712f..fc3f90ef2bc9 100644
--- a/drivers/power/supply/smb347-charger.c
+++ b/drivers/power/supply/smb347-charger.c
@@ -1083,7 +1083,7 @@ static int smb347_get_charging_status(struct smb347_charger *smb,
} else {
/*
* in this case no charger error or termination
- * occured but charging is not in progress!!!
+ * occurred but charging is not in progress!!!
*/
status = POWER_SUPPLY_STATUS_NOT_CHARGING;
}
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index e80449f6ce15..a0e7b7a13947 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -4528,7 +4528,7 @@ static void iscsit_logout_post_handler_closesession(
/*
* Traditional iscsi/tcp will invoke this logic from TX thread
* context during session logout, so clear tx_thread_active and
- * sleep if iscsit_close_connection() has not already occured.
+ * sleep if iscsit_close_connection() has not already occurred.
*
* Since iser-target invokes this logic from it's own workqueue,
* always sleep waiting for RX/TX thread shutdown to complete
diff --git a/drivers/video/backlight/ktd253-backlight.c b/drivers/video/backlight/ktd253-backlight.c
index 327b4ee75254..f2c5527d02e0 100644
--- a/drivers/video/backlight/ktd253-backlight.c
+++ b/drivers/video/backlight/ktd253-backlight.c
@@ -53,7 +53,7 @@ static int ktd253_backlight_stepdown(struct ktd253_backlight *ktd253)
*
* Architectures do not always support ndelay() and we will get a few us
* instead. If we get to a critical time limit an interrupt has likely
- * occured in the low part of the loop and we need to restart from the
+ * occurred in the low part of the loop and we need to restart from the
* top so we have the backlight in a known state.
*/
u64 ns;
diff --git a/drivers/watchdog/davinci_wdt.c b/drivers/watchdog/davinci_wdt.c
index 5f2184bda7b2..36ba71113614 100644
--- a/drivers/watchdog/davinci_wdt.c
+++ b/drivers/watchdog/davinci_wdt.c
@@ -121,7 +121,7 @@ static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd)
u32 val;
struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
- /* if timeout has occured then return 0 */
+ /* if timeout has occurred then return 0 */
val = ioread32(davinci_wdt->base + WDTCR);
if (val & WDFLAG)
return 0;
--
2.50.1 (Apple Git-155)
^ permalink raw reply related
* Re: [PATCH v3 3/8] wifi: ath10k: snoc: support powering on the device via pwrseq
From: Dmitry Baryshkov @ 2026-04-18 19:38 UTC (permalink / raw)
To: Luca Weiss
Cc: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley, Bartosz Golaszewski, Marcel Holtmann,
Luiz Augusto von Dentz, Jeff Johnson, Bjorn Andersson,
Konrad Dybcio, Manivannan Sadhasivam, Vinod Koul,
Balakrishna Godavarthi, Matthias Kaehlcke, linux-arm-msm,
linux-kernel, devicetree, linux-bluetooth, linux-wireless, ath10k,
linux-pm, Krzysztof Kozlowski, Bartosz Golaszewski
In-Reply-To: <DHUHU7UIT487.139L3KIVRVREU@fairphone.com>
On Thu, Apr 16, 2026 at 12:06:09PM +0200, Luca Weiss wrote:
> Hi Dmitry,
>
> On Mon Jan 19, 2026 at 6:07 PM CET, Dmitry Baryshkov wrote:
> > The WCN39xx family of WiFi/BT chips incorporates a simple PMU, spreading
> > voltages over internal rails. Implement support for using powersequencer
> > for this family of ATH10k devices in addition to using regulators.
> >
> > Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
> > ---
> > drivers/net/wireless/ath/ath10k/snoc.c | 53 ++++++++++++++++++++++++++++++++--
> > drivers/net/wireless/ath/ath10k/snoc.h | 3 ++
> > 2 files changed, 53 insertions(+), 3 deletions(-)
> >
> > + ar_snoc->pwrseq = devm_pwrseq_get(&pdev->dev, "wlan");
> > + if (IS_ERR(ar_snoc->pwrseq)) {
> > + ret = PTR_ERR(ar_snoc->pwrseq);
> > + ar_snoc->pwrseq = NULL;
> > + if (ret != -EPROBE_DEFER)
> > + goto err_free_irq;
>
> I'm fairly sure this is now broken with CONFIG_POWER_SEQUENCING=n since
> then pwrseq_get() is returning ERR_PTR(-ENOSYS) which is not handled
> here.
>
> I'm observing my ath10k_snoc is now failing to probe "with error -38"
> which definitely seems to be related, but I haven't debugged it further
> yet.
Posted https://patch.msgid.link/20260418-ath10k-snoc-pwrseq-v1-1-832594ba3294@oss.qualcomm.com
--
With best wishes
Dmitry
^ permalink raw reply
* Re: [PATCH v2 1/3] MAINTAINERS: Move Peter De Schrijver to CREDITS
From: Aaro Koskinen @ 2026-04-18 20:07 UTC (permalink / raw)
To: Thierry Reding
Cc: Geert Uytterhoeven, linux-tegra, linux-arm-kernel, linux-pm,
linux-omap, linux-m68k, devicetree, linux-kernel, Paul Walmsley
In-Reply-To: <20260417131549.3154534-1-thierry.reding@kernel.org>
Hi,
On Fri, Apr 17, 2026 at 03:15:46PM +0200, Thierry Reding wrote:
> From: Thierry Reding <treding@nvidia.com>
>
> Peter sadly passed away a while back. Paul did a much better job at
> finding the right words to mourn this loss than I ever could, so I will
> leave this link here:
>
> https://lore.kernel.org/lkml/alpine.DEB.2.21.999.2407240345480.11116@utopia.booyaka.com/T/#u
>
> Co-developed-by: Paul Walmsley <pjw@kernel.org>
> Co-developed-by: Aaro Koskinen <aaro.koskinen@iki.fi>
> Co-developed-by: Geert Uytterhoeven <geert@linux-m68k.org>
> Signed-off-by: Thierry Reding <treding@nvidia.com>
Reviewed-by: Aaro Koskinen <aaro.koskinen@iki.fi>
A.
> ---
> Changes in v2:
> - add more missing entries
>
> CREDITS | 10 ++++++++++
> MAINTAINERS | 1 -
> 2 files changed, 10 insertions(+), 1 deletion(-)
>
> diff --git a/CREDITS b/CREDITS
> index 885fb05d8816..afd1f70b41cf 100644
> --- a/CREDITS
> +++ b/CREDITS
> @@ -3645,7 +3645,17 @@ D: Macintosh IDE Driver
>
> N: Peter De Schrijver
> E: stud11@cc4.kuleuven.ac.be
> +E: p2@mind.be
> +E: peter.de-schrijver@nokia.com
> +E: pdeschrijver@nvidia.com
> +E: p2@psychaos.be
> +D: Apollo Domain workstations
> +D: Ariadne and Hydra Amiga Ethernet drivers
> +D: IBM PS/2, Microchannel, and Token Ring support
> D: Mitsumi CD-ROM driver patches March version
> +D: TWL4030 power management and audio codec driver
> +D: OMAP power management
> +D: NVIDIA Tegra clock and BPMP drivers, among many other things
> S: Molenbaan 29
> S: B2240 Zandhoven
> S: Belgium
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ef978bfca514..ffe20d770249 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -26145,7 +26145,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/tegra/linux.git
> N: [^a-z]tegra
>
> TEGRA CLOCK DRIVER
> -M: Peter De Schrijver <pdeschrijver@nvidia.com>
> M: Prashant Gaikwad <pgaikwad@nvidia.com>
> S: Supported
> F: drivers/clk/tegra/
> --
> 2.52.0
>
>
^ permalink raw reply
* Re: [PATCH v2 00/19] tracepoint: Avoid double static_branch evaluation at guarded call sites
From: Steven Rostedt @ 2026-04-18 23:04 UTC (permalink / raw)
To: Vineeth Pillai (Google)
Cc: Peter Zijlstra, Dmitry Ilvokhin, Masami Hiramatsu,
Mathieu Desnoyers, Ingo Molnar, Jens Axboe, io-uring,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexei Starovoitov, Daniel Borkmann, Marcelo Ricardo Leitner,
Xin Long, Jon Maloy, Aaron Conole, Eelco Chaudron, Ilya Maximets,
netdev, bpf, linux-sctp, tipc-discussion, dev, Jiri Pirko,
Oded Gabbay, Koby Elbaz, dri-devel, Rafael J. Wysocki,
Viresh Kumar, Gautham R. Shenoy, Huang Rui, Mario Limonciello,
Len Brown, Srinivas Pandruvada, linux-pm, MyungJoo Ham,
Kyungmin Park, Chanwoo Choi, Christian König, Sumit Semwal,
linaro-mm-sig, Eddie James, Andrew Jeffery, Joel Stanley,
linux-fsi, David Airlie, Simona Vetter, Alex Deucher,
Danilo Krummrich, Matthew Brost, Philipp Stanner, Harry Wentland,
Leo Li, amd-gfx, Jiri Kosina, Benjamin Tissoires, linux-input,
Wolfram Sang, linux-i2c, Mark Brown, Michael Hennerich,
Nuno Sá, linux-spi, James E.J. Bottomley, Martin K. Petersen,
linux-scsi, Chris Mason, David Sterba, linux-btrfs,
Thomas Gleixner, Andrew Morton, SeongJae Park, linux-mm,
Borislav Petkov, Dave Hansen, x86, linux-trace-kernel,
linux-kernel
In-Reply-To: <20260323160052.17528-1-vineeth@bitbyteword.org>
On Mon, 23 Mar 2026 12:00:19 -0400
"Vineeth Pillai (Google)" <vineeth@bitbyteword.org> wrote:
> if (trace_foo_enabled() && cond)
> trace_call__foo(args); /* calls __do_trace_foo() directly */
Hi Vineeth,
Could you rebase this series on top of 7.1-rc1 when it comes out?
Several of these patches were accepted already. Obviously drop those.
They were the patches that added the feature, and any where the
maintainer acked the patch.
Now that the feature has been accepted, if you post the patch series
again after 7.1-rc1 with all the patches that haven't been accepted
yet, then the maintainers can simply take them directly. As the feature
is now accepted, there's no dependency on it, and they don't need to go
through the tracing tree.
Thanks,
-- Steve
^ permalink raw reply
* Re: [RFC PATCH 1/2] kernel/notifier: replace single-linked list with double-linked list for reverse traversal
From: Song Chen @ 2026-04-19 0:07 UTC (permalink / raw)
To: Petr Mladek
Cc: rafael, lenb, mturquette, sboyd, viresh.kumar, agk, snitzer,
mpatocka, bmarzins, song, yukuai, linan122, jason.wessel, danielt,
dianders, horms, davem, edumazet, kuba, pabeni, paulmck, frederic,
mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin, jpoimboe,
jikos, mbenes, joe.lawrence, rostedt, mhiramat, mark.rutland,
mathieu.desnoyers, linux-modules, linux-kernel,
linux-trace-kernel, linux-acpi, linux-clk, linux-pm,
live-patching, dm-devel, linux-raid, kgdb-bugreport, netdev
In-Reply-To: <aeC7ByGA5MHBcGQR@pathway.suse.cz>
Hi,
On 4/16/26 18:33, Petr Mladek wrote:
> On Wed 2026-04-15 15:01:37, chensong_2000@189.cn wrote:
>> From: Song Chen <chensong_2000@189.cn>
>>
>> The current notifier chain implementation uses a single-linked list
>> (struct notifier_block *next), which only supports forward traversal
>> in priority order. This makes it difficult to handle cleanup/teardown
>> scenarios that require notifiers to be called in reverse priority order.
>>
>> A concrete example is the ordering dependency between ftrace and
>> livepatch during module load/unload. see the detail here [1].
>>
>> This patch replaces the single-linked list in struct notifier_block
>> with a struct list_head, converting the notifier chain into a
>> doubly-linked list sorted in descending priority order. Based on
>> this, a new function notifier_call_chain_reverse() is introduced,
>> which traverses the chain in reverse (ascending priority order).
>> The corresponding blocking_notifier_call_chain_reverse() is also
>> added as the locking wrapper for blocking notifier chains.
>>
>> The internal notifier_call_chain_robust() is updated to use
>> notifier_call_chain_reverse() for rollback: on error, it records
>> the failing notifier (last_nb) and the count of successfully called
>> notifiers (nr), then rolls back exactly those nr-1 notifiers in
>> reverse order starting from last_nb's predecessor, without needing
>> to know the total length of the chain.
>>
>> With this change, subsystems with symmetric setup/teardown ordering
>> requirements can register a single notifier_block with one priority
>> value, and rely on blocking_notifier_call_chain() for forward
>> traversal and blocking_notifier_call_chain_reverse() for reverse
>> traversal, without needing hard-coded call sequences or separate
>> notifier registrations for each direction.
>>
>> [1]:https://lore.kernel.org/all
>> /alpine.LNX.2.00.1602172216491.22700@cbobk.fhfr.pm/
>>
>> --- a/include/linux/notifier.h
>> +++ b/include/linux/notifier.h
>> @@ -53,41 +53,41 @@ typedef int (*notifier_fn_t)(struct notifier_block *nb,
> [...]
>> struct notifier_block {
>> notifier_fn_t notifier_call;
>> - struct notifier_block __rcu *next;
>> + struct list_head __rcu entry;
>> int priority;
>> };
> [...]
>> #define ATOMIC_INIT_NOTIFIER_HEAD(name) do { \
>> spin_lock_init(&(name)->lock); \
>> - (name)->head = NULL; \
>> + INIT_LIST_HEAD(&(name)->head); \
>
> I would expect the RCU variant here, aka INIT_LIST_HEAD_RCU().
I'm not familiar with list rcu, but i will look into it and give it a try.
>
>> --- a/kernel/notifier.c
>> +++ b/kernel/notifier.c
>> @@ -14,39 +14,47 @@
>> * are layered on top of these, with appropriate locking added.
>> */
>>
>> -static int notifier_chain_register(struct notifier_block **nl,
>> +static int notifier_chain_register(struct list_head *nl,
>> struct notifier_block *n,
>> bool unique_priority)
>> {
>> - while ((*nl) != NULL) {
>> - if (unlikely((*nl) == n)) {
>> + struct notifier_block *cur;
>> +
>> + list_for_each_entry(cur, nl, entry) {
>> + if (unlikely(cur == n)) {
>> WARN(1, "notifier callback %ps already registered",
>> n->notifier_call);
>> return -EEXIST;
>> }
>> - if (n->priority > (*nl)->priority)
>> - break;
>> - if (n->priority == (*nl)->priority && unique_priority)
>> +
>> + if (n->priority == cur->priority && unique_priority)
>> return -EBUSY;
>> - nl = &((*nl)->next);
>> +
>> + if (n->priority > cur->priority) {
>> + list_add_tail(&n->entry, &cur->entry);
>> + goto out;
>> + }
>> }
>> - n->next = *nl;
>> - rcu_assign_pointer(*nl, n);
>> +
>> + list_add_tail(&n->entry, nl);
>
> I would expect list_add_tail_rcu() here.
>
>> @@ -59,25 +67,25 @@ static int notifier_chain_unregister(struct notifier_block **nl,
>> * value of this parameter is -1.
>> * @nr_calls: Records the number of notifications sent. Don't care
>> * value of this field is NULL.
>> + * @last_nb: Records the last called notifier block for rolling back
>> * Return: notifier_call_chain returns the value returned by the
>> * last notifier function called.
>> */
>> -static int notifier_call_chain(struct notifier_block **nl,
>> +static int notifier_call_chain(struct list_head *nl,
>> unsigned long val, void *v,
>> - int nr_to_call, int *nr_calls)
>> + int nr_to_call, int *nr_calls,
>> + struct notifier_block **last_nb)
>> {
>> int ret = NOTIFY_DONE;
>> - struct notifier_block *nb, *next_nb;
>> -
>> - nb = rcu_dereference_raw(*nl);
>> + struct notifier_block *nb;
>>
>> - while (nb && nr_to_call) {
>> - next_nb = rcu_dereference_raw(nb->next);
>> + if (!nr_to_call)
>> + return ret;
>>
>> + list_for_each_entry(nb, nl, entry) {
>
> I would expect the RCU variant here, aka list_for_each_rcu()
>
> These are just two random examples which I found by a quick look.
>
> I guess that the notifier API is very old and it does not use all
> the RCU API features which allow to track safety when
> CONFIG_PROVE_RCU and CONFIG_PROVE_RCU_LIST are enabled.
>
> It actually might be worth to audit the code and make it right.
>
>> #ifdef CONFIG_DEBUG_NOTIFIERS
>> if (unlikely(!func_ptr_is_kernel_text(nb->notifier_call))) {
>> WARN(1, "Invalid notifier called!");
>> - nb = next_nb;
>> continue;
>> }
>> #endif
>
> That said, I am not sure if the ftrace/livepatching handlers are
> the right motivation for this. Especially when I see the
> complexity of the 2nd patch [*]
>
> After thinking more about it. I am not even sure that the ftrace and
> livepatching callbacks are good candidates for generic notifiers.
> They are too special. It is not only about ordering them against
> each other. But it is also about ordering them against other
> notifiers. The ftrace/livepatching callbacks must be the first/last
> during module load/release.
>
> [*] The 2nd patch is not archived by lore for some reason.
> I have found only a review but it gives a good picture, see
> https://lore.kernel.org/all/1191caf5-6a61-4622-a15e-854d3701f4fc@suse.com/
>
> Best Regards,
> Petr
>
Thanks.
BR
Song
^ permalink raw reply
* Re: [RFC PATCH 1/2] kernel/notifier: replace single-linked list with double-linked list for reverse traversal
From: Song Chen @ 2026-04-19 0:21 UTC (permalink / raw)
To: David Laight
Cc: rafael, lenb, mturquette, sboyd, viresh.kumar, agk, snitzer,
mpatocka, bmarzins, song, yukuai, linan122, jason.wessel, danielt,
dianders, horms, davem, edumazet, kuba, pabeni, paulmck, frederic,
mcgrof, petr.pavlu, da.gomez, samitolvanen, atomlin, jpoimboe,
jikos, mbenes, pmladek, joe.lawrence, rostedt, mhiramat,
mark.rutland, mathieu.desnoyers, linux-modules, linux-kernel,
linux-trace-kernel, linux-acpi, linux-clk, linux-pm,
live-patching, dm-devel, linux-raid, kgdb-bugreport, netdev
In-Reply-To: <20260416133004.07bd2886@pumpkin>
Hi,
On 4/16/26 20:30, David Laight wrote:
> On Wed, 15 Apr 2026 15:01:37 +0800
> chensong_2000@189.cn wrote:
>
>> From: Song Chen <chensong_2000@189.cn>
>>
>> The current notifier chain implementation uses a single-linked list
>> (struct notifier_block *next), which only supports forward traversal
>> in priority order. This makes it difficult to handle cleanup/teardown
>> scenarios that require notifiers to be called in reverse priority order.
>
> If it is only cleanup/teardown then the list can be order-reversed
> as part of that process at the same time as the list is deleted.
>
> David
>
>
>
Sorry, i don't follow, the notifiers in the list are deleted when
calling notifier_chain_unregister, other than that, they are traversed
forward and backward.
Song
^ permalink raw reply
* Re: [PATCH] cpufreq: clean up dead dependencies on X86 in Kconfig
From: Mario Limonciello @ 2026-04-19 4:09 UTC (permalink / raw)
To: Julian Braha, rafael, viresh.kumar
Cc: gautham.shenoy, Perry.Yuan, skhan, ray.huang, linux-pm,
linux-kernel
In-Reply-To: <20260417230652.305414-1-julianbraha@gmail.com>
On 4/17/26 18:06, Julian Braha wrote:
> The Kconfig in the parent directory already has an 'if X86'
> condition wrapping the inclusion of this file, meaning that each of the
> individual 'depends on' statements in this file is a duplicate dependency
> (dead code).
>
> I propose leaving the outer 'if X86...endif' and removing
> the individual 'depends on X86' statement from each option.
>
> This dead code was found by kconfirm, a static analysis tool for Kconfig.
>
> Signed-off-by: Julian Braha <julianbraha@gmail.com>
Reviewed-by: Mario Limonciello (AMD) <superm1@kernel.org>
> ---
> drivers/cpufreq/Kconfig.x86 | 5 ++---
> 1 file changed, 2 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
> index 027e6ea2e038..9afceb1143df 100644
> --- a/drivers/cpufreq/Kconfig.x86
> +++ b/drivers/cpufreq/Kconfig.x86
> @@ -5,7 +5,6 @@
>
> config X86_INTEL_PSTATE
> bool "Intel P state control"
> - depends on X86
> select ACPI_PROCESSOR if ACPI
> select ACPI_CPPC_LIB if X86_64 && ACPI && SCHED_MC_PRIO
> select CPU_FREQ_GOV_PERFORMANCE
> @@ -36,7 +35,7 @@ config X86_PCC_CPUFREQ
>
> config X86_AMD_PSTATE
> bool "AMD Processor P-State driver"
> - depends on X86 && ACPI
> + depends on ACPI
> select ACPI_PROCESSOR
> select ACPI_CPPC_LIB if X86_64
> select CPU_FREQ_GOV_SCHEDUTIL if SMP
> @@ -84,7 +83,7 @@ config X86_AMD_PSTATE_DYNAMIC_EPP
>
> config X86_AMD_PSTATE_UT
> tristate "selftest for AMD Processor P-State driver"
> - depends on X86 && ACPI_PROCESSOR
> + depends on ACPI_PROCESSOR
> depends on X86_AMD_PSTATE
> default n
> help
^ permalink raw reply
* [PATCH] [PATCH] PM: docs: Add comprehensive wakeup_count documentation
From: chenheyun @ 2026-04-19 7:23 UTC (permalink / raw)
To: rafael, pavel; +Cc: linux-pm, linux-api, linux-kernel, chenheyun
The current Documentation/power/wakeup-count.rst is empty and lacks
description of the race-free suspend mechanism, sysfs ABI semantics,
blocking behavior, and standard userspace usage.
Add complete documentation for /sys/power/wakeup_count, including
overview, interface semantics, usage example, and related interfaces.
Also update Documentation/power/index.rst to include the new document.
Signed-off-by: chenheyun <chen_heyun@163.com>
---
Documentation/power/index.rst | 1 +
Documentation/power/wakeup-count.rst | 63 ++++++++++++++++++++++++++++
2 files changed, 64 insertions(+)
create mode 100644 Documentation/power/wakeup-count.rst
diff --git a/Documentation/power/index.rst b/Documentation/power/index.rst
index b4581e4ae785..901268049d7c 100644
--- a/Documentation/power/index.rst
+++ b/Documentation/power/index.rst
@@ -27,6 +27,7 @@ Power Management
swsusp
video
tricks
+ wakeup-count
userland-swsusp
diff --git a/Documentation/power/wakeup-count.rst b/Documentation/power/wakeup-count.rst
new file mode 100644
index 000000000000..5f3a1ca654ce
--- /dev/null
+++ b/Documentation/power/wakeup-count.rst
@@ -0,0 +1,63 @@
+.. SPDX-License-Identifier: GPL-2.0
+.. Copyright (C) 2025 The Linux Foundation
+
+The wakeup_count mechanism for race-free suspend
+================================================
+
+Overview
+--------
+
+The ``/sys/power/wakeup_count`` sysfs interface provides a stable userspace
+mechanism to perform race-free system suspend transitions. It eliminates the
+well-known race condition between suspend permission check and actual system
+suspend entry.
+
+Userspace may use it in a standard three-step sequence:
+
+1. Read the current global wakeup event counter. The read operation blocks
+ until all ongoing wakeup event processing is finished, returning a stable value.
+2. Perform necessary suspend preparation steps in userspace.
+3. Write the previously-read counter value back to the interface.
+ The write operation will only succeed if no new wakeup events have occurred
+ since the read.
+
+Only after a successful write may userspace safely trigger system suspend.
+
+Interface semantics
+-------------------
+
+``/sys/power/wakeup_count``
+
+**Read**
+ Returns the global monotonically-increasing wakeup event counter.
+ This call blocks until there are no wakeup events under active processing
+ inside the kernel. If interrupted by a signal, it returns -EINTR.
+
+**Write**
+ Accepts the counter value obtained from a prior read.
+ The write succeeds only if the kernel's current counter exactly matches
+ the written value. Mismatch indicates new wakeup events arrived during
+ userspace preparation, and suspend must be aborted.
+
+Standard userspace usage example
+--------------------------------
+
+.. code-block:: shell
+
+ count=$(cat /sys/power/wakeup_count)
+ do_suspend_preparation
+ echo "$count" > /sys/power/wakeup_count && echo mem > /sys/power/state
+
+Blocking behavior
+-----------------
+
+The blocking read ensures that userspace never observes an inconsistent state
+where wakeup events are still being handled within the kernel. This stability
+is the core guarantee of the interface.
+
+Related kernel interfaces
+-------------------------
+
+- ``/sys/power/state``: System suspend state control interface.
+- ``/sys/kernel/debug/wakeup_sources``: Per-device wakeup source statistics.
+- ``Documentation/power/wakeup-events.rst``: General wakeup event framework.
\ No newline at end of file
--
2.25.1
^ permalink raw reply related
* Re: [PATCH v2 00/19] tracepoint: Avoid double static_branch evaluation at guarded call sites
From: Vineeth Remanan Pillai @ 2026-04-19 13:14 UTC (permalink / raw)
To: Steven Rostedt
Cc: Peter Zijlstra, Dmitry Ilvokhin, Masami Hiramatsu,
Mathieu Desnoyers, Ingo Molnar, Jens Axboe, io-uring,
David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
Alexei Starovoitov, Daniel Borkmann, Marcelo Ricardo Leitner,
Xin Long, Jon Maloy, Aaron Conole, Eelco Chaudron, Ilya Maximets,
netdev, bpf, linux-sctp, tipc-discussion, dev, Jiri Pirko,
Oded Gabbay, Koby Elbaz, dri-devel, Rafael J. Wysocki,
Viresh Kumar, Gautham R. Shenoy, Huang Rui, Mario Limonciello,
Len Brown, Srinivas Pandruvada, linux-pm, MyungJoo Ham,
Kyungmin Park, Chanwoo Choi, Christian König, Sumit Semwal,
linaro-mm-sig, Eddie James, Andrew Jeffery, Joel Stanley,
linux-fsi, David Airlie, Simona Vetter, Alex Deucher,
Danilo Krummrich, Matthew Brost, Philipp Stanner, Harry Wentland,
Leo Li, amd-gfx, Jiri Kosina, Benjamin Tissoires, linux-input,
Wolfram Sang, linux-i2c, Mark Brown, Michael Hennerich,
Nuno Sá, linux-spi, James E.J. Bottomley, Martin K. Petersen,
linux-scsi, Chris Mason, David Sterba, linux-btrfs,
Thomas Gleixner, Andrew Morton, SeongJae Park, linux-mm,
Borislav Petkov, Dave Hansen, x86, linux-trace-kernel,
linux-kernel
In-Reply-To: <20260418190456.631df6f3@fedora>
On Sat, Apr 18, 2026 at 7:05 PM Steven Rostedt <rostedt@goodmis.org> wrote:
>
> On Mon, 23 Mar 2026 12:00:19 -0400
> "Vineeth Pillai (Google)" <vineeth@bitbyteword.org> wrote:
>
> > if (trace_foo_enabled() && cond)
> > trace_call__foo(args); /* calls __do_trace_foo() directly */
>
> Hi Vineeth,
>
> Could you rebase this series on top of 7.1-rc1 when it comes out?
> Several of these patches were accepted already. Obviously drop those.
> They were the patches that added the feature, and any where the
> maintainer acked the patch.
>
> Now that the feature has been accepted, if you post the patch series
> again after 7.1-rc1 with all the patches that haven't been accepted
> yet, then the maintainers can simply take them directly. As the feature
> is now accepted, there's no dependency on it, and they don't need to go
> through the tracing tree.
>
Sure, will do. Thanks for merging this feature.
Thanks,
Vineeth
^ permalink raw reply
* [PATCH v3 0/2] governor: Fix races and stale baseline on prev_cpu_nice
From: Zhongqiu Han @ 2026-04-19 13:26 UTC (permalink / raw)
To: rafael, viresh.kumar
Cc: venkatesh.pallipadi, davej, trenn, linux-pm, linux-kernel,
zhongqiu.han
Patch 1 fixes two baseline-consistency issues in the DBS governor
framework.
gov_update_cpu_data() writes prev_cpu_idle and prev_cpu_nice while
holding only attr_set->update_lock, whereas dbs_update() reads and
writes the same fields while holding only policy_dbs->update_mutex.
Because these are independent locks, the two paths are not mutually
exclusive. The fix acquires policy_dbs->update_mutex inside
gov_update_cpu_data() for each policy.
Additionally, cpufreq_dbs_governor_start() reads io_is_busy before
acquiring policy_dbs->update_mutex. A concurrent io_is_busy_store()
can update io_is_busy and call gov_update_cpu_data(), which writes
prev_cpu_idle with the new value under the mutex.
cpufreq_dbs_governor_start() then overwrites prev_cpu_idle with the
stale value. The fix reads io_is_busy inside the mutex.
Patch 2 fixes a stale-baseline race on prev_cpu_nice when
ignore_nice_load is enabled via sysfs. There is a race window
between setting ignore_nice_load and gov_update_cpu_data() acquiring
update_mutex: a concurrent dbs_update() can see the new ignore_nice_load
value but read a stale prev_cpu_nice, producing an inflated idle_time
for that sample.
The fix unconditionally advances prev_cpu_nice on every dbs_update()
call. With prev_cpu_nice always reflecting the most recent sample,
enabling ignore_nice_load can never produce a stale-baseline spike.
To keep prev_cpu_nice handling consistent, gov_update_cpu_data()
resets prev_cpu_nice unconditionally alongside prev_cpu_idle, and
cpufreq_dbs_governor_start() initializes prev_cpu_nice unconditionally.
v3:
- Update linux-next base
- Fix two additional issues found during sashiko.dev review:
- Patch 1: move io_busy read inside policy_dbs->update_mutex in
cpufreq_dbs_governor_start() to close a TOCTOU window against
concurrent io_is_busy_store().
- Patch 2: restore unconditional prev_cpu_nice reset in
gov_update_cpu_data() to keep both baselines consistent when
io_is_busy changes with ignore_nice_load enabled; update comment.
- Patch 2: keep gov_update_cpu_data() in ignore_nice_load_store() to
prevent a stale-baseline spike in the governor-start window (when
ignore_nice_load is set before the first dbs_update() call); only
cpufreq_governor.c is modified. Update commit message and add one
more fixes tag '326c86deaed54a ("[CPUFREQ] Remove unneeded locks").'
- Update the commit messages.
- Link to v2: https://lore.kernel.org/all/20260409111407.9775-1-zhongqiu.han@oss.qualcomm.com/
- Sashiko v2 comments: https://sashiko.dev/#/patchset/20260409111407.9775-1-zhongqiu.han%40oss.qualcomm.com
v2:
- Update linux-next base
- Based on v1 review, patch 1 is updated to add the missing
protection around cpufreq_dbs_governor_start(), and patch 2/2 is added.
- Link to v1: https://lore.kernel.org/all/20260406110113.3475920-1-zhongqiu.han@oss.qualcomm.com/
Zhongqiu Han (2):
cpufreq: governor: Fix data races on per-CPU idle/nice baselines
cpufreq: governor: Fix stale prev_cpu_nice spike when enabling
ignore_nice_load
drivers/cpufreq/cpufreq_governor.c | 42 ++++++++++++++++++++----------
1 file changed, 28 insertions(+), 14 deletions(-)
base-commit: c7275b05bc428c7373d97aa2da02d3a7fa6b9f66
--
2.43.0
^ permalink raw reply
* [PATCH v3 1/2] cpufreq: governor: Fix data races on per-CPU idle/nice baselines
From: Zhongqiu Han @ 2026-04-19 13:26 UTC (permalink / raw)
To: rafael, viresh.kumar
Cc: venkatesh.pallipadi, davej, trenn, linux-pm, linux-kernel,
zhongqiu.han
In-Reply-To: <20260419132655.3800673-1-zhongqiu.han@oss.qualcomm.com>
gov_update_cpu_data() resets per-CPU prev_cpu_idle for every CPU in the
governed domain, and conditionally resets prev_cpu_nice when
ignore_nice_load is set. It is called from sysfs store callbacks
(e.g. ignore_nice_load_store) which run under attr_set->update_lock,
held by the surrounding governor_store().
Concurrently, dbs_work_handler() calls gov->gov_dbs_update() (which calls
dbs_update()) under policy_dbs->update_mutex. dbs_update() both reads and
writes the same prev_cpu_idle / prev_cpu_nice fields. The potential race
path is:
Path A (sysfs write, holds attr_set->update_lock only):
governor_store()
mutex_lock(&attr_set->update_lock)
ignore_nice_load_store()
dbs_data->ignore_nice_load = input
gov_update_cpu_data(dbs_data)
list_for_each_entry(policy_dbs, ...)
for_each_cpu(j, ...)
j_cdbs->prev_cpu_idle = get_cpu_idle_time(...) /* write */
j_cdbs->prev_cpu_nice = kcpustat_field(...) /* write */
mutex_unlock(&attr_set->update_lock)
Path B (work queue, holds policy_dbs->update_mutex only):
dbs_work_handler()
mutex_lock(&policy_dbs->update_mutex)
gov->gov_dbs_update(policy)
dbs_update()
for_each_cpu(j, policy->cpus)
idle_time = cur - j_cdbs->prev_cpu_idle /* read */
j_cdbs->prev_cpu_idle = cur_idle_time /* write */
idle_time += cur_nice - j_cdbs->prev_cpu_nice /* read */
j_cdbs->prev_cpu_nice = cur_nice /* write */
mutex_unlock(&policy_dbs->update_mutex)
Because attr_set->update_lock and policy_dbs->update_mutex are two
completely independent locks, the two paths are not mutually exclusive.
This results in a data race on cpu_dbs_info.prev_cpu_idle and
cpu_dbs_info.prev_cpu_nice.
Fix this by also acquiring policy_dbs->update_mutex in
gov_update_cpu_data() for each policy, so that path A participates in
the mutual exclusion already established by dbs_work_handler(). Also
update the function comment to accurately reflect the two-level locking
contract.
Additionally, cpufreq_dbs_governor_start() initializes prev_cpu_idle
using io_busy read from dbs_data->io_is_busy without holding
policy_dbs->update_mutex. A concurrent io_is_busy_store() can update
io_is_busy and call gov_update_cpu_data(), which writes prev_cpu_idle
with the new value under the mutex. cpufreq_dbs_governor_start() then
overwrites prev_cpu_idle with the stale io_busy value, leaving the
baseline inconsistent with the tunable. Fix this by reading io_busy
inside the mutex.
The root of this race dates back to the original ondemand/conservative
governors. Before commit ee88415caf73 ("[CPUFREQ] Cleanup locking in
conservative governor") and commit 5a75c82828e7 ("[CPUFREQ] Cleanup
locking in ondemand governor"), all accesses to prev_cpu_idle and
prev_cpu_nice in cpufreq_governor_dbs() (path X), store_ignore_nice_load()
/io_is_busy_store() (path Y), and do_dbs_timer() (path Z) were serialised
by the same dbs_mutex, so no race existed. Those two commits switched
do_dbs_timer() from dbs_mutex to a per-policy/per-cpu timer_mutex to
reduce lock contention, but left path Y (store) still holding dbs_mutex.
As a result, path Y (store) and path Z (do_dbs_timer) no longer shared a
common lock, introducing a potential race on prev_cpu_idle/prev_cpu_nice
between path Y (store) and dbs_check_cpu().
Commit 326c86deaed54a ("[CPUFREQ] Remove unneeded locks") then removed
dbs_mutex from store_ignore_nice_load()/io_is_busy_store() entirely,
introducing an additional potential race between path Y (now lockless)
and cpufreq_governor_dbs() (path X, still holding dbs_mutex), while the
race between path Y and path Z remained.
Fixes: ee88415caf736b ("[CPUFREQ] Cleanup locking in conservative governor")
Fixes: 5a75c82828e7c0 ("[CPUFREQ] Cleanup locking in ondemand governor")
Fixes: 326c86deaed54a ("[CPUFREQ] Remove unneeded locks")
Signed-off-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
---
drivers/cpufreq/cpufreq_governor.c | 9 +++++++--
1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index 86f35e451914..fc6f705c5a9c 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -90,7 +90,8 @@ EXPORT_SYMBOL_GPL(sampling_rate_store);
* (that may be a single policy or a bunch of them if governor tunables are
* system-wide).
*
- * Call under the @dbs_data mutex.
+ * Call under the @dbs_data->attr_set.update_lock. The per-policy
+ * update_mutex is acquired and released internally for each policy.
*/
void gov_update_cpu_data(struct dbs_data *dbs_data)
{
@@ -99,6 +100,7 @@ void gov_update_cpu_data(struct dbs_data *dbs_data)
list_for_each_entry(policy_dbs, &dbs_data->attr_set.policy_list, list) {
unsigned int j;
+ mutex_lock(&policy_dbs->update_mutex);
for_each_cpu(j, policy_dbs->policy->cpus) {
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
@@ -107,6 +109,7 @@ void gov_update_cpu_data(struct dbs_data *dbs_data)
if (dbs_data->ignore_nice_load)
j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
}
+ mutex_unlock(&policy_dbs->update_mutex);
}
}
EXPORT_SYMBOL_GPL(gov_update_cpu_data);
@@ -527,8 +530,9 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
sampling_rate = dbs_data->sampling_rate;
ignore_nice = dbs_data->ignore_nice_load;
- io_busy = dbs_data->io_is_busy;
+ mutex_lock(&policy_dbs->update_mutex);
+ io_busy = dbs_data->io_is_busy;
for_each_cpu(j, policy->cpus) {
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
@@ -541,6 +545,7 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
if (ignore_nice)
j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
}
+ mutex_unlock(&policy_dbs->update_mutex);
gov->start(policy);
--
2.43.0
^ permalink raw reply related
* [PATCH v3 2/2] cpufreq: governor: Fix stale prev_cpu_nice spike when enabling ignore_nice_load
From: Zhongqiu Han @ 2026-04-19 13:26 UTC (permalink / raw)
To: rafael, viresh.kumar
Cc: venkatesh.pallipadi, davej, trenn, linux-pm, linux-kernel,
zhongqiu.han
In-Reply-To: <20260419132655.3800673-1-zhongqiu.han@oss.qualcomm.com>
When ignore_nice_load is toggled from 0 to 1 via sysfs, dbs_update() may
run concurrently and observe the new tunable value while prev_cpu_nice
still holds a stale baseline, producing a spurious massive idle_time that
results in an incorrect CPU load value.
The race can be illustrated with two concurrent paths:
Path A (sysfs write, holds attr_set->update_lock):
governor_store()
mutex_lock(&attr_set->update_lock)
ignore_nice_load_store()
dbs_data->ignore_nice_load = 1 /* (A1) */
gov_update_cpu_data(dbs_data)
mutex_lock(&policy_dbs->update_mutex) /* (A2) */
j_cdbs->prev_cpu_nice = kcpustat_field(...)
mutex_unlock(&policy_dbs->update_mutex)
mutex_unlock(&attr_set->update_lock)
Path B (work queue, wins the race between A1 and A2):
dbs_work_handler()
mutex_lock(&policy_dbs->update_mutex) /* acquired before A2 */
dbs_update()
ignore_nice = dbs_data->ignore_nice_load /* sees new value: 1 */
cur_nice = kcpustat_field(...)
idle_time += div_u64(cur_nice - j_cdbs->prev_cpu_nice, ..) /* stale */
j_cdbs->prev_cpu_nice = cur_nice
mutex_unlock(&policy_dbs->update_mutex)
Fix this by unconditionally sampling cur_nice and advancing prev_cpu_nice
in dbs_update() on every call, regardless of ignore_nice. With
prev_cpu_nice always reflecting the most recent sample, enabling
ignore_nice_load can never produce a stale-baseline spike: the delta will
always be the nice time accumulated in the last sampling interval, not
since boot. The additional kcpustat_field() call per CPU per sample is
negligible given that the sampling path already reads idle and load
accounting.
To keep prev_cpu_nice handling consistent with the always-tracking
semantics introduced above:
- gov_update_cpu_data() unconditionally resets prev_cpu_nice alongside
prev_cpu_idle, so both baselines share the same timestamp when
io_is_busy changes. This prevents an interval mismatch between
idle_time and nice_delta on the next dbs_update() when
ignore_nice_load is enabled.
- cpufreq_dbs_governor_start() unconditionally initializes prev_cpu_nice
so the baseline is always valid from the first dbs_update() call;
remove the ignore_nice guard and the now-unused ignore_nice variable.
Fixes: ee88415caf736b ("[CPUFREQ] Cleanup locking in conservative governor")
Fixes: 5a75c82828e7c0 ("[CPUFREQ] Cleanup locking in ondemand governor")
Fixes: 326c86deaed54a ("[CPUFREQ] Remove unneeded locks")
Signed-off-by: Zhongqiu Han <zhongqiu.han@oss.qualcomm.com>
---
drivers/cpufreq/cpufreq_governor.c | 33 +++++++++++++++++++-----------
1 file changed, 21 insertions(+), 12 deletions(-)
diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c
index fc6f705c5a9c..8a85bd32defe 100644
--- a/drivers/cpufreq/cpufreq_governor.c
+++ b/drivers/cpufreq/cpufreq_governor.c
@@ -92,6 +92,12 @@ EXPORT_SYMBOL_GPL(sampling_rate_store);
*
* Call under the @dbs_data->attr_set.update_lock. The per-policy
* update_mutex is acquired and released internally for each policy.
+ *
+ * Note: prev_cpu_nice is reset here unconditionally alongside prev_cpu_idle.
+ * When io_is_busy changes, both baselines must be advanced to the same
+ * timestamp so that the next dbs_update() computes idle_time and nice_delta
+ * over the same interval, preventing an artificially inflated idle_time when
+ * ignore_nice_load is enabled.
*/
void gov_update_cpu_data(struct dbs_data *dbs_data)
{
@@ -106,8 +112,7 @@ void gov_update_cpu_data(struct dbs_data *dbs_data)
j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, &j_cdbs->prev_update_time,
dbs_data->io_is_busy);
- if (dbs_data->ignore_nice_load)
- j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
+ j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
}
mutex_unlock(&policy_dbs->update_mutex);
}
@@ -121,6 +126,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
unsigned int ignore_nice = dbs_data->ignore_nice_load;
unsigned int max_load = 0, idle_periods = UINT_MAX;
unsigned int sampling_rate, io_busy, j;
+ u64 cur_nice;
/*
* Sometimes governors may use an additional multiplier to increase
@@ -167,12 +173,18 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
j_cdbs->prev_cpu_idle = cur_idle_time;
- if (ignore_nice) {
- u64 cur_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
-
+ /*
+ * Always sample cur_nice and advance prev_cpu_nice, regardless
+ * of ignore_nice. This keeps prev_cpu_nice current so that
+ * enabling ignore_nice_load via sysfs never produces a
+ * stale-baseline spike (the delta will be at most one sampling
+ * interval of accumulated nice time, not since boot).
+ */
+ cur_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
+ if (ignore_nice)
idle_time += div_u64(cur_nice - j_cdbs->prev_cpu_nice, NSEC_PER_USEC);
- j_cdbs->prev_cpu_nice = cur_nice;
- }
+
+ j_cdbs->prev_cpu_nice = cur_nice;
if (unlikely(!time_elapsed)) {
/*
@@ -519,7 +531,7 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
struct dbs_governor *gov = dbs_governor_of(policy);
struct policy_dbs_info *policy_dbs = policy->governor_data;
struct dbs_data *dbs_data = policy_dbs->dbs_data;
- unsigned int sampling_rate, ignore_nice, j;
+ unsigned int sampling_rate, j;
unsigned int io_busy;
if (!policy->cur)
@@ -529,7 +541,6 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
policy_dbs->rate_mult = 1;
sampling_rate = dbs_data->sampling_rate;
- ignore_nice = dbs_data->ignore_nice_load;
mutex_lock(&policy_dbs->update_mutex);
io_busy = dbs_data->io_is_busy;
@@ -541,9 +552,7 @@ int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
* Make the first invocation of dbs_update() compute the load.
*/
j_cdbs->prev_load = 0;
-
- if (ignore_nice)
- j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
+ j_cdbs->prev_cpu_nice = kcpustat_field(&kcpustat_cpu(j), CPUTIME_NICE, j);
}
mutex_unlock(&policy_dbs->update_mutex);
--
2.43.0
^ permalink raw reply related
* [PATCH v1 00/14] Support cooling device with ID in the OF
From: Daniel Lezcano @ 2026-04-19 18:21 UTC (permalink / raw)
To: rafael
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon
A cooling device can be a single cooling device or a cooling device
controller with multiple cooling devices attached to it.
The thermal framework builds a connection between a cooling device and
a thermal zone when there is a trip point to be mitigated by the
cooling device. In the Linux kernel thermal semantic, the action of
connecting the cooling device and the thermal zone is called a
binding.
The description of the aforementioned connection depends on the
firmware definition and in our case it is through the device tree. The
cooling map describes this connection.
How is it done ?
For a single cooling device, the DT describes:
* A cooling device:
mycooling_device {
...
};
* A cooling map in a thermal zone
mythermal_zone {
...
cooling-maps {
map0 {
...
cooling-device = <&mycooling_device min max>;
...
};
}
...
};
For a cooling device controller with multiple cooling devices
attached, the DT describes:
* A cooling device controller:
mycooling_device_ctrl {
mycooling_device1 {
...
};
mycooling_device2 {
...
};
...
mycooling_deviceN {
...
};
};
* A cooling map in a thermal zone
mythermal_zone {
...
cooling-maps {
map0 {
...
cooling-device = <&mycooling_device1 min max>;
...
};
}
...
};
When the cooling device "mycooling_device" is registered, then the
binding function will browse all the cooling maps and matches the node
device pointer to do the association (the pĥandle in the cooling map
vs the cooling device node).
That is how the connection between the cooling device and the thermal
zone is done.
DT maintainers consider the above description with child nodes is
incorrect if a child node doesn't have its own bindings as explained
in the documentation [1].
Gaurav Kohli posted a series to support the QMI TMD (Qualcomm
Messaging Interface based Thermal Mitigation Devices) [2]. This device
is a dedicated, centralized cooling device controller managing a set
of cooling devices.
Because of the above restrictions with child nodes there is no DT
bindings allowing to do the connection between the cooling device
inside the cooling device controller and a thermal zone.
A QMI TMD is not a standalone cooling device neither a multiple
cooling devices with their own DT description.
For this reason, the proposed changes with child nodes has been
rejected [3].
As a solution, it has been proposed to fold all these child nodes into
an array and add an id in the cooling maps to identify the cooling
device entry in the controller node [4].
Given the thermal zone has the same mechanism [5], that is a phandle
to a sensor node and an sensor specifier. The proposed approach makes
sense as it is consistent with the thermal zone description.
This series provides a cleanup around the usage of the OF code which
is interleaved with non-OF code. The OF and the non-OF code are
separated and remain self-encapsulated.
Then the function to register a cooling device is renamed to reflect
the legacy usage and a new function is introduced with the id
parameter.
Finally, the DT bindings is updated with the new format and the
thermal OF is changed to handle the new DT bindings.
Given the trivial changes impacting the files outside of the thermal
framework, this series is designed to have all changes going through
the thermal tree.
Thanks!
[1] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/writing-bindings.rst
[2] https://lore.kernel.org/all/20260127155722.2797783-1-gaurav.kohli@oss.qualcomm.com/
[3] https://lore.kernel.org/all/546faeda-d896-403c-a449-5c9b0cd7159e@kernel.org/
[4] https://lore.kernel.org/all/74f59ef0-ead7-483f-a80e-a3da2f6ebcdb@oss.qualcomm.com/
[5] https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/thermal/thermal-zones.yaml#n99
Daniel Lezcano (13):
thermal/of: Move OF code where it belongs to
thermal/driver/tegra/soctherm: Use devm_ variant when registering a
cooling device
thermal/core: Make thermal_cooling_device_init_complete() non static
thermal/of: Move the node pointer assignation in the OF code file
thermal/core: Remove node pointer parameter parameter when registering
a tz
thermal/core: Register cooling device non-OF drivers
hwmon:: Use non-OF thermal cooling device register function
thermal/core: Move OF functions def in the CONFIG_OF section in
thermal.h
thermal/core: Put of_node field cooling device structure under Kconfig
option
thermal/of: Rename the devm_thermal_of_cooling_device_register()
function
thermal/of: Introduce cooling device of_index
thermal/of: Pass the of_index and add a function to register with an
index
thermal/of: Process cooling device index in cooling-spec
Gaurav Kohli (1):
dt-bindings: thermal: cooling-devices: Update support for 3 cells
cooling device
.../thermal/thermal-cooling-devices.yaml | 8 +-
.../bindings/thermal/thermal-zones.yaml | 3 +-
drivers/gpu/drm/etnaviv/etnaviv_gpu.c | 2 +-
drivers/hwmon/amc6821.c | 2 +-
drivers/hwmon/aspeed-pwm-tacho.c | 5 +-
drivers/hwmon/cros_ec_hwmon.c | 4 +-
drivers/hwmon/dell-smm-hwmon.c | 4 +-
drivers/hwmon/emc2305.c | 6 +-
drivers/hwmon/gpio-fan.c | 6 +-
drivers/hwmon/max6650.c | 6 +-
drivers/hwmon/mlxreg-fan.c | 4 +-
drivers/hwmon/npcm750-pwm-fan.c | 6 +-
drivers/hwmon/pwm-fan.c | 5 +-
drivers/hwmon/qnap-mcu-hwmon.c | 6 +-
drivers/hwmon/tc654.c | 5 +-
drivers/memory/tegra/tegra210-emc-core.c | 4 +-
drivers/soc/qcom/qcom_aoss.c | 2 +-
drivers/thermal/cpufreq_cooling.c | 2 +-
drivers/thermal/cpuidle_cooling.c | 2 +-
drivers/thermal/devfreq_cooling.c | 2 +-
drivers/thermal/khadas_mcu_fan.c | 7 +-
drivers/thermal/tegra/soctherm.c | 6 +-
drivers/thermal/thermal_core.c | 60 ++------
drivers/thermal/thermal_core.h | 6 +
drivers/thermal/thermal_of.c | 139 +++++++++++++++++-
include/linux/thermal.h | 71 ++++++---
26 files changed, 267 insertions(+), 106 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH v1 01/14] thermal/of: Move OF code where it belongs to
From: Daniel Lezcano @ 2026-04-19 18:21 UTC (permalink / raw)
To: rafael
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon, Daniel Lezcano
In-Reply-To: <20260419182203.4083985-1-daniel.lezcano@oss.qualcomm.com>
The functions:
- thermal_of_cooling_device_register()
- devm_thermal_of_cooling_device_register()
are related to thermal-of but they are implemented in
thermal-core. Move these functions to the right file.
Pure move patch.
No functional change intended.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/thermal_core.c | 75 +---------------------------------
drivers/thermal/thermal_core.h | 5 +++
drivers/thermal/thermal_of.c | 72 ++++++++++++++++++++++++++++++++
3 files changed, 78 insertions(+), 74 deletions(-)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 2f4e2dc46b8f..8a70768b46dd 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1056,7 +1056,7 @@ static void thermal_cooling_device_init_complete(struct thermal_cooling_device *
* Return: a pointer to the created struct thermal_cooling_device or an
* ERR_PTR. Caller must check return value with IS_ERR*() helpers.
*/
-static struct thermal_cooling_device *
+struct thermal_cooling_device *
__thermal_cooling_device_register(struct device_node *np,
const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
@@ -1163,79 +1163,6 @@ thermal_cooling_device_register(const char *type, void *devdata,
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
-/**
- * thermal_of_cooling_device_register() - register an OF thermal cooling device
- * @np: a pointer to a device tree node.
- * @type: the thermal cooling device type.
- * @devdata: device private data.
- * @ops: standard thermal cooling devices callbacks.
- *
- * This function will register a cooling device with device tree node reference.
- * This interface function adds a new thermal cooling device (fan/processor/...)
- * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
- * to all the thermal zone devices registered at the same time.
- *
- * Return: a pointer to the created struct thermal_cooling_device or an
- * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
- */
-struct thermal_cooling_device *
-thermal_of_cooling_device_register(struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops)
-{
- return __thermal_cooling_device_register(np, type, devdata, ops);
-}
-EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
-
-static void thermal_cooling_device_release(struct device *dev, void *res)
-{
- thermal_cooling_device_unregister(
- *(struct thermal_cooling_device **)res);
-}
-
-/**
- * devm_thermal_of_cooling_device_register() - register an OF thermal cooling
- * device
- * @dev: a valid struct device pointer of a sensor device.
- * @np: a pointer to a device tree node.
- * @type: the thermal cooling device type.
- * @devdata: device private data.
- * @ops: standard thermal cooling devices callbacks.
- *
- * This function will register a cooling device with device tree node reference.
- * This interface function adds a new thermal cooling device (fan/processor/...)
- * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
- * to all the thermal zone devices registered at the same time.
- *
- * Return: a pointer to the created struct thermal_cooling_device or an
- * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
- */
-struct thermal_cooling_device *
-devm_thermal_of_cooling_device_register(struct device *dev,
- struct device_node *np,
- const char *type, void *devdata,
- const struct thermal_cooling_device_ops *ops)
-{
- struct thermal_cooling_device **ptr, *tcd;
-
- ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
- GFP_KERNEL);
- if (!ptr)
- return ERR_PTR(-ENOMEM);
-
- tcd = __thermal_cooling_device_register(np, type, devdata, ops);
- if (IS_ERR(tcd)) {
- devres_free(ptr);
- return tcd;
- }
-
- *ptr = tcd;
- devres_add(dev, ptr);
-
- return tcd;
-}
-EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
-
static bool thermal_cooling_device_present(struct thermal_cooling_device *cdev)
{
struct thermal_cooling_device *pos = NULL;
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index d3acff602f9c..bdd59947b24f 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -269,6 +269,11 @@ void thermal_zone_device_critical_shutdown(struct thermal_zone_device *tz);
void thermal_governor_update_tz(struct thermal_zone_device *tz,
enum thermal_notify_event reason);
+struct thermal_cooling_device *
+__thermal_cooling_device_register(struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops);
+
/* Helpers */
#define for_each_trip_desc(__tz, __td) \
for (__td = __tz->trips; __td - __tz->trips < __tz->num_trips; __td++)
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index 99085c806a1f..398157e740fc 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -510,3 +510,75 @@ void devm_thermal_of_zone_unregister(struct device *dev, struct thermal_zone_dev
devm_thermal_of_zone_match, tz));
}
EXPORT_SYMBOL_GPL(devm_thermal_of_zone_unregister);
+
+/**
+ * thermal_of_cooling_device_register() - register an OF thermal cooling device
+ * @np: a pointer to a device tree node.
+ * @type: the thermal cooling device type.
+ * @devdata: device private data.
+ * @ops: standard thermal cooling devices callbacks.
+ *
+ * This function will register a cooling device with device tree node reference.
+ * This interface function adds a new thermal cooling device (fan/processor/...)
+ * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
+ * to all the thermal zone devices registered at the same time.
+ *
+ * Return: a pointer to the created struct thermal_cooling_device or an
+ * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
+ */
+struct thermal_cooling_device *
+thermal_of_cooling_device_register(struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ return __thermal_cooling_device_register(np, type, devdata, ops);
+}
+EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
+
+static void thermal_cooling_device_release(struct device *dev, void *res)
+{
+ thermal_cooling_device_unregister(*(struct thermal_cooling_device **)res);
+}
+
+/**
+ * devm_thermal_of_cooling_device_register() - register an OF thermal cooling
+ * device
+ * @dev: a valid struct device pointer of a sensor device.
+ * @np: a pointer to a device tree node.
+ * @type: the thermal cooling device type.
+ * @devdata: device private data.
+ * @ops: standard thermal cooling devices callbacks.
+ *
+ * This function will register a cooling device with device tree node reference.
+ * This interface function adds a new thermal cooling device (fan/processor/...)
+ * to /sys/class/thermal/ folder as cooling_device[0-*]. It tries to bind itself
+ * to all the thermal zone devices registered at the same time.
+ *
+ * Return: a pointer to the created struct thermal_cooling_device or an
+ * ERR_PTR. Caller must check return value with IS_ERR*() helpers.
+ */
+struct thermal_cooling_device *
+devm_thermal_of_cooling_device_register(struct device *dev,
+ struct device_node *np,
+ const char *type, void *devdata,
+ const struct thermal_cooling_device_ops *ops)
+{
+ struct thermal_cooling_device **ptr, *tcd;
+
+ ptr = devres_alloc(thermal_cooling_device_release, sizeof(*ptr),
+ GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ tcd = __thermal_cooling_device_register(np, type, devdata, ops);
+ if (IS_ERR(tcd)) {
+ devres_free(ptr);
+ return tcd;
+ }
+
+ *ptr = tcd;
+ devres_add(dev, ptr);
+
+ return tcd;
+}
+EXPORT_SYMBOL_GPL(devm_thermal_of_cooling_device_register);
--
2.43.0
^ permalink raw reply related
* [PATCH v1 02/14] thermal/driver/tegra/soctherm: Use devm_ variant when registering a cooling device
From: Daniel Lezcano @ 2026-04-19 18:21 UTC (permalink / raw)
To: rafael
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon, Daniel Lezcano,
Jiri Slaby (SUSE), Thomas Gleixner, Mikko Perttunen,
Svyatoslav Ryhel, open list:TEGRA ARCHITECTURE SUPPORT
In-Reply-To: <20260419182203.4083985-1-daniel.lezcano@oss.qualcomm.com>
The driver invokes thermal_of_cooling_device_register() at probe time
but without unregistering it at remove time.
As we have a devm_ variant, use it and the cooling device should be
automatically removed.
Compiled-tested only.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/tegra/soctherm.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/thermal/tegra/soctherm.c b/drivers/thermal/tegra/soctherm.c
index 5d26b52beaba..9d3eb3be2db0 100644
--- a/drivers/thermal/tegra/soctherm.c
+++ b/drivers/thermal/tegra/soctherm.c
@@ -1700,9 +1700,9 @@ static void soctherm_init_hw_throt_cdev(struct platform_device *pdev)
stc->init = true;
} else {
- tcd = thermal_of_cooling_device_register(np_stcc,
- (char *)name, ts,
- &throt_cooling_ops);
+ tcd = devm_thermal_of_cooling_device_register(dev, np_stcc,
+ (char *)name, ts,
+ &throt_cooling_ops);
if (IS_ERR_OR_NULL(tcd)) {
dev_err(dev,
"throttle-cfg: %s: failed to register cooling device\n",
--
2.43.0
^ permalink raw reply related
* [PATCH v1 03/14] thermal/core: Make thermal_cooling_device_init_complete() non static
From: Daniel Lezcano @ 2026-04-19 18:21 UTC (permalink / raw)
To: rafael
Cc: gaurav.kohli, Zhang Rui, Lukasz Luba, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Lucas Stach, Russell King,
Christian Gmeiner, David Airlie, Simona Vetter, Guenter Roeck,
Joel Stanley, Andrew Jeffery, Thomas Weißschuh, Benson Leung,
Pali Rohár, Avi Fishman, Tomer Maimon, Tali Perry,
Patrick Venture, Nancy Yuen, Benjamin Fair, Heiko Stuebner,
Thierry Reding, Jonathan Hunter, Bjorn Andersson, Konrad Dybcio,
Amit Daniel Kachhap, Viresh Kumar, Neil Armstrong, Amit Kucheria,
linux-pm, linux-kernel, linux-hwmon, Daniel Lezcano
In-Reply-To: <20260419182203.4083985-1-daniel.lezcano@oss.qualcomm.com>
In the process of separating clearly the OF code and the thermal core
code, let's split and export the
thermal_cooling_device_init_complete() function so it can be used by
an implementation inside the thermal OF code.
Signed-off-by: Daniel Lezcano <daniel.lezcano@oss.qualcomm.com>
---
drivers/thermal/thermal_core.c | 12 ++++++++----
drivers/thermal/thermal_core.h | 2 ++
drivers/thermal/thermal_of.c | 10 +++++++++-
3 files changed, 19 insertions(+), 5 deletions(-)
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 8a70768b46dd..35cf170f3fa1 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1028,7 +1028,7 @@ static void thermal_zone_cdev_bind(struct thermal_zone_device *tz,
__thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
}
-static void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev)
+void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev)
{
struct thermal_zone_device *tz;
@@ -1127,8 +1127,6 @@ __thermal_cooling_device_register(struct device_node *np,
if (current_state <= cdev->max_state)
thermal_debug_cdev_add(cdev, current_state);
- thermal_cooling_device_init_complete(cdev);
-
return cdev;
out_cooling_dev:
@@ -1159,7 +1157,13 @@ struct thermal_cooling_device *
thermal_cooling_device_register(const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
- return __thermal_cooling_device_register(NULL, type, devdata, ops);
+ struct thermal_cooling_device *cdev;
+
+ cdev = __thermal_cooling_device_register(NULL, type, devdata, ops);
+ if (!IS_ERR(cdev))
+ thermal_cooling_device_init_complete(cdev);
+
+ return cdev;
}
EXPORT_SYMBOL_GPL(thermal_cooling_device_register);
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index bdd59947b24f..6e44bcf37b00 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -269,6 +269,8 @@ void thermal_zone_device_critical_shutdown(struct thermal_zone_device *tz);
void thermal_governor_update_tz(struct thermal_zone_device *tz,
enum thermal_notify_event reason);
+void thermal_cooling_device_init_complete(struct thermal_cooling_device *cdev);
+
struct thermal_cooling_device *
__thermal_cooling_device_register(struct device_node *np,
const char *type, void *devdata,
diff --git a/drivers/thermal/thermal_of.c b/drivers/thermal/thermal_of.c
index 398157e740fc..35d542aac7f8 100644
--- a/drivers/thermal/thermal_of.c
+++ b/drivers/thermal/thermal_of.c
@@ -531,7 +531,15 @@ thermal_of_cooling_device_register(struct device_node *np,
const char *type, void *devdata,
const struct thermal_cooling_device_ops *ops)
{
- return __thermal_cooling_device_register(np, type, devdata, ops);
+ struct thermal_cooling_device *cdev;
+
+ cdev = __thermal_cooling_device_register(np, type, devdata, ops);
+ if (IS_ERR(cdev))
+ return cdev;
+
+ thermal_cooling_device_init_complete(cdev);
+
+ return cdev;
}
EXPORT_SYMBOL_GPL(thermal_of_cooling_device_register);
--
2.43.0
^ 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