]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
counter: rz-mtu3-cnt: prevent counter from being toggled multiple times
authorCosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
Fri, 30 Jan 2026 12:23:52 +0000 (14:23 +0200)
committerWilliam Breathitt Gray <wbg@kernel.org>
Sun, 22 Mar 2026 06:59:22 +0000 (15:59 +0900)
Runtime PM counter is incremented / decremented each time the sysfs
enable file is written to.

If user writes 0 to the sysfs enable file multiple times, runtime PM
usage count underflows, generating the following message.

rz-mtu3-counter rz-mtu3-counter.0: Runtime PM usage count underflow!

At the same time, hardware registers end up being accessed with clocks
off in rz_mtu3_terminate_counter() to disable an already disabled
channel.

If user writes 1 to the sysfs enable file multiple times, runtime PM
usage count will be incremented each time, requiring the same number of
0 writes to get it back to 0.

If user writes 0 to the sysfs enable file while PWM is in progress, PWM
is stopped without counter being the owner of the underlying MTU3
channel.

Check against the cached count_is_enabled value and exit if the user
is trying to set the same enable value.

Cc: stable@vger.kernel.org
Fixes: 0be8907359df ("counter: Add Renesas RZ/G2L MTU3a counter driver")
Signed-off-by: Cosmin Tanislav <cosmin-gabriel.tanislav.xa@renesas.com>
Link: https://lore.kernel.org/r/20260130122353.2263273-5-cosmin-gabriel.tanislav.xa@renesas.com
Signed-off-by: William Breathitt Gray <wbg@kernel.org>
drivers/counter/rz-mtu3-cnt.c

index e755d54dfece944c27f14bcfb867f499e6f27b18..a4a8ef2d88f06473f27b483540cbeffe18bbd82a 100644 (file)
@@ -499,21 +499,25 @@ static int rz_mtu3_count_enable_write(struct counter_device *counter,
        struct rz_mtu3_cnt *const priv = counter_priv(counter);
        int ret = 0;
 
+       mutex_lock(&priv->lock);
+
+       if (priv->count_is_enabled[count->id] == enable)
+               goto exit;
+
        if (enable) {
-               mutex_lock(&priv->lock);
                pm_runtime_get_sync(ch->dev);
                ret = rz_mtu3_initialize_counter(counter, count->id);
                if (ret == 0)
                        priv->count_is_enabled[count->id] = true;
-               mutex_unlock(&priv->lock);
        } else {
-               mutex_lock(&priv->lock);
                rz_mtu3_terminate_counter(counter, count->id);
                priv->count_is_enabled[count->id] = false;
                pm_runtime_put(ch->dev);
-               mutex_unlock(&priv->lock);
        }
 
+exit:
+       mutex_unlock(&priv->lock);
+
        return ret;
 }