Commit 64e29fd5ed42f5d0ff5b0ea9395b3abd5d43f89b
Committed by
Tony Lindgren
1 parent
49c58e8202
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
ARM: OMAP: clockdomain: Fix locking on _clkdm_clk_hwmod_enable / disable
Previously the code only acquired spinlock after increasing / decreasing the usecount value, which is wrong. This leaves a small window where a task switch may occur between the check of the usecount and the actual wakeup / sleep of the domain. Fixed by moving the spinlock locking before the usecount access. Left the usecount as atomic_t if someone wants an easy access to the parameter through atomic_read. Signed-off-by: Tero Kristo <t-kristo@ti.com> Acked-by: Paul Walmsley <paul@pwsan.com> Signed-off-by: Tony Lindgren <tony@atomide.com>
Showing 1 changed file with 11 additions and 4 deletions Side-by-side Diff
arch/arm/mach-omap2/clockdomain.c
... | ... | @@ -925,15 +925,18 @@ |
925 | 925 | if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) |
926 | 926 | return -EINVAL; |
927 | 927 | |
928 | + spin_lock_irqsave(&clkdm->lock, flags); | |
929 | + | |
928 | 930 | /* |
929 | 931 | * For arch's with no autodeps, clkcm_clk_enable |
930 | 932 | * should be called for every clock instance or hwmod that is |
931 | 933 | * enabled, so the clkdm can be force woken up. |
932 | 934 | */ |
933 | - if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) | |
935 | + if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) { | |
936 | + spin_unlock_irqrestore(&clkdm->lock, flags); | |
934 | 937 | return 0; |
938 | + } | |
935 | 939 | |
936 | - spin_lock_irqsave(&clkdm->lock, flags); | |
937 | 940 | arch_clkdm->clkdm_clk_enable(clkdm); |
938 | 941 | pwrdm_state_switch(clkdm->pwrdm.ptr); |
939 | 942 | spin_unlock_irqrestore(&clkdm->lock, flags); |
940 | 943 | |
941 | 944 | |
942 | 945 | |
943 | 946 | |
... | ... | @@ -950,15 +953,19 @@ |
950 | 953 | if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) |
951 | 954 | return -EINVAL; |
952 | 955 | |
956 | + spin_lock_irqsave(&clkdm->lock, flags); | |
957 | + | |
953 | 958 | if (atomic_read(&clkdm->usecount) == 0) { |
959 | + spin_unlock_irqrestore(&clkdm->lock, flags); | |
954 | 960 | WARN_ON(1); /* underflow */ |
955 | 961 | return -ERANGE; |
956 | 962 | } |
957 | 963 | |
958 | - if (atomic_dec_return(&clkdm->usecount) > 0) | |
964 | + if (atomic_dec_return(&clkdm->usecount) > 0) { | |
965 | + spin_unlock_irqrestore(&clkdm->lock, flags); | |
959 | 966 | return 0; |
967 | + } | |
960 | 968 | |
961 | - spin_lock_irqsave(&clkdm->lock, flags); | |
962 | 969 | arch_clkdm->clkdm_clk_disable(clkdm); |
963 | 970 | pwrdm_state_switch(clkdm->pwrdm.ptr); |
964 | 971 | spin_unlock_irqrestore(&clkdm->lock, flags); |