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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.19 335 lines 9.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * KUnit test for the FPGA Manager 4 * 5 * Copyright (C) 2023 Red Hat, Inc. 6 * 7 * Author: Marco Pagani <marpagan@redhat.com> 8 */ 9 10#include <kunit/device.h> 11#include <kunit/test.h> 12#include <linux/fpga/fpga-mgr.h> 13#include <linux/module.h> 14#include <linux/scatterlist.h> 15#include <linux/types.h> 16 17#define HEADER_FILL 'H' 18#define IMAGE_FILL 'P' 19#define IMAGE_BLOCK 1024 20 21#define HEADER_SIZE IMAGE_BLOCK 22#define IMAGE_SIZE (IMAGE_BLOCK * 4) 23 24struct mgr_stats { 25 bool header_match; 26 bool image_match; 27 u32 seq_num; 28 u32 op_parse_header_seq; 29 u32 op_write_init_seq; 30 u32 op_write_seq; 31 u32 op_write_sg_seq; 32 u32 op_write_complete_seq; 33 enum fpga_mgr_states op_parse_header_state; 34 enum fpga_mgr_states op_write_init_state; 35 enum fpga_mgr_states op_write_state; 36 enum fpga_mgr_states op_write_sg_state; 37 enum fpga_mgr_states op_write_complete_state; 38}; 39 40struct mgr_ctx { 41 struct fpga_image_info *img_info; 42 struct fpga_manager *mgr; 43 struct device *dev; 44 struct mgr_stats stats; 45}; 46 47/* 48 * Wrappers to avoid cast warnings when passing action functions directly 49 * to kunit_add_action(). 50 */ 51KUNIT_DEFINE_ACTION_WRAPPER(sg_free_table_wrapper, sg_free_table, 52 struct sg_table *); 53 54KUNIT_DEFINE_ACTION_WRAPPER(fpga_image_info_free_wrapper, fpga_image_info_free, 55 struct fpga_image_info *); 56 57/** 58 * init_test_buffer() - Allocate and initialize a test image in a buffer. 59 * @test: KUnit test context object. 60 * @count: image size in bytes. 61 * 62 * Return: pointer to the newly allocated image. 63 */ 64static char *init_test_buffer(struct kunit *test, size_t count) 65{ 66 char *buf; 67 68 KUNIT_ASSERT_GE(test, count, HEADER_SIZE); 69 70 buf = kunit_kzalloc(test, count, GFP_KERNEL); 71 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); 72 73 memset(buf, HEADER_FILL, HEADER_SIZE); 74 memset(buf + HEADER_SIZE, IMAGE_FILL, count - HEADER_SIZE); 75 76 return buf; 77} 78 79/* 80 * Check the image header. Do not return an error code if the image check fails 81 * since, in this case, it is a failure of the FPGA manager itself, not this 82 * op that tests it. 83 */ 84static int op_parse_header(struct fpga_manager *mgr, struct fpga_image_info *info, 85 const char *buf, size_t count) 86{ 87 struct mgr_stats *stats = mgr->priv; 88 size_t i; 89 90 stats->op_parse_header_state = mgr->state; 91 stats->op_parse_header_seq = stats->seq_num++; 92 93 /* Set header_size and data_size for later */ 94 info->header_size = HEADER_SIZE; 95 info->data_size = info->count - HEADER_SIZE; 96 97 stats->header_match = true; 98 for (i = 0; i < info->header_size; i++) { 99 if (buf[i] != HEADER_FILL) { 100 stats->header_match = false; 101 break; 102 } 103 } 104 105 return 0; 106} 107 108static int op_write_init(struct fpga_manager *mgr, struct fpga_image_info *info, 109 const char *buf, size_t count) 110{ 111 struct mgr_stats *stats = mgr->priv; 112 113 stats->op_write_init_state = mgr->state; 114 stats->op_write_init_seq = stats->seq_num++; 115 116 return 0; 117} 118 119/* 120 * Check the image data. As with op_parse_header, do not return an error code 121 * if the image check fails. 122 */ 123static int op_write(struct fpga_manager *mgr, const char *buf, size_t count) 124{ 125 struct mgr_stats *stats = mgr->priv; 126 size_t i; 127 128 stats->op_write_state = mgr->state; 129 stats->op_write_seq = stats->seq_num++; 130 131 stats->image_match = true; 132 for (i = 0; i < count; i++) { 133 if (buf[i] != IMAGE_FILL) { 134 stats->image_match = false; 135 break; 136 } 137 } 138 139 return 0; 140} 141 142/* 143 * Check the image data, but first skip the header since write_sg will get 144 * the whole image in sg_table. As with op_parse_header, do not return an 145 * error code if the image check fails. 146 */ 147static int op_write_sg(struct fpga_manager *mgr, struct sg_table *sgt) 148{ 149 struct mgr_stats *stats = mgr->priv; 150 struct sg_mapping_iter miter; 151 char *img; 152 size_t i; 153 154 stats->op_write_sg_state = mgr->state; 155 stats->op_write_sg_seq = stats->seq_num++; 156 157 stats->image_match = true; 158 sg_miter_start(&miter, sgt->sgl, sgt->nents, SG_MITER_FROM_SG); 159 160 if (!sg_miter_skip(&miter, HEADER_SIZE)) { 161 stats->image_match = false; 162 goto out; 163 } 164 165 while (sg_miter_next(&miter)) { 166 img = miter.addr; 167 for (i = 0; i < miter.length; i++) { 168 if (img[i] != IMAGE_FILL) { 169 stats->image_match = false; 170 goto out; 171 } 172 } 173 } 174out: 175 sg_miter_stop(&miter); 176 return 0; 177} 178 179static int op_write_complete(struct fpga_manager *mgr, struct fpga_image_info *info) 180{ 181 struct mgr_stats *stats = mgr->priv; 182 183 stats->op_write_complete_state = mgr->state; 184 stats->op_write_complete_seq = stats->seq_num++; 185 186 return 0; 187} 188 189/* 190 * Fake FPGA manager that implements all ops required to check the programming 191 * sequence using a single contiguous buffer and a scatter gather table. 192 */ 193static const struct fpga_manager_ops fake_mgr_ops = { 194 .skip_header = true, 195 .parse_header = op_parse_header, 196 .write_init = op_write_init, 197 .write = op_write, 198 .write_sg = op_write_sg, 199 .write_complete = op_write_complete, 200}; 201 202static void fpga_mgr_test_get(struct kunit *test) 203{ 204 struct mgr_ctx *ctx = test->priv; 205 struct fpga_manager *mgr; 206 207 mgr = fpga_mgr_get(ctx->dev); 208 KUNIT_EXPECT_PTR_EQ(test, mgr, ctx->mgr); 209 210 fpga_mgr_put(ctx->mgr); 211} 212 213static void fpga_mgr_test_lock(struct kunit *test) 214{ 215 struct mgr_ctx *ctx = test->priv; 216 int ret; 217 218 ret = fpga_mgr_lock(ctx->mgr); 219 KUNIT_EXPECT_EQ(test, ret, 0); 220 221 ret = fpga_mgr_lock(ctx->mgr); 222 KUNIT_EXPECT_EQ(test, ret, -EBUSY); 223 224 fpga_mgr_unlock(ctx->mgr); 225} 226 227/* Check the programming sequence using an image in a buffer */ 228static void fpga_mgr_test_img_load_buf(struct kunit *test) 229{ 230 struct mgr_ctx *ctx = test->priv; 231 char *img_buf; 232 int ret; 233 234 img_buf = init_test_buffer(test, IMAGE_SIZE); 235 236 ctx->img_info->count = IMAGE_SIZE; 237 ctx->img_info->buf = img_buf; 238 239 ret = fpga_mgr_load(ctx->mgr, ctx->img_info); 240 KUNIT_EXPECT_EQ(test, ret, 0); 241 242 KUNIT_EXPECT_TRUE(test, ctx->stats.header_match); 243 KUNIT_EXPECT_TRUE(test, ctx->stats.image_match); 244 245 KUNIT_EXPECT_EQ(test, ctx->stats.op_parse_header_state, FPGA_MGR_STATE_PARSE_HEADER); 246 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_state, FPGA_MGR_STATE_WRITE_INIT); 247 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_state, FPGA_MGR_STATE_WRITE); 248 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_state, FPGA_MGR_STATE_WRITE_COMPLETE); 249 250 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_seq, ctx->stats.op_parse_header_seq + 1); 251 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_seq, ctx->stats.op_parse_header_seq + 2); 252 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_seq, ctx->stats.op_parse_header_seq + 3); 253} 254 255/* Check the programming sequence using an image in a scatter gather table */ 256static void fpga_mgr_test_img_load_sgt(struct kunit *test) 257{ 258 struct mgr_ctx *ctx = test->priv; 259 struct sg_table *sgt; 260 char *img_buf; 261 int ret; 262 263 img_buf = init_test_buffer(test, IMAGE_SIZE); 264 265 sgt = kunit_kzalloc(test, sizeof(*sgt), GFP_KERNEL); 266 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, sgt); 267 ret = sg_alloc_table(sgt, 1, GFP_KERNEL); 268 KUNIT_ASSERT_EQ(test, ret, 0); 269 sg_init_one(sgt->sgl, img_buf, IMAGE_SIZE); 270 271 ret = kunit_add_action_or_reset(test, sg_free_table_wrapper, sgt); 272 KUNIT_ASSERT_EQ(test, ret, 0); 273 274 ctx->img_info->sgt = sgt; 275 276 ret = fpga_mgr_load(ctx->mgr, ctx->img_info); 277 KUNIT_EXPECT_EQ(test, ret, 0); 278 279 KUNIT_EXPECT_TRUE(test, ctx->stats.header_match); 280 KUNIT_EXPECT_TRUE(test, ctx->stats.image_match); 281 282 KUNIT_EXPECT_EQ(test, ctx->stats.op_parse_header_state, FPGA_MGR_STATE_PARSE_HEADER); 283 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_state, FPGA_MGR_STATE_WRITE_INIT); 284 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_sg_state, FPGA_MGR_STATE_WRITE); 285 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_state, FPGA_MGR_STATE_WRITE_COMPLETE); 286 287 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_seq, ctx->stats.op_parse_header_seq + 1); 288 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_sg_seq, ctx->stats.op_parse_header_seq + 2); 289 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_seq, ctx->stats.op_parse_header_seq + 3); 290} 291 292static int fpga_mgr_test_init(struct kunit *test) 293{ 294 struct mgr_ctx *ctx; 295 int ret; 296 297 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); 298 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 299 300 ctx->dev = kunit_device_register(test, "fpga-manager-test-dev"); 301 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev); 302 303 ctx->mgr = devm_fpga_mgr_register(ctx->dev, "Fake FPGA Manager", &fake_mgr_ops, 304 &ctx->stats); 305 KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->mgr)); 306 307 ctx->img_info = fpga_image_info_alloc(ctx->dev); 308 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->img_info); 309 310 ret = kunit_add_action_or_reset(test, fpga_image_info_free_wrapper, ctx->img_info); 311 KUNIT_ASSERT_EQ(test, ret, 0); 312 313 test->priv = ctx; 314 315 return 0; 316} 317 318static struct kunit_case fpga_mgr_test_cases[] = { 319 KUNIT_CASE(fpga_mgr_test_get), 320 KUNIT_CASE(fpga_mgr_test_lock), 321 KUNIT_CASE(fpga_mgr_test_img_load_buf), 322 KUNIT_CASE(fpga_mgr_test_img_load_sgt), 323 {} 324}; 325 326static struct kunit_suite fpga_mgr_suite = { 327 .name = "fpga_mgr", 328 .init = fpga_mgr_test_init, 329 .test_cases = fpga_mgr_test_cases, 330}; 331 332kunit_test_suite(fpga_mgr_suite); 333 334MODULE_DESCRIPTION("KUnit test for the FPGA Manager"); 335MODULE_LICENSE("GPL");