aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-omap2
diff options
context:
space:
mode:
authorRajendra Nayak <rnayak@ti.com>2011-07-10 07:56:55 -0400
committerPaul Walmsley <paul@pwsan.com>2011-07-10 07:56:55 -0400
commit555e74ea08bfc04a0136f976cbaa200addf1ba87 (patch)
treeafac050a2669fcf1e47d764785f9007c568b9e15 /arch/arm/mach-omap2
parentb86cfb52a145d8ddad66b98c39c6764f3883cd5a (diff)
OMAP2+: clockdomain: Add per clkdm lock to prevent concurrent state programming
Since the clkdm state programming is now done from within the hwmod framework (which uses a per-hwmod lock) instead of the being done from the clock framework (which used a global lock), there is now a need to have per-clkdm locking to prevent races between different hwmods/modules belonging to the same clock domain concurrently programming the clkdm state. Signed-off-by: Rajendra Nayak <rnayak@ti.com> Signed-off-by: Benoit Cousson <b-cousson@ti.com> Cc: Paul Walmsley <paul@pwsan.com> Signed-off-by: Paul Walmsley <paul@pwsan.com>
Diffstat (limited to 'arch/arm/mach-omap2')
-rw-r--r--arch/arm/mach-omap2/clockdomain.c47
-rw-r--r--arch/arm/mach-omap2/clockdomain.h2
-rw-r--r--arch/arm/mach-omap2/clockdomain2xxx_3xxx.c6
-rw-r--r--arch/arm/mach-omap2/clockdomain44xx.c13
4 files changed, 50 insertions, 18 deletions
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index 239b558853f5..ab7db083f97f 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -92,6 +92,8 @@ static int _clkdm_register(struct clockdomain *clkdm)
92 92
93 pwrdm_add_clkdm(pwrdm, clkdm); 93 pwrdm_add_clkdm(pwrdm, clkdm);
94 94
95 spin_lock_init(&clkdm->lock);
96
95 pr_debug("clockdomain: registered %s\n", clkdm->name); 97 pr_debug("clockdomain: registered %s\n", clkdm->name);
96 98
97 return 0; 99 return 0;
@@ -690,6 +692,9 @@ int clkdm_clear_all_sleepdeps(struct clockdomain *clkdm)
690 */ 692 */
691int clkdm_sleep(struct clockdomain *clkdm) 693int clkdm_sleep(struct clockdomain *clkdm)
692{ 694{
695 int ret;
696 unsigned long flags;
697
693 if (!clkdm) 698 if (!clkdm)
694 return -EINVAL; 699 return -EINVAL;
695 700
@@ -704,9 +709,11 @@ int clkdm_sleep(struct clockdomain *clkdm)
704 709
705 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name); 710 pr_debug("clockdomain: forcing sleep on %s\n", clkdm->name);
706 711
712 spin_lock_irqsave(&clkdm->lock, flags);
707 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 713 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
708 714 ret = arch_clkdm->clkdm_sleep(clkdm);
709 return arch_clkdm->clkdm_sleep(clkdm); 715 spin_unlock_irqrestore(&clkdm->lock, flags);
716 return ret;
710} 717}
711 718
712/** 719/**
@@ -720,6 +727,9 @@ int clkdm_sleep(struct clockdomain *clkdm)
720 */ 727 */
721int clkdm_wakeup(struct clockdomain *clkdm) 728int clkdm_wakeup(struct clockdomain *clkdm)
722{ 729{
730 int ret;
731 unsigned long flags;
732
723 if (!clkdm) 733 if (!clkdm)
724 return -EINVAL; 734 return -EINVAL;
725 735
@@ -734,9 +744,11 @@ int clkdm_wakeup(struct clockdomain *clkdm)
734 744
735 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name); 745 pr_debug("clockdomain: forcing wakeup on %s\n", clkdm->name);
736 746
747 spin_lock_irqsave(&clkdm->lock, flags);
737 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 748 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
738 749 ret = arch_clkdm->clkdm_wakeup(clkdm);
739 return arch_clkdm->clkdm_wakeup(clkdm); 750 spin_unlock_irqrestore(&clkdm->lock, flags);
751 return ret;
740} 752}
741 753
742/** 754/**
@@ -751,6 +763,8 @@ int clkdm_wakeup(struct clockdomain *clkdm)
751 */ 763 */
752void clkdm_allow_idle(struct clockdomain *clkdm) 764void clkdm_allow_idle(struct clockdomain *clkdm)
753{ 765{
766 unsigned long flags;
767
754 if (!clkdm) 768 if (!clkdm)
755 return; 769 return;
756 770
@@ -766,10 +780,11 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
766 pr_debug("clockdomain: enabling automatic idle transitions for %s\n", 780 pr_debug("clockdomain: enabling automatic idle transitions for %s\n",
767 clkdm->name); 781 clkdm->name);
768 782
783 spin_lock_irqsave(&clkdm->lock, flags);
769 clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED; 784 clkdm->_flags |= _CLKDM_FLAG_HWSUP_ENABLED;
770
771 arch_clkdm->clkdm_allow_idle(clkdm); 785 arch_clkdm->clkdm_allow_idle(clkdm);
772 pwrdm_clkdm_state_switch(clkdm); 786 pwrdm_clkdm_state_switch(clkdm);
787 spin_unlock_irqrestore(&clkdm->lock, flags);
773} 788}
774 789
775/** 790/**
@@ -783,6 +798,8 @@ void clkdm_allow_idle(struct clockdomain *clkdm)
783 */ 798 */
784void clkdm_deny_idle(struct clockdomain *clkdm) 799void clkdm_deny_idle(struct clockdomain *clkdm)
785{ 800{
801 unsigned long flags;
802
786 if (!clkdm) 803 if (!clkdm)
787 return; 804 return;
788 805
@@ -798,9 +815,10 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
798 pr_debug("clockdomain: disabling automatic idle transitions for %s\n", 815 pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
799 clkdm->name); 816 clkdm->name);
800 817
818 spin_lock_irqsave(&clkdm->lock, flags);
801 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED; 819 clkdm->_flags &= ~_CLKDM_FLAG_HWSUP_ENABLED;
802
803 arch_clkdm->clkdm_deny_idle(clkdm); 820 arch_clkdm->clkdm_deny_idle(clkdm);
821 spin_unlock_irqrestore(&clkdm->lock, flags);
804} 822}
805 823
806/** 824/**
@@ -816,16 +834,25 @@ void clkdm_deny_idle(struct clockdomain *clkdm)
816 */ 834 */
817bool clkdm_in_hwsup(struct clockdomain *clkdm) 835bool clkdm_in_hwsup(struct clockdomain *clkdm)
818{ 836{
837 bool ret;
838 unsigned long flags;
839
819 if (!clkdm) 840 if (!clkdm)
820 return false; 841 return false;
821 842
822 return (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false; 843 spin_lock_irqsave(&clkdm->lock, flags);
844 ret = (clkdm->_flags & _CLKDM_FLAG_HWSUP_ENABLED) ? true : false;
845 spin_unlock_irqrestore(&clkdm->lock, flags);
846
847 return ret;
823} 848}
824 849
825/* Clockdomain-to-clock/hwmod framework interface code */ 850/* Clockdomain-to-clock/hwmod framework interface code */
826 851
827static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm) 852static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
828{ 853{
854 unsigned long flags;
855
829 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable) 856 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_enable)
830 return -EINVAL; 857 return -EINVAL;
831 858
@@ -837,9 +864,11 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
837 if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps) 864 if ((atomic_inc_return(&clkdm->usecount) > 1) && autodeps)
838 return 0; 865 return 0;
839 866
867 spin_lock_irqsave(&clkdm->lock, flags);
840 arch_clkdm->clkdm_clk_enable(clkdm); 868 arch_clkdm->clkdm_clk_enable(clkdm);
841 pwrdm_wait_transition(clkdm->pwrdm.ptr); 869 pwrdm_wait_transition(clkdm->pwrdm.ptr);
842 pwrdm_clkdm_state_switch(clkdm); 870 pwrdm_clkdm_state_switch(clkdm);
871 spin_unlock_irqrestore(&clkdm->lock, flags);
843 872
844 pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name); 873 pr_debug("clockdomain: clkdm %s: enabled\n", clkdm->name);
845 874
@@ -848,6 +877,8 @@ static int _clkdm_clk_hwmod_enable(struct clockdomain *clkdm)
848 877
849static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm) 878static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
850{ 879{
880 unsigned long flags;
881
851 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable) 882 if (!clkdm || !arch_clkdm || !arch_clkdm->clkdm_clk_disable)
852 return -EINVAL; 883 return -EINVAL;
853 884
@@ -859,8 +890,10 @@ static int _clkdm_clk_hwmod_disable(struct clockdomain *clkdm)
859 if (atomic_dec_return(&clkdm->usecount) > 0) 890 if (atomic_dec_return(&clkdm->usecount) > 0)
860 return 0; 891 return 0;
861 892
893 spin_lock_irqsave(&clkdm->lock, flags);
862 arch_clkdm->clkdm_clk_disable(clkdm); 894 arch_clkdm->clkdm_clk_disable(clkdm);
863 pwrdm_clkdm_state_switch(clkdm); 895 pwrdm_clkdm_state_switch(clkdm);
896 spin_unlock_irqrestore(&clkdm->lock, flags);
864 897
865 pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name); 898 pr_debug("clockdomain: clkdm %s: disabled\n", clkdm->name);
866 899
diff --git a/arch/arm/mach-omap2/clockdomain.h b/arch/arm/mach-omap2/clockdomain.h
index 8782a5cadfa6..1e50c88b8a07 100644
--- a/arch/arm/mach-omap2/clockdomain.h
+++ b/arch/arm/mach-omap2/clockdomain.h
@@ -17,6 +17,7 @@
17#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H 17#define __ARCH_ARM_MACH_OMAP2_CLOCKDOMAIN_H
18 18
19#include <linux/init.h> 19#include <linux/init.h>
20#include <linux/spinlock.h>
20 21
21#include "powerdomain.h" 22#include "powerdomain.h"
22#include <plat/clock.h> 23#include <plat/clock.h>
@@ -128,6 +129,7 @@ struct clockdomain {
128 const struct omap_chip_id omap_chip; 129 const struct omap_chip_id omap_chip;
129 atomic_t usecount; 130 atomic_t usecount;
130 struct list_head node; 131 struct list_head node;
132 spinlock_t lock;
131}; 133};
132 134
133/** 135/**
diff --git a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
index 48d0db7e6069..f740edb111f4 100644
--- a/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/clockdomain2xxx_3xxx.c
@@ -183,7 +183,8 @@ static int omap2_clkdm_clk_enable(struct clockdomain *clkdm)
183 _clkdm_add_autodeps(clkdm); 183 _clkdm_add_autodeps(clkdm);
184 _enable_hwsup(clkdm); 184 _enable_hwsup(clkdm);
185 } else { 185 } else {
186 clkdm_wakeup(clkdm); 186 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
187 omap2_clkdm_wakeup(clkdm);
187 } 188 }
188 189
189 return 0; 190 return 0;
@@ -205,7 +206,8 @@ static int omap2_clkdm_clk_disable(struct clockdomain *clkdm)
205 _clkdm_del_autodeps(clkdm); 206 _clkdm_del_autodeps(clkdm);
206 _enable_hwsup(clkdm); 207 _enable_hwsup(clkdm);
207 } else { 208 } else {
208 clkdm_sleep(clkdm); 209 if (clkdm->flags & CLKDM_CAN_FORCE_SLEEP)
210 omap2_clkdm_sleep(clkdm);
209 } 211 }
210 212
211 return 0; 213 return 0;
diff --git a/arch/arm/mach-omap2/clockdomain44xx.c b/arch/arm/mach-omap2/clockdomain44xx.c
index a1a4ecd26544..b43706aa08bd 100644
--- a/arch/arm/mach-omap2/clockdomain44xx.c
+++ b/arch/arm/mach-omap2/clockdomain44xx.c
@@ -95,13 +95,8 @@ static void omap4_clkdm_deny_idle(struct clockdomain *clkdm)
95 95
96static int omap4_clkdm_clk_enable(struct clockdomain *clkdm) 96static int omap4_clkdm_clk_enable(struct clockdomain *clkdm)
97{ 97{
98 bool hwsup = false; 98 if (clkdm->flags & CLKDM_CAN_FORCE_WAKEUP)
99 99 return omap4_clkdm_wakeup(clkdm);
100 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
101 clkdm->cm_inst, clkdm->clkdm_offs);
102
103 if (!hwsup)
104 clkdm_wakeup(clkdm);
105 100
106 return 0; 101 return 0;
107} 102}
@@ -113,8 +108,8 @@ static int omap4_clkdm_clk_disable(struct clockdomain *clkdm)
113 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition, 108 hwsup = omap4_cminst_is_clkdm_in_hwsup(clkdm->prcm_partition,
114 clkdm->cm_inst, clkdm->clkdm_offs); 109 clkdm->cm_inst, clkdm->clkdm_offs);
115 110
116 if (!hwsup) 111 if (!hwsup && (clkdm->flags & CLKDM_CAN_FORCE_SLEEP))
117 clkdm_sleep(clkdm); 112 omap4_clkdm_sleep(clkdm);
118 113
119 return 0; 114 return 0;
120} 115}