From: Stephen Boyd <sboyd@kernel.org>
To: Maxime Ripard <maxime@cerno.tech>,
Mike Turquette <mturquette@baylibre.com>
Cc: linux-clk@vger.kernel.org, dri-devel@lists.freedesktop.org,
Dave Stevenson <dave.stevenson@raspberrypi.com>,
Phil Elwell <phil@raspberrypi.com>,
Tim Gover <tim.gover@raspberrypi.com>,
Dom Cobley <dom@raspberrypi.com>,
Maxime Ripard <maxime@cerno.tech>,
kunit-dev@googlegroups.com
Subject: Re: [PATCH v4 01/10] clk: Introduce Kunit Tests for the framework
Date: Fri, 18 Feb 2022 18:20:46 -0800 [thread overview]
Message-ID: <20220219022048.19E1BC340E9@smtp.kernel.org> (raw)
In-Reply-To: <20220125141549.747889-2-maxime@cerno.tech>
Quoting Maxime Ripard (2022-01-25 06:15:40)
> diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
> index 6a98291350b6..2664aaab8068 100644
> --- a/drivers/clk/Makefile
> +++ b/drivers/clk/Makefile
> @@ -2,6 +2,7 @@
> # common clock types
> obj-$(CONFIG_HAVE_CLK) += clk-devres.o clk-bulk.o clkdev.o
> obj-$(CONFIG_COMMON_CLK) += clk.o
> +obj-$(CONFIG_CLK_KUNIT_TEST) += clk-test.o
The file name should be clk_test.c with an underscore.
> obj-$(CONFIG_COMMON_CLK) += clk-divider.o
> obj-$(CONFIG_COMMON_CLK) += clk-fixed-factor.o
> obj-$(CONFIG_COMMON_CLK) += clk-fixed-rate.o
> diff --git a/drivers/clk/clk-test.c b/drivers/clk/clk-test.c
> new file mode 100644
> index 000000000000..47a600d590c1
> --- /dev/null
> +++ b/drivers/clk/clk-test.c
> @@ -0,0 +1,285 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Kunit test for clk rate management
> + */
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/slab.h>
> +
> +#include <kunit/test.h>
> +
> +#define DUMMY_CLOCK_INIT_RATE (42 * 1000 * 1000)
> +#define DUMMY_CLOCK_RATE_1 (142 * 1000 * 1000)
> +#define DUMMY_CLOCK_RATE_2 (242 * 1000 * 1000)
> +
> +struct clk_dummy_context {
> + struct clk_hw hw;
> + unsigned long rate;
> +};
> +
> +static unsigned long clk_dummy_recalc_rate(struct clk_hw *hw,
> + unsigned long parent_rate)
> +{
> + struct clk_dummy_context *ctx =
> + container_of(hw, struct clk_dummy_context, hw);
> +
> + return ctx->rate;
> +}
> +
> +static int clk_dummy_determine_rate(struct clk_hw *hw,
> + struct clk_rate_request *req)
> +{
> + /* Just return the same rate without modifying it */
> + return 0;
> +}
> +
> +static int clk_dummy_set_rate(struct clk_hw *hw,
> + unsigned long rate,
> + unsigned long parent_rate)
> +{
> + struct clk_dummy_context *ctx =
> + container_of(hw, struct clk_dummy_context, hw);
> +
> + ctx->rate = rate;
> + return 0;
> +}
> +
> +static const struct clk_ops clk_dummy_ops = {
Maybe clk_dummy_rate_ops? So we don't mix it up with other dummy ops in
this file testing things that aren't rates.
> + .recalc_rate = clk_dummy_recalc_rate,
> + .determine_rate = clk_dummy_determine_rate,
> + .set_rate = clk_dummy_set_rate,
> +};
> +
> +static int clk_test_init_with_ops(struct kunit *test, const struct clk_ops *ops)
> +{
> + struct clk_dummy_context *ctx;
> + struct clk_init_data init = { };
> + int ret;
> +
> + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
> + if (!ctx)
> + return -ENOMEM;
> + ctx->rate = DUMMY_CLOCK_INIT_RATE;
> + test->priv = ctx;
> +
> + init.name = "test_dummy_rate";
> + init.ops = ops;
> + ctx->hw.init = &init;
> +
> + ret = clk_hw_register(NULL, &ctx->hw);
> + if (ret)
> + return ret;
> +
> + return 0;
> +}
> +
> +static int clk_test_init(struct kunit *test)
> +{
> + return clk_test_init_with_ops(test, &clk_dummy_ops);
> +}
> +
> +static void clk_test_exit(struct kunit *test)
> +{
> + struct clk_dummy_context *ctx = test->priv;
> +
> + clk_hw_unregister(&ctx->hw);
> +}
> +
> +/*
> + * Test that the actual rate matches what is returned by clk_get_rate()
> + */
> +static void clk_test_get_rate(struct kunit *test)
> +{
> + struct clk_dummy_context *ctx = test->priv;
> + struct clk_hw *hw = &ctx->hw;
> + struct clk *clk = hw->clk;
> + unsigned long rate;
> +
> + rate = clk_get_rate(clk);
> + KUNIT_ASSERT_TRUE(test, rate > 0);
> + KUNIT_EXPECT_EQ(test, rate, ctx->rate);
> +}
> +
> +/*
> + * Test that, after a call to clk_set_rate(), the rate returned by
> + * clk_get_rate() matches.
> + *
> + * This assumes that clk_ops.determine_rate or clk_ops.round_rate won't
> + * modify the requested rate, which is our case in clk_dummy_rate_ops.
> + */
> +static void clk_test_set_get_rate(struct kunit *test)
> +{
> + struct clk_dummy_context *ctx = test->priv;
> + struct clk_hw *hw = &ctx->hw;
> + struct clk *clk = hw->clk;
> + unsigned long rate;
> +
> + KUNIT_ASSERT_EQ(test,
> + clk_set_rate(clk, DUMMY_CLOCK_RATE_1),
> + 0);
> +
> + rate = clk_get_rate(clk);
> + KUNIT_ASSERT_GT(test, rate, 0);
> + KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_1);
> +}
> +
> +/*
> + * Test that, after several calls to clk_set_rate(), the rate returned
> + * by clk_get_rate() matches the last one.
> + *
> + * This assumes that clk_ops.determine_rate or clk_ops.round_rate won't
> + * modify the requested rate, which is our case in clk_dummy_rate_ops.
> + */
> +static void clk_test_set_set_get_rate(struct kunit *test)
> +{
> + struct clk_dummy_context *ctx = test->priv;
> + struct clk_hw *hw = &ctx->hw;
> + struct clk *clk = hw->clk;
> + unsigned long rate;
> +
> + KUNIT_ASSERT_EQ(test,
> + clk_set_rate(clk, DUMMY_CLOCK_RATE_1),
> + 0);
> +
> + KUNIT_ASSERT_EQ(test,
> + clk_set_rate(clk, DUMMY_CLOCK_RATE_2),
> + 0);
> +
> + rate = clk_get_rate(clk);
> + KUNIT_ASSERT_GT(test, rate, 0);
> + KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_2);
> +}
> +
> +static struct kunit_case clk_test_cases[] = {
> + KUNIT_CASE(clk_test_get_rate),
> + KUNIT_CASE(clk_test_set_get_rate),
> + KUNIT_CASE(clk_test_set_set_get_rate),
> + {}
> +};
> +
> +static struct kunit_suite clk_test_suite = {
> + .name = "clk-test",
> + .init = clk_test_init,
> + .exit = clk_test_exit,
> + .test_cases = clk_test_cases,
> +};
> +
> +/*
> + * Test that clk_set_rate_range won't return an error for a valid range.
> + */
> +static void clk_range_test_set_range(struct kunit *test)
> +{
> + struct clk_dummy_context *ctx = test->priv;
> + struct clk_hw *hw = &ctx->hw;
> + struct clk *clk = hw->clk;
> + unsigned long rate;
> +
> + KUNIT_ASSERT_EQ(test,
> + clk_set_rate_range(clk,
> + DUMMY_CLOCK_RATE_1,
> + DUMMY_CLOCK_RATE_2),
> + 0);
> +
> + rate = clk_get_rate(clk);
> + KUNIT_ASSERT_GT(test, rate, 0);
> + KUNIT_EXPECT_GE(test, rate, DUMMY_CLOCK_RATE_1);
> + KUNIT_EXPECT_LE(test, rate, DUMMY_CLOCK_RATE_2);
> +}
> +
> +/*
> + * Test that calling clk_set_rate_range with a minimum rate higher than
> + * the maximum rate returns an error.
> + */
> +static void clk_range_test_set_range_invalid(struct kunit *test)
> +{
> + struct clk_dummy_context *ctx = test->priv;
> + struct clk_hw *hw = &ctx->hw;
> + struct clk *clk = hw->clk;
> +
> + KUNIT_EXPECT_LT(test,
> + clk_set_rate_range(clk,
> + DUMMY_CLOCK_RATE_1 + 1000,
> + DUMMY_CLOCK_RATE_1),
> + 0);
> +}
> +
> +/*
> + * Test that if our clock has a rate lower than the minimum set by a
> + * call to clk_set_rate_range(), the rate will be raised to match the
> + * new minimum.
> + *
> + * This assumes that clk_ops.determine_rate or clk_ops.round_rate won't
> + * modify the requested rate, which is our case in clk_dummy_rate_ops.
> + */
> +static void clk_range_test_set_range_get_rate_raised(struct kunit *test)
> +{
> + struct clk_dummy_context *ctx = test->priv;
> + struct clk_hw *hw = &ctx->hw;
> + struct clk *clk = hw->clk;
> + unsigned long rate;
> +
> + KUNIT_ASSERT_EQ(test,
> + clk_set_rate(clk, DUMMY_CLOCK_RATE_1 - 1000),
> + 0);
> +
> + KUNIT_ASSERT_EQ(test,
> + clk_set_rate_range(clk,
> + DUMMY_CLOCK_RATE_1,
> + DUMMY_CLOCK_RATE_2),
> + 0);
> +
> + rate = clk_get_rate(clk);
> + KUNIT_ASSERT_GT(test, rate, 0);
> + KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_1);
> +}
> +
> +/*
> + * Test that if our clock has a rate higher than the maximum set by a
> + * call to clk_set_rate_range(), the rate will be lowered to match the
> + * new maximum.
> + *
> + * This assumes that clk_ops.determine_rate or clk_ops.round_rate won't
> + * modify the requested rate, which is our case in clk_dummy_rate_ops.
> + */
> +static void clk_range_test_set_range_get_rate_lowered(struct kunit *test)
> +{
> + struct clk_dummy_context *ctx = test->priv;
> + struct clk_hw *hw = &ctx->hw;
> + struct clk *clk = hw->clk;
> + unsigned long rate;
> +
> + KUNIT_ASSERT_EQ(test,
> + clk_set_rate(clk, DUMMY_CLOCK_RATE_2 + 1000),
> + 0);
> +
> + KUNIT_ASSERT_EQ(test,
> + clk_set_rate_range(clk,
> + DUMMY_CLOCK_RATE_1,
> + DUMMY_CLOCK_RATE_2),
> + 0);
> +
> + rate = clk_get_rate(clk);
> + KUNIT_ASSERT_GT(test, rate, 0);
> + KUNIT_EXPECT_EQ(test, rate, DUMMY_CLOCK_RATE_2);
> +}
> +
> +static struct kunit_case clk_range_test_cases[] = {
> + KUNIT_CASE(clk_range_test_set_range),
> + KUNIT_CASE(clk_range_test_set_range_invalid),
> + KUNIT_CASE(clk_range_test_set_range_get_rate_raised),
> + KUNIT_CASE(clk_range_test_set_range_get_rate_lowered),
Can you add a test case for round_rate matching what set_rate did, i.e.
calling clk_round_rate() and then clk_set_rate() followed by
clk_get_rate() with the same argument for round and set rate leads to
the same frequency?
It would also be good to add a test that tries to set the clk rate with
clk_set_rate() after a range has been set that is outside the acceptable
range and verify that it fails, and one that tries to set it within the
range and make sure it succeeds (and changes it to be exactly what was
set). Similarly, a call to set two disjoint ranges and verify that the
call that tries to set the second disjoint range fails. We want to test
the failure paths as well, to make sure we don't start causing them to
pass, unless it's expected. This patch could also contain the failure
scenario you're experiencing and mark it as expecting to fail. Then the
patch that fixes it in the core could mark the test as expecting to
pass, which may help us understand more easily what exactly changed
instead of having to figure that out after the fact by reading the
entire test.
> + {}
> +};
> +
> +static struct kunit_suite clk_range_test_suite = {
> + .name = "clk-range-test",
> + .init = clk_test_init,
> + .exit = clk_test_exit,
> + .test_cases = clk_range_test_cases,
> +};
next prev parent reply other threads:[~2022-02-19 2:20 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-01-25 14:15 [PATCH v4 00/10] clk: Improve clock range handling Maxime Ripard
2022-01-25 14:15 ` [PATCH v4 01/10] clk: Introduce Kunit Tests for the framework Maxime Ripard
2022-02-19 2:20 ` Stephen Boyd [this message]
2022-02-21 15:12 ` Maxime Ripard
2022-02-24 22:30 ` Stephen Boyd
2022-01-25 14:15 ` [PATCH v4 02/10] clk: Always clamp the rounded rate Maxime Ripard
2022-02-18 23:15 ` Stephen Boyd
2022-02-21 16:18 ` Maxime Ripard
2022-02-21 16:43 ` Maxime Ripard
2022-02-24 22:39 ` Stephen Boyd
2022-02-25 9:35 ` Maxime Ripard
2022-02-24 22:32 ` Stephen Boyd
2022-02-25 9:45 ` Maxime Ripard
2022-01-25 14:15 ` [PATCH v4 03/10] clk: Use clamp instead of open-coding our own Maxime Ripard
2022-02-18 22:34 ` Stephen Boyd
2022-02-21 16:30 ` Maxime Ripard
2022-02-24 22:44 ` Stephen Boyd
2022-02-25 9:39 ` Maxime Ripard
2022-01-25 14:15 ` [PATCH v4 04/10] clk: Always set the rate on clk_set_range_rate Maxime Ripard
2022-01-25 14:15 ` [PATCH v4 05/10] clk: Add clk_drop_range Maxime Ripard
2022-02-19 2:22 ` Stephen Boyd
2022-01-25 14:15 ` [PATCH v4 06/10] clk: bcm: rpi: Add variant structure Maxime Ripard
2022-01-25 14:15 ` [PATCH v4 07/10] clk: bcm: rpi: Set a default minimum rate Maxime Ripard
2022-01-25 14:15 ` [PATCH v4 08/10] clk: bcm: rpi: Run some clocks at the minimum rate allowed Maxime Ripard
2022-01-25 14:15 ` [PATCH v4 09/10] drm/vc4: Add logging and comments Maxime Ripard
2022-01-25 14:15 ` [PATCH v4 10/10] drm/vc4: hdmi: Remove clock rate initialization Maxime Ripard
2022-02-10 10:19 ` [PATCH v4 00/10] clk: Improve clock range handling Maxime Ripard
2022-02-19 2:25 ` Stephen Boyd
2022-02-14 9:45 ` [PATCH v4 0/10] " Laurent Pinchart
2022-02-19 2:24 ` Stephen Boyd
2022-02-21 9:56 ` Laurent Pinchart
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20220219022048.19E1BC340E9@smtp.kernel.org \
--to=sboyd@kernel.org \
--cc=dave.stevenson@raspberrypi.com \
--cc=dom@raspberrypi.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=kunit-dev@googlegroups.com \
--cc=linux-clk@vger.kernel.org \
--cc=maxime@cerno.tech \
--cc=mturquette@baylibre.com \
--cc=phil@raspberrypi.com \
--cc=tim.gover@raspberrypi.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox