Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

clk: fractional-divider: tests: Add test suite for edge cases

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]
Link: https://lore.kernel.org/r/20230617131041.18313-3-frank@oltmanns.dev
[sboyd@kernel.org: Rename suite and tests slightly, drop unused
includes, store parent rate to compare instead of repeating equation]
Signed-off-by: Stephen Boyd <sboyd@kernel.org>

authored by

Frank Oltmanns and committed by
Stephen Boyd
2790e2a3 2e9abc6e

+156
+1
drivers/clk/.kunitconfig
··· 2 2 CONFIG_COMMON_CLK=y 3 3 CONFIG_CLK_KUNIT_TEST=y 4 4 CONFIG_CLK_GATE_KUNIT_TEST=y 5 + CONFIG_CLK_FD_KUNIT_TEST=y 5 6 CONFIG_UML_PCI_OVER_VIRTIO=n
+7
drivers/clk/Kconfig
··· 517 517 help 518 518 Kunit test for the basic clk gate type. 519 519 520 + config CLK_FD_KUNIT_TEST 521 + tristate "Basic fractional divider type Kunit test" if !KUNIT_ALL_TESTS 522 + depends on KUNIT 523 + default KUNIT_ALL_TESTS 524 + help 525 + Kunit test for the clk-fractional-divider type. 526 + 520 527 endif
+1
drivers/clk/Makefile
··· 12 12 obj-$(CONFIG_COMMON_CLK) += clk-mux.o 13 13 obj-$(CONFIG_COMMON_CLK) += clk-composite.o 14 14 obj-$(CONFIG_COMMON_CLK) += clk-fractional-divider.o 15 + obj-$(CONFIG_CLK_FD_KUNIT_TEST) += clk-fractional-divider_test.o 15 16 obj-$(CONFIG_COMMON_CLK) += clk-gpio.o 16 17 ifeq ($(CONFIG_OF), y) 17 18 obj-$(CONFIG_COMMON_CLK) += clk-conf.o
+147
drivers/clk/clk-fractional-divider_test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Kunit test for clock fractional divider 4 + */ 5 + #include <linux/clk-provider.h> 6 + #include <kunit/test.h> 7 + 8 + #include "clk-fractional-divider.h" 9 + 10 + /* 11 + * Test the maximum denominator case for fd clock without flags. 12 + * 13 + * Expect the highest possible denominator to be used in order to get as close as possible to the 14 + * requested rate. 15 + */ 16 + static void clk_fd_test_approximation_max_denominator(struct kunit *test) 17 + { 18 + struct clk_fractional_divider *fd; 19 + unsigned long rate, parent_rate, parent_rate_before, m, n, max_n; 20 + 21 + fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL); 22 + KUNIT_ASSERT_NOT_NULL(test, fd); 23 + 24 + fd->mwidth = 3; 25 + fd->nwidth = 3; 26 + max_n = 7; 27 + 28 + rate = 240000000; 29 + parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */ 30 + parent_rate_before = parent_rate; 31 + 32 + clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n); 33 + KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before); 34 + 35 + KUNIT_EXPECT_EQ(test, m, 1); 36 + KUNIT_EXPECT_EQ(test, n, max_n); 37 + } 38 + 39 + /* 40 + * Test the maximum numerator case for fd clock without flags. 41 + * 42 + * Expect the highest possible numerator to be used in order to get as close as possible to the 43 + * requested rate. 44 + */ 45 + static void clk_fd_test_approximation_max_numerator(struct kunit *test) 46 + { 47 + struct clk_fractional_divider *fd; 48 + unsigned long rate, parent_rate, parent_rate_before, m, n, max_m; 49 + 50 + fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL); 51 + KUNIT_ASSERT_NOT_NULL(test, fd); 52 + 53 + fd->mwidth = 3; 54 + max_m = 7; 55 + fd->nwidth = 3; 56 + 57 + rate = 240000000; 58 + parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */ 59 + parent_rate_before = parent_rate; 60 + 61 + clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n); 62 + KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before); 63 + 64 + KUNIT_EXPECT_EQ(test, m, max_m); 65 + KUNIT_EXPECT_EQ(test, n, 1); 66 + } 67 + 68 + /* 69 + * Test the maximum denominator case for zero based fd clock. 70 + * 71 + * Expect the highest possible denominator to be used in order to get as close as possible to the 72 + * requested rate. 73 + */ 74 + static void clk_fd_test_approximation_max_denominator_zero_based(struct kunit *test) 75 + { 76 + struct clk_fractional_divider *fd; 77 + unsigned long rate, parent_rate, parent_rate_before, m, n, max_n; 78 + 79 + fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL); 80 + KUNIT_ASSERT_NOT_NULL(test, fd); 81 + 82 + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; 83 + fd->mwidth = 3; 84 + fd->nwidth = 3; 85 + max_n = 8; 86 + 87 + rate = 240000000; 88 + parent_rate = (max_n + 1) * rate; /* so that it exceeds the maximum divisor */ 89 + parent_rate_before = parent_rate; 90 + 91 + clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n); 92 + KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before); 93 + 94 + KUNIT_EXPECT_EQ(test, m, 1); 95 + KUNIT_EXPECT_EQ(test, n, max_n); 96 + } 97 + 98 + /* 99 + * Test the maximum numerator case for zero based fd clock. 100 + * 101 + * Expect the highest possible numerator to be used in order to get as close as possible to the 102 + * requested rate. 103 + */ 104 + static void clk_fd_test_approximation_max_numerator_zero_based(struct kunit *test) 105 + { 106 + struct clk_fractional_divider *fd; 107 + unsigned long rate, parent_rate, parent_rate_before, m, n, max_m; 108 + 109 + fd = kunit_kzalloc(test, sizeof(*fd), GFP_KERNEL); 110 + KUNIT_ASSERT_NOT_NULL(test, fd); 111 + 112 + fd->flags = CLK_FRAC_DIVIDER_ZERO_BASED; 113 + fd->mwidth = 3; 114 + max_m = 8; 115 + fd->nwidth = 3; 116 + 117 + rate = 240000000; 118 + parent_rate = rate / (max_m + 1); /* so that it exceeds the maximum numerator */ 119 + parent_rate_before = parent_rate; 120 + 121 + clk_fractional_divider_general_approximation(&fd->hw, rate, &parent_rate, &m, &n); 122 + KUNIT_ASSERT_EQ(test, parent_rate, parent_rate_before); 123 + 124 + KUNIT_EXPECT_EQ(test, m, max_m); 125 + KUNIT_EXPECT_EQ(test, n, 1); 126 + } 127 + 128 + static struct kunit_case clk_fd_approximation_test_cases[] = { 129 + KUNIT_CASE(clk_fd_test_approximation_max_denominator), 130 + KUNIT_CASE(clk_fd_test_approximation_max_numerator), 131 + KUNIT_CASE(clk_fd_test_approximation_max_denominator_zero_based), 132 + KUNIT_CASE(clk_fd_test_approximation_max_numerator_zero_based), 133 + {} 134 + }; 135 + 136 + /* 137 + * Test suite for clk_fractional_divider_general_approximation(). 138 + */ 139 + static struct kunit_suite clk_fd_approximation_suite = { 140 + .name = "clk-fd-approximation", 141 + .test_cases = clk_fd_approximation_test_cases, 142 + }; 143 + 144 + kunit_test_suites( 145 + &clk_fd_approximation_suite 146 + ); 147 + MODULE_LICENSE("GPL");