]> Git Repo - J-linux.git/commitdiff
Merge tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux
authorLinus Torvalds <[email protected]>
Sun, 16 Oct 2022 18:08:19 +0000 (11:08 -0700)
committerLinus Torvalds <[email protected]>
Sun, 16 Oct 2022 18:08:19 +0000 (11:08 -0700)
Pull more clk updates from Stephen Boyd:
 "This is the final part of the clk patches for this merge window.

  The clk rate range series needed another week to fully bake. Maxime
  fixed the bug that broke clk notifiers and prevented this from being
  included in the first pull request. He also added a unit test on top
  to make sure it doesn't break so easily again. The majority of the
  series fixes up how the clk_set_rate_*() APIs work, particularly
  around when the rate constraints are dropped and how they move around
  when reparenting clks. Overall it's a much needed improvement to the
  clk rate range APIs that used to be pretty broken if you looked
  sideways.

  Beyond the core changes there are a few driver fixes for a compilation
  issue or improper data causing clks to fail to register or have the
  wrong parents. These are good to get in before the first -rc so that
  the system actually boots on the affected devices"

* tag 'clk-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/clk/linux: (31 commits)
  clk: tegra: Fix Tegra PWM parent clock
  clk: at91: fix the build with binutils 2.27
  clk: qcom: gcc-msm8660: Drop hardcoded fixed board clocks
  clk: mediatek: clk-mux: Add .determine_rate() callback
  clk: tests: Add tests for notifiers
  clk: Update req_rate on __clk_recalc_rates()
  clk: tests: Add missing test case for ranges
  clk: qcom: clk-rcg2: Take clock boundaries into consideration for gfx3d
  clk: Introduce the clk_hw_get_rate_range function
  clk: Zero the clk_rate_request structure
  clk: Stop forwarding clk_rate_requests to the parent
  clk: Constify clk_has_parent()
  clk: Introduce clk_core_has_parent()
  clk: Switch from __clk_determine_rate to clk_core_round_rate_nolock
  clk: Add our request boundaries in clk_core_init_rate_req
  clk: Introduce clk_hw_init_rate_request()
  clk: Move clk_core_init_rate_req() from clk_core_round_rate_nolock() to its caller
  clk: Change clk_core_init_rate_req prototype
  clk: Set req_rate on reparenting
  clk: Take into account uncached clocks in clk_set_rate_range()
  ...

1  2 
drivers/clk/clk.c

diff --combined drivers/clk/clk.c
index dd810bcd270026b296db13d972727c714074d328,d0cf097a8a5003961faea5c184551e71a470892e..c3c3f8c072588d2a3581e7af7cad80115ffb081d
@@@ -536,6 -536,53 +536,53 @@@ static bool mux_is_better_rate(unsigne
        return now <= rate && now > best;
  }
  
+ static void clk_core_init_rate_req(struct clk_core * const core,
+                                  struct clk_rate_request *req,
+                                  unsigned long rate);
+ static int clk_core_round_rate_nolock(struct clk_core *core,
+                                     struct clk_rate_request *req);
+ static bool clk_core_has_parent(struct clk_core *core, const struct clk_core *parent)
+ {
+       struct clk_core *tmp;
+       unsigned int i;
+       /* Optimize for the case where the parent is already the parent. */
+       if (core->parent == parent)
+               return true;
+       for (i = 0; i < core->num_parents; i++) {
+               tmp = clk_core_get_parent_by_index(core, i);
+               if (!tmp)
+                       continue;
+               if (tmp == parent)
+                       return true;
+       }
+       return false;
+ }
+ static void
+ clk_core_forward_rate_req(struct clk_core *core,
+                         const struct clk_rate_request *old_req,
+                         struct clk_core *parent,
+                         struct clk_rate_request *req,
+                         unsigned long parent_rate)
+ {
+       if (WARN_ON(!clk_core_has_parent(core, parent)))
+               return;
+       clk_core_init_rate_req(parent, req, parent_rate);
+       if (req->min_rate < old_req->min_rate)
+               req->min_rate = old_req->min_rate;
+       if (req->max_rate > old_req->max_rate)
+               req->max_rate = old_req->max_rate;
+ }
  int clk_mux_determine_rate_flags(struct clk_hw *hw,
                                 struct clk_rate_request *req,
                                 unsigned long flags)
        struct clk_core *core = hw->core, *parent, *best_parent = NULL;
        int i, num_parents, ret;
        unsigned long best = 0;
-       struct clk_rate_request parent_req = *req;
  
        /* if NO_REPARENT flag set, pass through to current parent */
        if (core->flags & CLK_SET_RATE_NO_REPARENT) {
                parent = core->parent;
                if (core->flags & CLK_SET_RATE_PARENT) {
-                       ret = __clk_determine_rate(parent ? parent->hw : NULL,
-                                                  &parent_req);
+                       struct clk_rate_request parent_req;
+                       if (!parent) {
+                               req->rate = 0;
+                               return 0;
+                       }
+                       clk_core_forward_rate_req(core, req, parent, &parent_req, req->rate);
+                       ret = clk_core_round_rate_nolock(parent, &parent_req);
                        if (ret)
                                return ret;
  
        /* find the parent that can provide the fastest rate <= rate */
        num_parents = core->num_parents;
        for (i = 0; i < num_parents; i++) {
+               unsigned long parent_rate;
                parent = clk_core_get_parent_by_index(core, i);
                if (!parent)
                        continue;
  
                if (core->flags & CLK_SET_RATE_PARENT) {
-                       parent_req = *req;
-                       ret = __clk_determine_rate(parent->hw, &parent_req);
+                       struct clk_rate_request parent_req;
+                       clk_core_forward_rate_req(core, req, parent, &parent_req, req->rate);
+                       ret = clk_core_round_rate_nolock(parent, &parent_req);
                        if (ret)
                                continue;
+                       parent_rate = parent_req.rate;
                } else {
-                       parent_req.rate = clk_core_get_rate_nolock(parent);
+                       parent_rate = clk_core_get_rate_nolock(parent);
                }
  
-               if (mux_is_better_rate(req->rate, parent_req.rate,
+               if (mux_is_better_rate(req->rate, parent_rate,
                                       best, flags)) {
                        best_parent = parent;
-                       best = parent_req.rate;
+                       best = parent_rate;
                }
        }
  
@@@ -625,6 -684,22 +684,22 @@@ static void clk_core_get_boundaries(str
                *max_rate = min(*max_rate, clk_user->max_rate);
  }
  
+ /*
+  * clk_hw_get_rate_range() - returns the clock rate range for a hw clk
+  * @hw: the hw clk we want to get the range from
+  * @min_rate: pointer to the variable that will hold the minimum
+  * @max_rate: pointer to the variable that will hold the maximum
+  *
+  * Fills the @min_rate and @max_rate variables with the minimum and
+  * maximum that clock can reach.
+  */
+ void clk_hw_get_rate_range(struct clk_hw *hw, unsigned long *min_rate,
+                          unsigned long *max_rate)
+ {
+       clk_core_get_boundaries(hw->core, min_rate, max_rate);
+ }
+ EXPORT_SYMBOL_GPL(clk_hw_get_rate_range);
  static bool clk_core_check_boundaries(struct clk_core *core,
                                      unsigned long min_rate,
                                      unsigned long max_rate)
@@@ -840,9 -915,10 +915,9 @@@ static void clk_core_unprepare(struct c
        if (core->ops->unprepare)
                core->ops->unprepare(core->hw);
  
 -      clk_pm_runtime_put(core);
 -
        trace_clk_unprepare_complete(core);
        clk_core_unprepare(core->parent);
 +      clk_pm_runtime_put(core);
  }
  
  static void clk_core_unprepare_lock(struct clk_core *core)
@@@ -1340,7 -1416,19 +1415,19 @@@ static int clk_core_determine_round_nol
        if (!core)
                return 0;
  
-       req->rate = clamp(req->rate, req->min_rate, req->max_rate);
+       /*
+        * Some clock providers hand-craft their clk_rate_requests and
+        * might not fill min_rate and max_rate.
+        *
+        * If it's the case, clamping the rate is equivalent to setting
+        * the rate to 0 which is bad. Skip the clamping but complain so
+        * that it gets fixed, hopefully.
+        */
+       if (!req->min_rate && !req->max_rate)
+               pr_warn("%s: %s: clk_rate_request has initialized min or max rate.\n",
+                       __func__, core->name);
+       else
+               req->rate = clamp(req->rate, req->min_rate, req->max_rate);
  
        /*
         * At this point, core protection will be disabled
  }
  
  static void clk_core_init_rate_req(struct clk_core * const core,
-                                  struct clk_rate_request *req)
+                                  struct clk_rate_request *req,
+                                  unsigned long rate)
  {
        struct clk_core *parent;
  
        if (WARN_ON(!core || !req))
                return;
  
+       memset(req, 0, sizeof(*req));
+       req->rate = rate;
+       clk_core_get_boundaries(core, &req->min_rate, &req->max_rate);
        parent = core->parent;
        if (parent) {
                req->best_parent_hw = parent->hw;
        }
  }
  
+ /**
+  * clk_hw_init_rate_request - Initializes a clk_rate_request
+  * @hw: the clk for which we want to submit a rate request
+  * @req: the clk_rate_request structure we want to initialise
+  * @rate: the rate which is to be requested
+  *
+  * Initializes a clk_rate_request structure to submit to
+  * __clk_determine_rate() or similar functions.
+  */
+ void clk_hw_init_rate_request(const struct clk_hw *hw,
+                             struct clk_rate_request *req,
+                             unsigned long rate)
+ {
+       if (WARN_ON(!hw || !req))
+               return;
+       clk_core_init_rate_req(hw->core, req, rate);
+ }
+ EXPORT_SYMBOL_GPL(clk_hw_init_rate_request);
+ /**
+  * clk_hw_forward_rate_request - Forwards a clk_rate_request to a clock's parent
+  * @hw: the original clock that got the rate request
+  * @old_req: the original clk_rate_request structure we want to forward
+  * @parent: the clk we want to forward @old_req to
+  * @req: the clk_rate_request structure we want to initialise
+  * @parent_rate: The rate which is to be requested to @parent
+  *
+  * Initializes a clk_rate_request structure to submit to a clock parent
+  * in __clk_determine_rate() or similar functions.
+  */
+ void clk_hw_forward_rate_request(const struct clk_hw *hw,
+                                const struct clk_rate_request *old_req,
+                                const struct clk_hw *parent,
+                                struct clk_rate_request *req,
+                                unsigned long parent_rate)
+ {
+       if (WARN_ON(!hw || !old_req || !parent || !req))
+               return;
+       clk_core_forward_rate_req(hw->core, old_req,
+                                 parent->core, req,
+                                 parent_rate);
+ }
  static bool clk_core_can_round(struct clk_core * const core)
  {
        return core->ops->determine_rate || core->ops->round_rate;
  static int clk_core_round_rate_nolock(struct clk_core *core,
                                      struct clk_rate_request *req)
  {
+       int ret;
        lockdep_assert_held(&prepare_lock);
  
        if (!core) {
                return 0;
        }
  
-       clk_core_init_rate_req(core, req);
        if (clk_core_can_round(core))
                return clk_core_determine_round_nolock(core, req);
-       else if (core->flags & CLK_SET_RATE_PARENT)
-               return clk_core_round_rate_nolock(core->parent, req);
+       if (core->flags & CLK_SET_RATE_PARENT) {
+               struct clk_rate_request parent_req;
+               clk_core_forward_rate_req(core, req, core->parent, &parent_req, req->rate);
+               ret = clk_core_round_rate_nolock(core->parent, &parent_req);
+               if (ret)
+                       return ret;
+               req->best_parent_rate = parent_req.rate;
+               req->rate = parent_req.rate;
+               return 0;
+       }
  
        req->rate = core->rate;
        return 0;
@@@ -1448,8 -1599,7 +1598,7 @@@ unsigned long clk_hw_round_rate(struct 
        int ret;
        struct clk_rate_request req;
  
-       clk_core_get_boundaries(hw->core, &req.min_rate, &req.max_rate);
-       req.rate = rate;
+       clk_core_init_rate_req(hw->core, &req, rate);
  
        ret = clk_core_round_rate_nolock(hw->core, &req);
        if (ret)
@@@ -1481,8 -1631,7 +1630,7 @@@ long clk_round_rate(struct clk *clk, un
        if (clk->exclusive_count)
                clk_core_rate_unprotect(clk->core);
  
-       clk_core_get_boundaries(clk->core, &req.min_rate, &req.max_rate);
-       req.rate = rate;
+       clk_core_init_rate_req(clk->core, &req, rate);
  
        ret = clk_core_round_rate_nolock(clk->core, &req);
  
@@@ -1611,6 -1760,7 +1759,7 @@@ static unsigned long clk_recalc(struct 
  /**
   * __clk_recalc_rates
   * @core: first clk in the subtree
+  * @update_req: Whether req_rate should be updated with the new rate
   * @msg: notification type (see include/linux/clk.h)
   *
   * Walks the subtree of clks starting with clk and recalculates rates as it
   * clk_recalc_rates also propagates the POST_RATE_CHANGE notification,
   * if necessary.
   */
- static void __clk_recalc_rates(struct clk_core *core, unsigned long msg)
+ static void __clk_recalc_rates(struct clk_core *core, bool update_req,
+                              unsigned long msg)
  {
        unsigned long old_rate;
        unsigned long parent_rate = 0;
                parent_rate = core->parent->rate;
  
        core->rate = clk_recalc(core, parent_rate);
+       if (update_req)
+               core->req_rate = core->rate;
  
        /*
         * ignore NOTIFY_STOP and NOTIFY_BAD return values for POST_RATE_CHANGE
                __clk_notify(core, msg, old_rate, core->rate);
  
        hlist_for_each_entry(child, &core->children, child_node)
-               __clk_recalc_rates(child, msg);
+               __clk_recalc_rates(child, update_req, msg);
  }
  
  static unsigned long clk_core_get_rate_recalc(struct clk_core *core)
  {
        if (core && (core->flags & CLK_GET_RATE_NOCACHE))
-               __clk_recalc_rates(core, 0);
+               __clk_recalc_rates(core, false, 0);
  
        return clk_core_get_rate_nolock(core);
  }
   * @clk: the clk whose rate is being returned
   *
   * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
-  * is set, which means a recalc_rate will be issued.
-  * If clk is NULL then returns 0.
+  * is set, which means a recalc_rate will be issued. Can be called regardless of
+  * the clock enabledness. If clk is NULL, or if an error occurred, then returns
+  * 0.
   */
  unsigned long clk_get_rate(struct clk *clk)
  {
@@@ -1864,6 -2018,7 +2017,7 @@@ static int __clk_set_parent(struct clk_
                flags = clk_enable_lock();
                clk_reparent(core, old_parent);
                clk_enable_unlock(flags);
                __clk_set_parent_after(core, old_parent, parent);
  
                return ret;
@@@ -1969,11 -2124,7 +2123,7 @@@ static struct clk_core *clk_calc_new_ra
        if (clk_core_can_round(core)) {
                struct clk_rate_request req;
  
-               req.rate = rate;
-               req.min_rate = min_rate;
-               req.max_rate = max_rate;
-               clk_core_init_rate_req(core, &req);
+               clk_core_init_rate_req(core, &req, rate);
  
                ret = clk_core_determine_round_nolock(core, &req);
                if (ret < 0)
@@@ -2172,8 -2323,7 +2322,7 @@@ static unsigned long clk_core_req_round
        if (cnt < 0)
                return cnt;
  
-       clk_core_get_boundaries(core, &req.min_rate, &req.max_rate);
-       req.rate = req_rate;
+       clk_core_init_rate_req(core, &req, req_rate);
  
        ret = clk_core_round_rate_nolock(core, &req);
  
@@@ -2324,19 -2474,15 +2473,15 @@@ int clk_set_rate_exclusive(struct clk *
  }
  EXPORT_SYMBOL_GPL(clk_set_rate_exclusive);
  
- /**
-  * clk_set_rate_range - set a rate range for a clock source
-  * @clk: clock source
-  * @min: desired minimum clock rate in Hz, inclusive
-  * @max: desired maximum clock rate in Hz, inclusive
-  *
-  * Returns success (0) or negative errno.
-  */
- int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
+ static int clk_set_rate_range_nolock(struct clk *clk,
+                                    unsigned long min,
+                                    unsigned long max)
  {
        int ret = 0;
        unsigned long old_min, old_max, rate;
  
+       lockdep_assert_held(&prepare_lock);
        if (!clk)
                return 0;
  
                return -EINVAL;
        }
  
-       clk_prepare_lock();
        if (clk->exclusive_count)
                clk_core_rate_unprotect(clk->core);
  
                goto out;
        }
  
+       rate = clk->core->req_rate;
+       if (clk->core->flags & CLK_GET_RATE_NOCACHE)
+               rate = clk_core_get_rate_recalc(clk->core);
        /*
         * Since the boundaries have been changed, let's give the
         * opportunity to the provider to adjust the clock rate based on
         * - the determine_rate() callback does not really check for
         *   this corner case when determining the rate
         */
-       rate = clamp(clk->core->req_rate, min, max);
+       rate = clamp(rate, min, max);
        ret = clk_core_set_rate_nolock(clk->core, rate);
        if (ret) {
                /* rollback the changes */
        if (clk->exclusive_count)
                clk_core_rate_protect(clk->core);
  
+       return ret;
+ }
+ /**
+  * clk_set_rate_range - set a rate range for a clock source
+  * @clk: clock source
+  * @min: desired minimum clock rate in Hz, inclusive
+  * @max: desired maximum clock rate in Hz, inclusive
+  *
+  * Return: 0 for success or negative errno on failure.
+  */
+ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
+ {
+       int ret;
+       if (!clk)
+               return 0;
+       clk_prepare_lock();
+       ret = clk_set_rate_range_nolock(clk, min, max);
        clk_prepare_unlock();
  
        return ret;
@@@ -2473,7 -2643,7 +2642,7 @@@ static void clk_core_reparent(struct cl
  {
        clk_reparent(core, new_parent);
        __clk_recalc_accuracies(core);
-       __clk_recalc_rates(core, POST_RATE_CHANGE);
+       __clk_recalc_rates(core, true, POST_RATE_CHANGE);
  }
  
  void clk_hw_reparent(struct clk_hw *hw, struct clk_hw *new_parent)
   *
   * Returns true if @parent is a possible parent for @clk, false otherwise.
   */
- bool clk_has_parent(struct clk *clk, struct clk *parent)
+ bool clk_has_parent(const struct clk *clk, const struct clk *parent)
  {
-       struct clk_core *core, *parent_core;
-       int i;
        /* NULL clocks should be nops, so return success if either is NULL. */
        if (!clk || !parent)
                return true;
  
-       core = clk->core;
-       parent_core = parent->core;
-       /* Optimize for the case where the parent is already the parent. */
-       if (core->parent == parent_core)
-               return true;
-       for (i = 0; i < core->num_parents; i++)
-               if (!strcmp(core->parents[i].name, parent_core->name))
-                       return true;
-       return false;
+       return clk_core_has_parent(clk->core, parent->core);
  }
  EXPORT_SYMBOL_GPL(clk_has_parent);
  
@@@ -2571,9 -2727,9 +2726,9 @@@ static int clk_core_set_parent_nolock(s
  
        /* propagate rate an accuracy recalculation accordingly */
        if (ret) {
-               __clk_recalc_rates(core, ABORT_RATE_CHANGE);
+               __clk_recalc_rates(core, true, ABORT_RATE_CHANGE);
        } else {
-               __clk_recalc_rates(core, POST_RATE_CHANGE);
+               __clk_recalc_rates(core, true, POST_RATE_CHANGE);
                __clk_recalc_accuracies(core);
        }
  
@@@ -3470,7 -3626,7 +3625,7 @@@ static void clk_core_reparent_orphans_n
                        __clk_set_parent_before(orphan, parent);
                        __clk_set_parent_after(orphan, parent, NULL);
                        __clk_recalc_accuracies(orphan);
-                       __clk_recalc_rates(orphan, 0);
+                       __clk_recalc_rates(orphan, true, 0);
  
                        /*
                         * __clk_init_parent() will set the initial req_rate to
@@@ -4346,9 -4502,10 +4501,10 @@@ void __clk_put(struct clk *clk
        }
  
        hlist_del(&clk->clks_node);
-       if (clk->min_rate > clk->core->req_rate ||
-           clk->max_rate < clk->core->req_rate)
-               clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+       /* If we had any boundaries on that clock, let's drop them. */
+       if (clk->min_rate > 0 || clk->max_rate < ULONG_MAX)
+               clk_set_rate_range_nolock(clk, 0, ULONG_MAX);
  
        owner = clk->core->owner;
        kref_put(&clk->core->ref, __clk_release);
This page took 0.118278 seconds and 4 git commands to generate.