summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/clk.c45
-rw-r--r--drivers/clk/clk_test.c54
2 files changed, 47 insertions, 52 deletions
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index c15ee5070f52..9bc8bf434b94 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -2373,28 +2373,29 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
goto out;
}
- rate = clk_core_get_rate_nolock(clk->core);
- if (rate < min || rate > max) {
- /*
- * FIXME:
- * We are in bit of trouble here, current rate is outside the
- * the requested range. We are going try to request appropriate
- * range boundary but there is a catch. It may fail for the
- * usual reason (clock broken, clock protected, etc) but also
- * because:
- * - round_rate() was not favorable and fell on the wrong
- * side of the boundary
- * - the determine_rate() callback does not really check for
- * this corner case when determining the rate
- */
-
- rate = clamp(clk->core->req_rate, min, max);
- ret = clk_core_set_rate_nolock(clk->core, rate);
- if (ret) {
- /* rollback the changes */
- clk->min_rate = old_min;
- clk->max_rate = old_max;
- }
+ /*
+ * Since the boundaries have been changed, let's give the
+ * opportunity to the provider to adjust the clock rate based on
+ * the new boundaries.
+ *
+ * We also need to handle the case where the clock is currently
+ * outside of the boundaries. Clamping the last requested rate
+ * to the current minimum and maximum will also handle this.
+ *
+ * FIXME:
+ * There is a catch. It may fail for the usual reason (clock
+ * broken, clock protected, etc) but also because:
+ * - round_rate() was not favorable and fell on the wrong
+ * side of the boundary
+ * - the determine_rate() callback does not really check for
+ * this corner case when determining the rate
+ */
+ rate = clamp(clk->core->req_rate, min, max);
+ ret = clk_core_set_rate_nolock(clk->core, rate);
+ if (ret) {
+ /* rollback the changes */
+ clk->min_rate = old_min;
+ clk->max_rate = old_max;
}
out:
diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
index bc8d856f0ee8..8924a5ac56d8 100644
--- a/drivers/clk/clk_test.c
+++ b/drivers/clk/clk_test.c
@@ -549,13 +549,12 @@ static struct kunit_suite clk_range_test_suite = {
};
/*
- * Test that if:
- * - we have several subsequent calls to clk_set_rate_range();
- * - and we have a round_rate ops that always return the maximum
- * frequency allowed;
+ * Test that if we have several subsequent calls to
+ * clk_set_rate_range(), the core will reevaluate whether a new rate is
+ * needed each and every time.
*
- * The clock will run at the minimum of all maximum boundaries
- * requested, even if those boundaries aren't there anymore.
+ * With clk_dummy_maximize_rate_ops, this means that the rate will
+ * trail along the maximum as it evolves.
*/
static void clk_range_test_set_range_rate_maximized(struct kunit *test)
{
@@ -596,18 +595,16 @@ static void clk_range_test_set_range_rate_maximized(struct kunit *test)
rate = clk_get_rate(clk);
KUNIT_ASSERT_GT(test, rate, 0);
- KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_2 - 1000);
+ KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_2);
}
/*
- * Test that if:
- * - we have several subsequent calls to clk_set_rate_range(), across
- * multiple users;
- * - and we have a round_rate ops that always return the maximum
- * frequency allowed;
+ * Test that if we have several subsequent calls to
+ * clk_set_rate_range(), across multiple users, the core will reevaluate
+ * whether a new rate is needed each and every time.
*
- * The clock will run at the minimum of all maximum boundaries
- * requested, even if those boundaries aren't there anymore.
+ * With clk_dummy_maximize_rate_ops, this means that the rate will
+ * trail along the maximum as it evolves.
*/
static void clk_range_test_multiple_set_range_rate_maximized(struct kunit *test)
{
@@ -653,7 +650,7 @@ static void clk_range_test_multiple_set_range_rate_maximized(struct kunit *test)
rate = clk_get_rate(clk);
KUNIT_ASSERT_GT(test, rate, 0);
- KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_1);
+ KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_2);
clk_put(user2);
clk_put(user1);
@@ -673,13 +670,12 @@ static struct kunit_suite clk_range_maximize_test_suite = {
};
/*
- * Test that if:
- * - we have several subsequent calls to clk_set_rate_range()
- * - and we have a round_rate ops that always return the minimum
- * frequency allowed;
+ * Test that if we have several subsequent calls to
+ * clk_set_rate_range(), the core will reevaluate whether a new rate is
+ * needed each and every time.
*
- * The clock will run at the maximum of all minimum boundaries
- * requested, even if those boundaries aren't there anymore.
+ * With clk_dummy_minimize_rate_ops, this means that the rate will
+ * trail along the minimum as it evolves.
*/
static void clk_range_test_set_range_rate_minimized(struct kunit *test)
{
@@ -720,18 +716,16 @@ static void clk_range_test_set_range_rate_minimized(struct kunit *test)
rate = clk_get_rate(clk);
KUNIT_ASSERT_GT(test, rate, 0);
- KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_1 + 1000);
+ KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_1);
}
/*
- * Test that if:
- * - we have several subsequent calls to clk_set_rate_range(), across
- * multiple users;
- * - and we have a round_rate ops that always return the minimum
- * frequency allowed;
+ * Test that if we have several subsequent calls to
+ * clk_set_rate_range(), across multiple users, the core will reevaluate
+ * whether a new rate is needed each and every time.
*
- * The clock will run at the maximum of all minimum boundaries
- * requested, even if those boundaries aren't there anymore.
+ * With clk_dummy_minimize_rate_ops, this means that the rate will
+ * trail along the minimum as it evolves.
*/
static void clk_range_test_multiple_set_range_rate_minimized(struct kunit *test)
{
@@ -773,7 +767,7 @@ static void clk_range_test_multiple_set_range_rate_minimized(struct kunit *test)
rate = clk_get_rate(clk);
KUNIT_ASSERT_GT(test, rate, 0);
- KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_2);
+ KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_1);
clk_put(user2);
clk_put(user1);