7be47a3509d4ce69feb005762fec16ae60f5f57a
[librecmc/librecmc.git] /
1 From d330eae026b4a73e77ca0422f5cae5207d80f738 Mon Sep 17 00:00:00 2001
2 From: Stephen Boyd <sboyd@codeaurora.org>
3 Date: Mon, 1 Jun 2015 18:47:57 -0700
4 Subject: OPP: Allow notifiers to call dev_pm_opp_get_{voltage, freq} RCU-free
5
6 We pass the dev_pm_opp structure to OPP notifiers but the users
7 of the notifier need to surround calls to dev_pm_opp_get_*() with
8 RCU read locks to avoid lockdep warnings. The notifier is already
9 called with the dev_opp's srcu lock held, so it should be safe to
10 assume the devm_pm_opp structure is already protected inside the
11 notifier. Update the lockdep check for this.
12
13 Cc: Krzysztof Kozlowski <k.kozlowski@samsung.com>
14 Signed-off-by: Stephen Boyd <sboyd@codeaurora.org>
15 ---
16  drivers/base/power/opp/core.c | 27 +++++++++++++++------------
17  1 file changed, 15 insertions(+), 12 deletions(-)
18
19 --- a/drivers/base/power/opp/core.c
20 +++ b/drivers/base/power/opp/core.c
21 @@ -31,9 +31,10 @@ static LIST_HEAD(dev_opp_list);
22  /* Lock to allow exclusive modification to the device and opp lists */
23  DEFINE_MUTEX(dev_opp_list_lock);
24  
25 -#define opp_rcu_lockdep_assert()                                       \
26 +#define opp_rcu_lockdep_assert(s)                                      \
27  do {                                                                   \
28         RCU_LOCKDEP_WARN(!rcu_read_lock_held() &&                       \
29 +                               !(s && srcu_read_lock_held(s)) &&       \
30                                 !lockdep_is_held(&dev_opp_list_lock),   \
31                            "Missing rcu_read_lock() or "                \
32                            "dev_opp_list_lock protection");             \
33 @@ -91,7 +92,7 @@ struct device_opp *_find_device_opp(stru
34  {
35         struct device_opp *dev_opp;
36  
37 -       opp_rcu_lockdep_assert();
38 +       opp_rcu_lockdep_assert(NULL);
39  
40         if (IS_ERR_OR_NULL(dev)) {
41                 pr_err("%s: Invalid parameters\n", __func__);
42 @@ -125,10 +126,11 @@ unsigned long dev_pm_opp_get_voltage(str
43         struct dev_pm_opp *tmp_opp;
44         unsigned long v = 0;
45  
46 -       opp_rcu_lockdep_assert();
47 +       opp_rcu_lockdep_assert(&opp->dev_opp->srcu_head.srcu);
48  
49 -       tmp_opp = rcu_dereference(opp);
50 -       if (IS_ERR_OR_NULL(tmp_opp))
51 +       tmp_opp = srcu_dereference_check(opp, &opp->dev_opp->srcu_head.srcu,
52 +                                        rcu_read_lock_held());
53 +       if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available)
54                 pr_err("%s: Invalid parameters\n", __func__);
55         else
56                 v = tmp_opp->u_volt;
57 @@ -157,9 +159,10 @@ unsigned long dev_pm_opp_get_freq(struct
58         struct dev_pm_opp *tmp_opp;
59         unsigned long f = 0;
60  
61 -       opp_rcu_lockdep_assert();
62 +       opp_rcu_lockdep_assert(&opp->dev_opp->srcu_head.srcu);
63  
64 -       tmp_opp = rcu_dereference(opp);
65 +       tmp_opp = srcu_dereference_check(opp, &opp->dev_opp->srcu_head.srcu,
66 +                                        rcu_read_lock_held());
67         if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available)
68                 pr_err("%s: Invalid parameters\n", __func__);
69         else
70 @@ -191,7 +194,7 @@ bool dev_pm_opp_is_turbo(struct dev_pm_o
71  {
72         struct dev_pm_opp *tmp_opp;
73  
74 -       opp_rcu_lockdep_assert();
75 +       opp_rcu_lockdep_assert(&opp->dev_opp->srcu_head.srcu);
76  
77         tmp_opp = rcu_dereference(opp);
78         if (IS_ERR_OR_NULL(tmp_opp) || !tmp_opp->available) {
79 @@ -246,7 +249,7 @@ struct dev_pm_opp *dev_pm_opp_get_suspen
80  {
81         struct device_opp *dev_opp;
82  
83 -       opp_rcu_lockdep_assert();
84 +       opp_rcu_lockdep_assert(NULL);
85  
86         dev_opp = _find_device_opp(dev);
87         if (IS_ERR(dev_opp) || !dev_opp->suspend_opp ||
88 @@ -326,7 +329,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_
89         struct device_opp *dev_opp;
90         struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
91  
92 -       opp_rcu_lockdep_assert();
93 +       opp_rcu_lockdep_assert(NULL);
94  
95         dev_opp = _find_device_opp(dev);
96         if (IS_ERR(dev_opp)) {
97 @@ -374,7 +377,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_
98         struct device_opp *dev_opp;
99         struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
100  
101 -       opp_rcu_lockdep_assert();
102 +       opp_rcu_lockdep_assert(NULL);
103  
104         if (!dev || !freq) {
105                 dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);
106 @@ -424,7 +427,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_
107         struct device_opp *dev_opp;
108         struct dev_pm_opp *temp_opp, *opp = ERR_PTR(-ERANGE);
109  
110 -       opp_rcu_lockdep_assert();
111 +       opp_rcu_lockdep_assert(NULL);
112  
113         if (!dev || !freq) {
114                 dev_err(dev, "%s: Invalid argument freq=%p\n", __func__, freq);