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