[v4,2/2] clk: fractional-divider: tests: Add test suite for edge cases
Commit Message
In light of the recent discovery that the fractional divisor
approximation does not utilize the full available range for clocks that
are flagged CLK_FRAC_DIVIDER_ZERO_BASED [1], implement tests for the
edge cases of this clock type.
Signed-off-by: Frank Oltmanns <frank@oltmanns.dev>
Link: https://lore.kernel.org/lkml/20230529133433.56215-1-frank@oltmanns.dev [1]
---
Please note: I get two checkpatch warnings for this patch:
- Concerning the help text in Kconfig.
- Regarding the file being added, asking if MAINTAINERS needs updating.
Both the help text as well as the MAINTAINERS file seem fine to me.
As expected, when the tests are run *without* PATCH 1, the two "zero
based" test cases fail:
================= clk-fd-test (4 subtests) =================
[PASSED] clk_fd_test_approximation_max_denominator
[PASSED] clk_fd_test_approximation_max_numerator
# clk_fd_test_approximation_max_denominator_zero_based: EXPECTATION FAILED at drivers/clk/clk-fractional-divider_test.c:107
Expected n == max_n, but
n == 7 (0x7)
max_n == 8 (0x8)
[FAILED] clk_fd_test_approximation_max_denominator_zero_based
# clk_fd_test_approximation_max_numerator_zero_based: EXPECTATION FAILED at drivers/clk/clk-fractional-divider_test.c:138
Expected m == max_m, but
m == 7 (0x7)
max_m == 8 (0x8)
[FAILED] clk_fd_test_approximation_max_numerator_zero_based
# clk-fd-test: pass:2 fail:2 skip:0 total:4
# Totals: pass:2 fail:2 skip:0 total:4
=================== [FAILED] clk-fd-test ===================
Best regards,
Frank
drivers/clk/.kunitconfig | 1 +
drivers/clk/Kconfig | 7 +
drivers/clk/Makefile | 1 +
drivers/clk/clk-fractional-divider_test.c | 161 ++++++++++++++++++++++
4 files changed, 170 insertions(+)
create mode 100644 drivers/clk/clk-fractional-divider_test.c
Comments
Hi Frank,
kernel test robot noticed the following build warnings:
[auto build test WARNING on clk/clk-next]
[also build test WARNING on linus/master v6.4-rc6 next-20230616]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Frank-Oltmanns/clk-fractional-divider-Improve-approximation-when-zero-based-and-export/20230617-183118
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
patch link: https://lore.kernel.org/r/20230617102919.27564-3-frank%40oltmanns.dev
patch subject: [PATCH v4 2/2] clk: fractional-divider: tests: Add test suite for edge cases
config: arm-randconfig-r046-20230617 (https://download.01.org/0day-ci/archive/20230617/202306171912.PqJBpGMg-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 12.3.0
reproduce: (https://download.01.org/0day-ci/archive/20230617/202306171912.PqJBpGMg-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306171912.PqJBpGMg-lkp@intel.com/
All warnings (new ones prefixed by >>):
drivers/clk/clk-fractional-divider_test.c: In function 'clk_fd_test_approximation_max_denominator':
>> drivers/clk/clk-fractional-divider_test.c:26:48: warning: variable 'max_m' set but not used [-Wunused-but-set-variable]
26 | unsigned long rate, parent_rate, m, n, max_m, max_n;
| ^~~~~
drivers/clk/clk-fractional-divider_test.c: In function 'clk_fd_test_approximation_max_denominator_zero_based':
drivers/clk/clk-fractional-divider_test.c:88:48: warning: variable 'max_m' set but not used [-Wunused-but-set-variable]
88 | unsigned long rate, parent_rate, m, n, max_m, max_n;
| ^~~~~
vim +/max_m +26 drivers/clk/clk-fractional-divider_test.c
15
16 /*
17 * Test the maximum denominator case for fd clock without flags.
18 *
19 * Expect the highest possible denominator to be used in order to get as close as possible to the
20 * requested rate.
21 */
22 static void clk_fd_test_approximation_max_denominator(struct kunit *test)
23 {
24 struct clk_fractional_divider *fd;
25 struct clk_hw *hw;
> 26 unsigned long rate, parent_rate, m, n, max_m, max_n;
27
28 fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
29 KUNIT_ASSERT_NOT_NULL(test, fd);
30
31 fd->mwidth = 3;
32 max_m = 7;
33 fd->nwidth = 3;
34 max_n = 7;
35
36 hw = &fd->hw;
37
38 rate = 240000000;
39 parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
40
41 clk_fractional_divider_general_approximation(hw, rate, &parent_rate, &m, &n);
42 KUNIT_EXPECT_EQ(test, parent_rate, (max_n + 1) * rate); /* parent remains unchanged */
43 KUNIT_EXPECT_EQ(test, m, 1);
44 KUNIT_EXPECT_EQ(test, n, max_n);
45 }
46
Hi Frank,
kernel test robot noticed the following build warnings:
[auto build test WARNING on clk/clk-next]
[also build test WARNING on linus/master v6.4-rc6 next-20230616]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Frank-Oltmanns/clk-fractional-divider-Improve-approximation-when-zero-based-and-export/20230617-183118
base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
patch link: https://lore.kernel.org/r/20230617102919.27564-3-frank%40oltmanns.dev
patch subject: [PATCH v4 2/2] clk: fractional-divider: tests: Add test suite for edge cases
config: hexagon-randconfig-r035-20230617 (https://download.01.org/0day-ci/archive/20230617/202306172036.EevtaVp6-lkp@intel.com/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce: (https://download.01.org/0day-ci/archive/20230617/202306172036.EevtaVp6-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202306172036.EevtaVp6-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> drivers/clk/clk-fractional-divider_test.c:26:41: warning: variable 'max_m' set but not used [-Wunused-but-set-variable]
26 | unsigned long rate, parent_rate, m, n, max_m, max_n;
| ^
drivers/clk/clk-fractional-divider_test.c:88:41: warning: variable 'max_m' set but not used [-Wunused-but-set-variable]
88 | unsigned long rate, parent_rate, m, n, max_m, max_n;
| ^
2 warnings generated.
vim +/max_m +26 drivers/clk/clk-fractional-divider_test.c
15
16 /*
17 * Test the maximum denominator case for fd clock without flags.
18 *
19 * Expect the highest possible denominator to be used in order to get as close as possible to the
20 * requested rate.
21 */
22 static void clk_fd_test_approximation_max_denominator(struct kunit *test)
23 {
24 struct clk_fractional_divider *fd;
25 struct clk_hw *hw;
> 26 unsigned long rate, parent_rate, m, n, max_m, max_n;
27
28 fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
29 KUNIT_ASSERT_NOT_NULL(test, fd);
30
31 fd->mwidth = 3;
32 max_m = 7;
33 fd->nwidth = 3;
34 max_n = 7;
35
36 hw = &fd->hw;
37
38 rate = 240000000;
39 parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
40
41 clk_fractional_divider_general_approximation(hw, rate, &parent_rate, &m, &n);
42 KUNIT_EXPECT_EQ(test, parent_rate, (max_n + 1) * rate); /* parent remains unchanged */
43 KUNIT_EXPECT_EQ(test, m, 1);
44 KUNIT_EXPECT_EQ(test, n, max_n);
45 }
46
On 2023-06-17 at 20:15:20 +0800, kernel test robot <lkp@intel.com> wrote:
> Hi Frank,
>
> kernel test robot noticed the following build warnings:
>
> [auto build test WARNING on clk/clk-next]
> [also build test WARNING on linus/master v6.4-rc6 next-20230616]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
>
> url: https://github.com/intel-lab-lkp/linux/commits/Frank-Oltmanns/clk-fractional-divider-Improve-approximation-when-zero-based-and-export/20230617-183118
> base: https://git.kernel.org/pub/scm/linux/kernel/git/clk/linux.git clk-next
> patch link: https://lore.kernel.org/r/20230617102919.27564-3-frank%40oltmanns.dev
> patch subject: [PATCH v4 2/2] clk: fractional-divider: tests: Add test suite for edge cases
> config: hexagon-randconfig-r035-20230617 (https://download.01.org/0day-ci/archive/20230617/202306172036.EevtaVp6-lkp@intel.com/config)
> compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
> reproduce: (https://download.01.org/0day-ci/archive/20230617/202306172036.EevtaVp6-lkp@intel.com/reproduce)
>
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202306172036.EevtaVp6-lkp@intel.com/
>
> All warnings (new ones prefixed by >>):
>
>>> drivers/clk/clk-fractional-divider_test.c:26:41: warning: variable 'max_m' set but not used [-Wunused-but-set-variable]
> 26 | unsigned long rate, parent_rate, m, n, max_m, max_n;
> | ^
> drivers/clk/clk-fractional-divider_test.c:88:41: warning: variable 'max_m' set but not used [-Wunused-but-set-variable]
> 88 | unsigned long rate, parent_rate, m, n, max_m, max_n;
> | ^
> 2 warnings generated.
Clang compiler warnings are fixed in version 5:
https://lore.kernel.org/all/20230617131041.18313-1-frank@oltmanns.dev/
>
>
> vim +/max_m +26 drivers/clk/clk-fractional-divider_test.c
>
> 15
> 16 /*
> 17 * Test the maximum denominator case for fd clock without flags.
> 18 *
> 19 * Expect the highest possible denominator to be used in order to get as close as possible to the
> 20 * requested rate.
> 21 */
> 22 static void clk_fd_test_approximation_max_denominator(struct kunit *test)
> 23 {
> 24 struct clk_fractional_divider *fd;
> 25 struct clk_hw *hw;
> > 26 unsigned long rate, parent_rate, m, n, max_m, max_n;
> 27
> 28 fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
> 29 KUNIT_ASSERT_NOT_NULL(test, fd);
> 30
> 31 fd->mwidth = 3;
> 32 max_m = 7;
> 33 fd->nwidth = 3;
> 34 max_n = 7;
> 35
> 36 hw = &fd->hw;
> 37
> 38 rate = 240000000;
> 39 parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
> 40
> 41 clk_fractional_divider_general_approximation(hw, rate, &parent_rate, &m, &n);
> 42 KUNIT_EXPECT_EQ(test, parent_rate, (max_n + 1) * rate); /* parent remains unchanged */
> 43 KUNIT_EXPECT_EQ(test, m, 1);
> 44 KUNIT_EXPECT_EQ(test, n, max_n);
> 45 }
> 46
@@ -513,4 +513,11 @@ config CLK_GATE_KUNIT_TEST
help
Kunit test for the basic clk gate type.
+config CLK_FD_KUNIT_TEST
+ tristate "Basic fractional divider type Kunit test" if !KUNIT_ALL_TESTS
+ depends on KUNIT
+ default KUNIT_ALL_TESTS
+ help
+ Kunit test for the clk-fractional-divider type.
+
endif
@@ -12,6 +12,7 @@ obj-$(CONFIG_COMMON_CLK) += clk-multiplier.o
obj-$(CONFIG_COMMON_CLK) += clk-mux.o
obj-$(CONFIG_COMMON_CLK) += clk-composite.o
obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o
+obj-$(CONFIG_CLK_FD_KUNIT_TEST) += clk-fractional-divider_test.o
obj-$(CONFIG_COMMON_CLK) += clk-gpio.o
ifeq ($(CONFIG_OF), y)
obj-$(CONFIG_COMMON_CLK) += clk-conf.o
new file mode 100644
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kunit test for clock fractional divider
+ */
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+
+/* Needed for clk_hw_get_clk() */
+#include "clk.h"
+
+/* Needed for clk_fractional_divider_general_approximation */
+#include "clk-fractional-divider.h"
+
+#include <kunit/test.h>
+
+/*
+ * Test the maximum denominator case for fd clock without flags.
+ *
+ * Expect the highest possible denominator to be used in order to get as close as possible to the
+ * requested rate.
+ */
+static void clk_fd_test_approximation_max_denominator(struct kunit *test)
+{
+ struct clk_fractional_divider *fd;
+ struct clk_hw *hw;
+ unsigned long rate, parent_rate, m, n, max_m, max_n;
+
+ fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fd);
+
+ fd->mwidth = 3;
+ max_m = 7;
+ fd->nwidth = 3;
+ max_n = 7;
+
+ hw = &fd->hw;
+
+ rate = 240000000;
+ parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
+
+ clk_fractional_divider_general_approximation(hw, rate, &parent_rate, &m, &n);
+ KUNIT_EXPECT_EQ(test, parent_rate, (max_n + 1) * rate); /* parent remains unchanged */
+ KUNIT_EXPECT_EQ(test, m, 1);
+ KUNIT_EXPECT_EQ(test, n, max_n);
+}
+
+/*
+ * Test the maximum numerator case for fd clock without flags.
+ *
+ * Expect the highest possible numerator to be used in order to get as close as possible to the
+ * requested rate.
+ */
+static void clk_fd_test_approximation_max_numerator(struct kunit *test)
+{
+ struct clk_fractional_divider *fd;
+ struct clk_hw *hw;
+ unsigned long rate, parent_rate, m, n, max_m, max_n;
+
+ fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fd);
+
+ fd->mwidth = 3;
+ max_m = 7;
+ fd->nwidth = 3;
+ max_n = 7;
+
+ hw = &fd->hw;
+
+ rate = 240000000;
+ parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */
+
+ clk_fractional_divider_general_approximation(hw, rate, &parent_rate, &m, &n);
+ KUNIT_EXPECT_EQ(test, parent_rate, rate / (max_n + 1)); /* parent remains unchanged */
+ KUNIT_EXPECT_EQ(test, m, max_m);
+ KUNIT_EXPECT_EQ(test, n, 1);
+}
+
+/*
+ * Test the maximum denominator case for zero based fd clock.
+ *
+ * Expect the highest possible denominator to be used in order to get as close as possible to the
+ * requested rate.
+ */
+static void clk_fd_test_approximation_max_denominator_zero_based(struct kunit *test)
+{
+ struct clk_fractional_divider *fd;
+ struct clk_hw *hw;
+ unsigned long rate, parent_rate, m, n, max_m, max_n;
+
+ fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fd);
+
+ fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
+ fd->mwidth = 3;
+ max_m = 8;
+ fd->nwidth = 3;
+ max_n = 8;
+
+ hw = &fd->hw;
+
+ rate = 240000000;
+ parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */
+
+ clk_fractional_divider_general_approximation(hw, rate, &parent_rate, &m, &n);
+ KUNIT_EXPECT_EQ(test, parent_rate, (max_n + 1) * rate); /* parent remains unchanged */
+ KUNIT_EXPECT_EQ(test, m, 1);
+ KUNIT_EXPECT_EQ(test, n, max_n);
+}
+
+/*
+ * Test the maximum numerator case for zero based fd clock.
+ *
+ * Expect the highest possible numerator to be used in order to get as close as possible to the
+ * requested rate.
+ */
+static void clk_fd_test_approximation_max_numerator_zero_based(struct kunit *test)
+{
+ struct clk_fractional_divider *fd;
+ struct clk_hw *hw;
+ unsigned long rate, parent_rate, m, n, max_m, max_n;
+
+ fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL);
+ KUNIT_ASSERT_NOT_NULL(test, fd);
+
+ fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED;
+ fd->mwidth = 3;
+ max_m = 8;
+ fd->nwidth = 3;
+ max_n = 8;
+
+ hw = &fd->hw;
+
+ rate = 240000000;
+ parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */
+
+ clk_fractional_divider_general_approximation(hw, rate, &parent_rate, &m, &n);
+ KUNIT_EXPECT_EQ(test, parent_rate, rate / (max_n + 1)); /* parent remains unchanged */
+ KUNIT_EXPECT_EQ(test, m, max_m);
+ KUNIT_EXPECT_EQ(test, n, 1);
+}
+
+static struct kunit_case clk_fd_test_cases[] = {
+ KUNIT_CASE(clk_fd_test_approximation_max_denominator),
+ KUNIT_CASE(clk_fd_test_approximation_max_numerator),
+ KUNIT_CASE(clk_fd_test_approximation_max_denominator_zero_based),
+ KUNIT_CASE(clk_fd_test_approximation_max_numerator_zero_based),
+ {}
+};
+
+/*
+ * Test suite for a fractional divider clock.
+ */
+static struct kunit_suite clk_fd_test_suite = {
+ .name = "clk-fd-test",
+ .test_cases = clk_fd_test_cases,
+};
+
+kunit_test_suites(
+ &clk_fd_test_suite
+);
+MODULE_LICENSE("GPL");