Commit 64e29fd5ed42f5d0ff5b0ea9395b3abd5d43f89b

Authored by Tero Kristo
Committed by Tony Lindgren
1 parent 49c58e8202

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);