lkml.org 
[lkml]   [2023]   [Mar]   [27]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v3 11/11] clk: Add KUnit tests for clks registered with struct clk_parent_data
    Date
    Test that clks registered with 'struct clk_parent_data' work as
    intended and can find their parents.

    Cc: Christian Marangi <ansuelsmth@gmail.com>
    Cc: Brendan Higgins <brendan.higgins@linux.dev>
    Cc: David Gow <davidgow@google.com>
    Signed-off-by: Stephen Boyd <sboyd@kernel.org>
    ---
    drivers/clk/Makefile | 3 +-
    drivers/clk/clk_parent_data_test.h | 10 +
    drivers/clk/clk_test.c | 459 +++++++++++++++++++-
    drivers/clk/kunit_clk_parent_data_test.dtso | 28 ++
    4 files changed, 498 insertions(+), 2 deletions(-)
    create mode 100644 drivers/clk/clk_parent_data_test.h
    create mode 100644 drivers/clk/kunit_clk_parent_data_test.dtso

    diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
    index 4fb809f4bd95..2697bdec1c46 100644
    --- a/drivers/clk/Makefile
    +++ b/drivers/clk/Makefile
    @@ -2,7 +2,8 @@
    # 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
    +obj-$(CONFIG_CLK_KUNIT_TEST) += clk_test.o \
    + kunit_clk_parent_data_test.dtbo.o
    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_parent_data_test.h b/drivers/clk/clk_parent_data_test.h
    new file mode 100644
    index 000000000000..eedd53ae910d
    --- /dev/null
    +++ b/drivers/clk/clk_parent_data_test.h
    @@ -0,0 +1,10 @@
    +/* SPDX-License-Identifier: GPL-2.0 */
    +#ifndef _CLK_PARENT_DATA_TEST_H
    +#define _CLK_PARENT_DATA_TEST_H
    +
    +#define CLK_PARENT_DATA_1MHZ_NAME "1mhz_fixed_legacy"
    +#define CLK_PARENT_DATA_PARENT1 "parent_fwname"
    +#define CLK_PARENT_DATA_PARENT2 "50"
    +#define CLK_PARENT_DATA_50MHZ_NAME "50_clk"
    +
    +#endif
    diff --git a/drivers/clk/clk_test.c b/drivers/clk/clk_test.c
    index f9a5c2964c65..60c6a47f9c68 100644
    --- a/drivers/clk/clk_test.c
    +++ b/drivers/clk/clk_test.c
    @@ -4,12 +4,19 @@
    */
    #include <linux/clk.h>
    #include <linux/clk-provider.h>
    +#include <linux/of.h>
    +#include <linux/platform_device.h>

    /* Needed for clk_hw_get_clk() */
    #include "clk.h"

    +#include <kunit/clk.h>
    +#include <kunit/of.h>
    +#include <kunit/platform_device.h>
    #include <kunit/test.h>

    +#include "clk_parent_data_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)
    @@ -2394,6 +2401,454 @@ static struct kunit_suite clk_mux_notifier_test_suite = {
    .test_cases = clk_mux_notifier_test_cases,
    };

    +struct clk_register_clk_parent_data_test_case {
    + const char *desc;
    + struct clk_parent_data pdata;
    +};
    +
    +static void
    +clk_register_clk_parent_data_test_case_to_desc(
    + const struct clk_register_clk_parent_data_test_case *t, char *desc)
    +{
    + strcpy(desc, t->desc);
    +}
    +
    +static const struct clk_register_clk_parent_data_test_case
    +clk_register_clk_parent_data_of_cases[] = {
    + {
    + /*
    + * Test that a clk registered with a struct device_node can
    + * find a parent based on struct clk_parent_data::index.
    + */
    + .desc = "clk_parent_data_of_index_test",
    + .pdata.index = 0,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device_node can
    + * find a parent based on struct clk_parent_data::fwname.
    + */
    + .desc = "clk_parent_data_of_fwname_test",
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT1,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device_node can
    + * find a parent based on struct clk_parent_data::name.
    + */
    + .desc = "clk_parent_data_of_name_test",
    + /* The index must be negative to indicate firmware not used */
    + .pdata.index = -1,
    + .pdata.name = CLK_PARENT_DATA_1MHZ_NAME,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device_node can
    + * find a parent based on struct
    + * clk_parent_data::{fw_name,name}.
    + */
    + .desc = "clk_parent_data_of_fwname_name_test",
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT1,
    + .pdata.name = "not_matching",
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device_node can
    + * find a parent based on struct clk_parent_data::{index,name}.
    + * Index takes priority.
    + */
    + .desc = "clk_parent_data_of_index_name_priority_test",
    + .pdata.index = 0,
    + .pdata.name = "not_matching",
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device_node can
    + * find a parent based on struct
    + * clk_parent_data::{index,fwname,name}. The fw_name takes
    + * priority over index and name.
    + */
    + .desc = "clk_parent_data_of_index_fwname_name_priority_test",
    + .pdata.index = 1,
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT1,
    + .pdata.name = "not_matching",
    + },
    +};
    +
    +KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_of_test, clk_register_clk_parent_data_of_cases,
    + clk_register_clk_parent_data_test_case_to_desc)
    +
    +/**
    + * struct clk_register_clk_parent_data_of_ctx - Context for clk_parent_data OF tests
    + * @np: device node of clk under test
    + * @hw: clk_hw for clk under test
    + */
    +struct clk_register_clk_parent_data_of_ctx {
    + struct device_node *np;
    + struct clk_hw hw;
    +};
    +
    +static int clk_register_clk_parent_data_of_test_init(struct kunit *test)
    +{
    + struct clk_register_clk_parent_data_of_ctx *ctx;
    +
    + KUNIT_ASSERT_EQ(test, 0,
    + of_overlay_apply_kunit(test, kunit_clk_parent_data_test));
    +
    + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
    + if (!ctx)
    + return -ENOMEM;
    + test->priv = ctx;
    +
    + ctx->np = of_find_compatible_node(NULL, NULL, "test,clk-parent-data");
    + if (!ctx->np)
    + return -ENODEV;
    +
    + return 0;
    +}
    +
    +static void clk_register_clk_parent_data_of_test_exit(struct kunit *test)
    +{
    + struct clk_register_clk_parent_data_of_ctx *ctx = test->priv;
    +
    + of_node_put(ctx->np);
    +}
    +
    +/*
    + * Test that a clk registered with a struct device_node can find a parent based on
    + * struct clk_parent_data when the hw member isn't set.
    + */
    +static void clk_register_clk_parent_data_of_test(struct kunit *test)
    +{
    + struct clk_register_clk_parent_data_of_ctx *ctx = test->priv;
    + struct clk_hw *parent_hw;
    + const struct clk_register_clk_parent_data_test_case *test_param;
    + struct clk_init_data init = { };
    + struct clk *expected_parent, *actual_parent;
    +
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->np);
    +
    + expected_parent = of_clk_get_kunit(test, ctx->np, 0);
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent);
    +
    + test_param = test->param_value;
    + init.parent_data = &test_param->pdata;
    + init.num_parents = 1;
    + init.name = "parent_data_of_test_clk";
    + init.ops = &clk_dummy_single_parent_ops;
    + ctx->hw.init = &init;
    + KUNIT_ASSERT_EQ(test, 0, of_clk_hw_register_kunit(test, ctx->np, &ctx->hw));
    +
    + parent_hw = clk_hw_get_parent(&ctx->hw);
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
    +
    + actual_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__);
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, actual_parent);
    +
    + KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent));
    +}
    +
    +static struct kunit_case clk_register_clk_parent_data_of_test_cases[] = {
    + KUNIT_CASE_PARAM(clk_register_clk_parent_data_of_test,
    + clk_register_clk_parent_data_of_test_gen_params),
    + {}
    +};
    +
    +/*
    + * Test suite for registering clks with struct clk_parent_data and a struct
    + * device_node.
    + */
    +static struct kunit_suite clk_register_clk_parent_data_of_suite = {
    + .name = "clk_register_clk_parent_data_of",
    + .init = clk_register_clk_parent_data_of_test_init,
    + .exit = clk_register_clk_parent_data_of_test_exit,
    + .test_cases = clk_register_clk_parent_data_of_test_cases,
    +};
    +
    +/**
    + * struct clk_register_clk_parent_data_device_ctx - Context for clk_parent_data device tests
    + * @dev: device of clk under test
    + * @hw: clk_hw for clk under test
    + * @pdrv: driver to attach to find @dev
    + */
    +struct clk_register_clk_parent_data_device_ctx {
    + struct device *dev;
    + struct clk_hw hw;
    + struct platform_driver pdrv;
    +};
    +
    +static inline struct clk_register_clk_parent_data_device_ctx *
    +clk_register_clk_parent_data_driver_to_test_context(struct platform_device *pdev)
    +{
    + return container_of(to_platform_driver(pdev->dev.driver),
    + struct clk_register_clk_parent_data_device_ctx, pdrv);
    +}
    +
    +static int clk_register_clk_parent_data_device_probe(struct platform_device *pdev)
    +{
    + struct clk_register_clk_parent_data_device_ctx *ctx;
    +
    + ctx = clk_register_clk_parent_data_driver_to_test_context(pdev);
    + ctx->dev = &pdev->dev;
    +
    + return 0;
    +}
    +
    +static void clk_register_clk_parent_data_device_driver(struct kunit *test)
    +{
    + struct clk_register_clk_parent_data_device_ctx *ctx = test->priv;
    + static const struct of_device_id match_table[] = {
    + { .compatible = "test,clk-parent-data" },
    + { }
    + };
    +
    + ctx->pdrv.probe = clk_register_clk_parent_data_device_probe;
    + ctx->pdrv.driver.of_match_table = match_table;
    + ctx->pdrv.driver.name = __func__;
    + ctx->pdrv.driver.owner = THIS_MODULE;
    +
    + KUNIT_ASSERT_EQ(test, 0, platform_driver_register_kunit(test, &ctx->pdrv));
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev);
    +}
    +
    +static const struct clk_register_clk_parent_data_test_case
    +clk_register_clk_parent_data_device_cases[] = {
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::index.
    + */
    + .desc = "clk_parent_data_device_index_test",
    + .pdata.index = 1,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::fwname.
    + */
    + .desc = "clk_parent_data_device_fwname_test",
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT2,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::name.
    + */
    + .desc = "clk_parent_data_device_name_test",
    + /* The index must be negative to indicate firmware not used */
    + .pdata.index = -1,
    + .pdata.name = CLK_PARENT_DATA_50MHZ_NAME,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::{fw_name,name}.
    + */
    + .desc = "clk_parent_data_device_fwname_name_test",
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT2,
    + .pdata.name = "not_matching",
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::{index,name}. Index
    + * takes priority.
    + */
    + .desc = "clk_parent_data_device_index_name_priority_test",
    + .pdata.index = 1,
    + .pdata.name = "not_matching",
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::{index,fwname,name}.
    + * The fw_name takes priority over index and name.
    + */
    + .desc = "clk_parent_data_device_index_fwname_name_priority_test",
    + .pdata.index = 0,
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT2,
    + .pdata.name = "not_matching",
    + },
    +};
    +
    +KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_device_test,
    + clk_register_clk_parent_data_device_cases,
    + clk_register_clk_parent_data_test_case_to_desc)
    +
    +/*
    + * Test that a clk registered with a struct device can find a parent based on
    + * struct clk_parent_data when the hw member isn't set.
    + */
    +static void clk_register_clk_parent_data_device_test(struct kunit *test)
    +{
    + struct clk_register_clk_parent_data_device_ctx *ctx;
    + const struct clk_register_clk_parent_data_test_case *test_param;
    + struct clk_hw *parent_hw;
    + struct clk_init_data init = { };
    + struct clk *expected_parent, *actual_parent;
    +
    + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
    + test->priv = ctx;
    +
    + clk_register_clk_parent_data_device_driver(test);
    +
    + expected_parent = clk_get_kunit(test, ctx->dev, "50");
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, expected_parent);
    +
    + test_param = test->param_value;
    + init.parent_data = &test_param->pdata;
    + init.num_parents = 1;
    + init.name = "parent_data_device_test_clk";
    + init.ops = &clk_dummy_single_parent_ops;
    + ctx->hw.init = &init;
    + KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, &ctx->hw));
    +
    + parent_hw = clk_hw_get_parent(&ctx->hw);
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent_hw);
    +
    + actual_parent = clk_hw_get_clk_kunit(test, parent_hw, __func__);
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, actual_parent);
    +
    + KUNIT_EXPECT_TRUE(test, clk_is_match(expected_parent, actual_parent));
    +}
    +
    +static const struct clk_register_clk_parent_data_test_case
    +clk_register_clk_parent_data_device_hw_cases[] = {
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::hw.
    + */
    + .desc = "clk_parent_data_device_hw_index_test",
    + /* The index must be negative to indicate firmware not used */
    + .pdata.index = -1,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::hw when
    + * struct clk_parent_data::fw_name is set.
    + */
    + .desc = "clk_parent_data_device_hw_fwname_test",
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT2,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::hw when struct
    + * clk_parent_data::name is set.
    + */
    + .desc = "clk_parent_data_device_hw_name_test",
    + /* The index must be negative to indicate firmware not used */
    + .pdata.index = -1,
    + .pdata.name = CLK_PARENT_DATA_50MHZ_NAME,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::hw when struct
    + * clk_parent_data::{fw_name,name} are set.
    + */
    + .desc = "clk_parent_data_device_hw_fwname_name_test",
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT2,
    + .pdata.name = "not_matching",
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::hw when struct
    + * clk_parent_data::index is set. The hw pointer takes
    + * priority.
    + */
    + .desc = "clk_parent_data_device_hw_index_priority_test",
    + .pdata.index = 0,
    + },
    + {
    + /*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::hw when
    + * struct clk_parent_data::{index,fwname,name} are set.
    + * The hw pointer takes priority over everything else.
    + */
    + .desc = "clk_parent_data_device_hw_index_fwname_name_priority_test",
    + .pdata.index = 0,
    + .pdata.fw_name = CLK_PARENT_DATA_PARENT2,
    + .pdata.name = "not_matching",
    + },
    +};
    +
    +KUNIT_ARRAY_PARAM(clk_register_clk_parent_data_device_hw_test,
    + clk_register_clk_parent_data_device_hw_cases,
    + clk_register_clk_parent_data_test_case_to_desc)
    +
    +/*
    + * Test that a clk registered with a struct device can find a
    + * parent based on struct clk_parent_data::hw.
    + */
    +static void clk_register_clk_parent_data_device_hw_test(struct kunit *test)
    +{
    + struct clk_register_clk_parent_data_device_ctx *ctx;
    + const struct clk_register_clk_parent_data_test_case *test_param;
    + struct clk_dummy_context *parent;
    + struct clk_hw *parent_hw;
    + struct clk_parent_data pdata = { };
    + struct clk_init_data init = { };
    +
    + ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
    + test->priv = ctx;
    +
    + clk_register_clk_parent_data_device_driver(test);
    +
    + parent = kunit_kzalloc(test, sizeof(*parent), GFP_KERNEL);
    + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, parent);
    +
    + parent_hw = &parent->hw;
    + parent_hw->init = CLK_HW_INIT_NO_PARENT("parent-clk",
    + &clk_dummy_rate_ops, 0);
    +
    + KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, parent_hw));
    +
    + test_param = test->param_value;
    + memcpy(&pdata, &test_param->pdata, sizeof(pdata));
    + pdata.hw = parent_hw;
    + init.parent_data = &pdata;
    + init.num_parents = 1;
    + init.ops = &clk_dummy_single_parent_ops;
    + init.name = "parent_data_device_hw_test_clk";
    + ctx->hw.init = &init;
    + KUNIT_ASSERT_EQ(test, 0, clk_hw_register_kunit(test, ctx->dev, &ctx->hw));
    +
    + KUNIT_EXPECT_PTR_EQ(test, parent_hw, clk_hw_get_parent(&ctx->hw));
    +}
    +
    +static struct kunit_case clk_register_clk_parent_data_device_test_cases[] = {
    + KUNIT_CASE_PARAM(clk_register_clk_parent_data_device_test,
    + clk_register_clk_parent_data_device_test_gen_params),
    + KUNIT_CASE_PARAM(clk_register_clk_parent_data_device_hw_test,
    + clk_register_clk_parent_data_device_hw_test_gen_params),
    + {}
    +};
    +
    +static int clk_register_clk_parent_data_device_init(struct kunit *test)
    +{
    + KUNIT_ASSERT_EQ(test, 0,
    + of_overlay_apply_kunit(test, kunit_clk_parent_data_test));
    +
    + return 0;
    +}
    +
    +/*
    + * Test suite for registering clks with struct clk_parent_data and a struct
    + * device.
    + */
    +static struct kunit_suite clk_register_clk_parent_data_device_suite = {
    + .name = "clk_register_clk_parent_data_device",
    + .init = clk_register_clk_parent_data_device_init,
    + .test_cases = clk_register_clk_parent_data_device_test_cases,
    +};
    +
    kunit_test_suites(
    &clk_leaf_mux_set_rate_parent_test_suite,
    &clk_test_suite,
    @@ -2405,7 +2860,9 @@ kunit_test_suites(
    &clk_range_test_suite,
    &clk_range_maximize_test_suite,
    &clk_range_minimize_test_suite,
    + &clk_register_clk_parent_data_of_suite,
    + &clk_register_clk_parent_data_device_suite,
    &clk_single_parent_mux_test_suite,
    - &clk_uncached_test_suite
    + &clk_uncached_test_suite,
    );
    MODULE_LICENSE("GPL v2");
    diff --git a/drivers/clk/kunit_clk_parent_data_test.dtso b/drivers/clk/kunit_clk_parent_data_test.dtso
    new file mode 100644
    index 000000000000..7d3ed9a5a2e8
    --- /dev/null
    +++ b/drivers/clk/kunit_clk_parent_data_test.dtso
    @@ -0,0 +1,28 @@
    +// SPDX-License-Identifier: GPL-2.0
    +/dts-v1/;
    +/plugin/;
    +
    +#include "clk_parent_data_test.h"
    +
    +&{/} {
    + fixed_50: kunit-clock-50MHz {
    + compatible = "fixed-clock";
    + #clock-cells = <0>;
    + clock-frequency = <50000000>;
    + clock-output-names = CLK_PARENT_DATA_50MHZ_NAME;
    + };
    +
    + fixed_parent: kunit-clock-1MHz {
    + compatible = "fixed-clock";
    + #clock-cells = <0>;
    + clock-frequency = <1000000>;
    + clock-output-names = CLK_PARENT_DATA_1MHZ_NAME;
    + };
    +
    + kunit-clock-controller {
    + compatible = "test,clk-parent-data";
    + clocks = <&fixed_parent>, <&fixed_50>;
    + clock-names = CLK_PARENT_DATA_PARENT1, CLK_PARENT_DATA_PARENT2;
    + #clock-cells = <1>;
    + };
    +};
    --
    https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git/
    https://git.kernel.org/pub/scm/linux/kernel/git/sboyd/spmi.git
    \
     
     \ /
      Last update: 2023-03-28 00:23    [W:3.169 / U:0.344 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site