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 24 struct 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 40 struct 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 */ 51 KUNIT_DEFINE_ACTION_WRAPPER(sg_free_table_wrapper, sg_free_table, 52 struct sg_table *); 53 54 KUNIT_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 */ 64 static 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 */ 84 static 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 108 static 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 */ 123 static 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 */ 147 static 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 } 174 out: 175 sg_miter_stop(&miter); 176 return 0; 177 } 178 179 static 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 */ 193 static 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 202 static 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 213 static 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 */ 228 static 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 */ 256 static 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 ret = sg_alloc_table(sgt, 1, GFP_KERNEL); 267 KUNIT_ASSERT_EQ(test, ret, 0); 268 sg_init_one(sgt->sgl, img_buf, IMAGE_SIZE); 269 270 ret = kunit_add_action_or_reset(test, sg_free_table_wrapper, sgt); 271 KUNIT_ASSERT_EQ(test, ret, 0); 272 273 ctx->img_info->sgt = sgt; 274 275 ret = fpga_mgr_load(ctx->mgr, ctx->img_info); 276 KUNIT_EXPECT_EQ(test, ret, 0); 277 278 KUNIT_EXPECT_TRUE(test, ctx->stats.header_match); 279 KUNIT_EXPECT_TRUE(test, ctx->stats.image_match); 280 281 KUNIT_EXPECT_EQ(test, ctx->stats.op_parse_header_state, FPGA_MGR_STATE_PARSE_HEADER); 282 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_state, FPGA_MGR_STATE_WRITE_INIT); 283 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_sg_state, FPGA_MGR_STATE_WRITE); 284 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_state, FPGA_MGR_STATE_WRITE_COMPLETE); 285 286 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_init_seq, ctx->stats.op_parse_header_seq + 1); 287 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_sg_seq, ctx->stats.op_parse_header_seq + 2); 288 KUNIT_EXPECT_EQ(test, ctx->stats.op_write_complete_seq, ctx->stats.op_parse_header_seq + 3); 289 } 290 291 static int fpga_mgr_test_init(struct kunit *test) 292 { 293 struct mgr_ctx *ctx; 294 int ret; 295 296 ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL); 297 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx); 298 299 ctx->dev = kunit_device_register(test, "fpga-manager-test-dev"); 300 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->dev); 301 302 ctx->mgr = devm_fpga_mgr_register(ctx->dev, "Fake FPGA Manager", &fake_mgr_ops, 303 &ctx->stats); 304 KUNIT_ASSERT_FALSE(test, IS_ERR_OR_NULL(ctx->mgr)); 305 306 ctx->img_info = fpga_image_info_alloc(ctx->dev); 307 KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ctx->img_info); 308 309 ret = kunit_add_action_or_reset(test, fpga_image_info_free_wrapper, ctx->img_info); 310 KUNIT_ASSERT_EQ(test, ret, 0); 311 312 test->priv = ctx; 313 314 return 0; 315 } 316 317 static struct kunit_case fpga_mgr_test_cases[] = { 318 KUNIT_CASE(fpga_mgr_test_get), 319 KUNIT_CASE(fpga_mgr_test_lock), 320 KUNIT_CASE(fpga_mgr_test_img_load_buf), 321 KUNIT_CASE(fpga_mgr_test_img_load_sgt), 322 {} 323 }; 324 325 static struct kunit_suite fpga_mgr_suite = { 326 .name = "fpga_mgr", 327 .init = fpga_mgr_test_init, 328 .test_cases = fpga_mgr_test_cases, 329 }; 330 331 kunit_test_suite(fpga_mgr_suite); 332 333 MODULE_LICENSE("GPL"); 334