Skip to content

Commit 64a5f97

Browse files
Marco Paganiyilunxu1984
authored andcommitted
fpga: add an initial KUnit suite for the FPGA Region
The suite tests the basic behaviors of the FPGA Region including the programming and the function for finding a specific region. Signed-off-by: Marco Pagani <[email protected]> Acked-by: Xu Yilun <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Xu Yilun <[email protected]>
1 parent 9e68234 commit 64a5f97

File tree

1 file changed

+211
-0
lines changed

1 file changed

+211
-0
lines changed
Lines changed: 211 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,211 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* KUnit test for the FPGA Region
4+
*
5+
* Copyright (C) 2023 Red Hat, Inc.
6+
*
7+
* Author: Marco Pagani <[email protected]>
8+
*/
9+
10+
#include <kunit/test.h>
11+
#include <linux/fpga/fpga-bridge.h>
12+
#include <linux/fpga/fpga-mgr.h>
13+
#include <linux/fpga/fpga-region.h>
14+
#include <linux/module.h>
15+
#include <linux/platform_device.h>
16+
#include <linux/types.h>
17+
18+
struct mgr_stats {
19+
u32 write_count;
20+
};
21+
22+
struct bridge_stats {
23+
bool enable;
24+
u32 cycles_count;
25+
};
26+
27+
struct test_ctx {
28+
struct fpga_manager *mgr;
29+
struct platform_device *mgr_pdev;
30+
struct fpga_bridge *bridge;
31+
struct platform_device *bridge_pdev;
32+
struct fpga_region *region;
33+
struct platform_device *region_pdev;
34+
struct bridge_stats bridge_stats;
35+
struct mgr_stats mgr_stats;
36+
};
37+
38+
static int op_write(struct fpga_manager *mgr, const char *buf, size_t count)
39+
{
40+
struct mgr_stats *stats = mgr->priv;
41+
42+
stats->write_count++;
43+
44+
return 0;
45+
}
46+
47+
/*
48+
* Fake FPGA manager that implements only the write op to count the number
49+
* of programming cycles. The internals of the programming sequence are
50+
* tested in the Manager suite since they are outside the responsibility
51+
* of the Region.
52+
*/
53+
static const struct fpga_manager_ops fake_mgr_ops = {
54+
.write = op_write,
55+
};
56+
57+
static int op_enable_set(struct fpga_bridge *bridge, bool enable)
58+
{
59+
struct bridge_stats *stats = bridge->priv;
60+
61+
if (!stats->enable && enable)
62+
stats->cycles_count++;
63+
64+
stats->enable = enable;
65+
66+
return 0;
67+
}
68+
69+
/*
70+
* Fake FPGA bridge that implements only enable_set op to count the number
71+
* of activation cycles.
72+
*/
73+
static const struct fpga_bridge_ops fake_bridge_ops = {
74+
.enable_set = op_enable_set,
75+
};
76+
77+
static int fake_region_get_bridges(struct fpga_region *region)
78+
{
79+
struct fpga_bridge *bridge = region->priv;
80+
81+
return fpga_bridge_get_to_list(bridge->dev.parent, region->info, &region->bridge_list);
82+
}
83+
84+
static int fake_region_match(struct device *dev, const void *data)
85+
{
86+
return dev->parent == data;
87+
}
88+
89+
static void fpga_region_test_class_find(struct kunit *test)
90+
{
91+
struct test_ctx *ctx = test->priv;
92+
struct fpga_region *region;
93+
94+
region = fpga_region_class_find(NULL, &ctx->region_pdev->dev, fake_region_match);
95+
KUNIT_EXPECT_PTR_EQ(test, region, ctx->region);
96+
}
97+
98+
/*
99+
* FPGA Region programming test. The Region must call get_bridges() to get
100+
* and control the bridges, and then the Manager for the actual programming.
101+
*/
102+
static void fpga_region_test_program_fpga(struct kunit *test)
103+
{
104+
struct test_ctx *ctx = test->priv;
105+
struct fpga_image_info *img_info;
106+
char img_buf[4];
107+
int ret;
108+
109+
img_info = fpga_image_info_alloc(&ctx->mgr_pdev->dev);
110+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, img_info);
111+
112+
img_info->buf = img_buf;
113+
img_info->count = sizeof(img_buf);
114+
115+
ctx->region->info = img_info;
116+
ret = fpga_region_program_fpga(ctx->region);
117+
KUNIT_ASSERT_EQ(test, ret, 0);
118+
119+
KUNIT_EXPECT_EQ(test, 1, ctx->mgr_stats.write_count);
120+
KUNIT_EXPECT_EQ(test, 1, ctx->bridge_stats.cycles_count);
121+
122+
fpga_bridges_put(&ctx->region->bridge_list);
123+
124+
ret = fpga_region_program_fpga(ctx->region);
125+
KUNIT_ASSERT_EQ(test, ret, 0);
126+
127+
KUNIT_EXPECT_EQ(test, 2, ctx->mgr_stats.write_count);
128+
KUNIT_EXPECT_EQ(test, 2, ctx->bridge_stats.cycles_count);
129+
130+
fpga_bridges_put(&ctx->region->bridge_list);
131+
132+
fpga_image_info_free(img_info);
133+
}
134+
135+
/*
136+
* The configuration used in this test suite uses a single bridge to
137+
* limit the code under test to a single unit. The functions used by the
138+
* Region for getting and controlling bridges are tested (with a list of
139+
* multiple bridges) in the Bridge suite.
140+
*/
141+
static int fpga_region_test_init(struct kunit *test)
142+
{
143+
struct test_ctx *ctx;
144+
struct fpga_region_info region_info = { 0 };
145+
146+
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
147+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx);
148+
149+
ctx->mgr_pdev = platform_device_register_simple("mgr_pdev", PLATFORM_DEVID_AUTO, NULL, 0);
150+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->mgr_pdev);
151+
152+
ctx->mgr = devm_fpga_mgr_register(&ctx->mgr_pdev->dev, "Fake FPGA Manager", &fake_mgr_ops,
153+
&ctx->mgr_stats);
154+
KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->mgr));
155+
156+
ctx->bridge_pdev = platform_device_register_simple("bridge_pdev", PLATFORM_DEVID_AUTO,
157+
NULL, 0);
158+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->bridge_pdev);
159+
160+
ctx->bridge = fpga_bridge_register(&ctx->bridge_pdev->dev, "Fake FPGA Bridge",
161+
&fake_bridge_ops, &ctx->bridge_stats);
162+
KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->bridge));
163+
164+
ctx->bridge_stats.enable = true;
165+
166+
ctx->region_pdev = platform_device_register_simple("region_pdev", PLATFORM_DEVID_AUTO,
167+
NULL, 0);
168+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->region_pdev);
169+
170+
region_info.mgr = ctx->mgr;
171+
region_info.priv = ctx->bridge;
172+
region_info.get_bridges = fake_region_get_bridges;
173+
174+
ctx->region = fpga_region_register_full(&ctx->region_pdev->dev, &region_info);
175+
KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->region));
176+
177+
test->priv = ctx;
178+
179+
return 0;
180+
}
181+
182+
static void fpga_region_test_exit(struct kunit *test)
183+
{
184+
struct test_ctx *ctx = test->priv;
185+
186+
fpga_region_unregister(ctx->region);
187+
platform_device_unregister(ctx->region_pdev);
188+
189+
fpga_bridge_unregister(ctx->bridge);
190+
platform_device_unregister(ctx->bridge_pdev);
191+
192+
platform_device_unregister(ctx->mgr_pdev);
193+
}
194+
195+
static struct kunit_case fpga_region_test_cases[] = {
196+
KUNIT_CASE(fpga_region_test_class_find),
197+
KUNIT_CASE(fpga_region_test_program_fpga),
198+
199+
{}
200+
};
201+
202+
static struct kunit_suite fpga_region_suite = {
203+
.name = "fpga_mgr",
204+
.init = fpga_region_test_init,
205+
.exit = fpga_region_test_exit,
206+
.test_cases = fpga_region_test_cases,
207+
};
208+
209+
kunit_test_suite(fpga_region_suite);
210+
211+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)