1 /*
2 * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "i3c_test.h"
10 #include "hdf_base.h"
11 #include "hdf_io_service_if.h"
12 #include "hdf_log.h"
13 #include "i3c_if.h"
14 #include "osal_mem.h"
15 #include "osal_thread.h"
16 #include "osal_time.h"
17 #include "securec.h"
18
19 #define HDF_LOG_TAG i3c_test_c
20
21 #define I3C_TEST_MSG_NUM 2
22 #define I3C_TEST_8BIT 8
23 #define I3C_TEST_WAIT_TIMES 100
24 #define I3C_TEST_WAIT_TIMEOUT 20
25 #define I3C_TEST_STACK_SIZE (1024 * 256)
26 #define I3C_TEST_IBI_PAYLOAD 16
27 #define I3C_TEST_REG_LEN 2
28
29 static struct I3cMsg g_msgs[I3C_TEST_MSG_NUM];
30 static uint8_t *g_buf;
31 static uint8_t g_regs[I3C_TEST_REG_LEN];
32
33 struct I3cTestEntry {
34 int cmd;
35 int32_t (*func)(void *param);
36 const char *name;
37 };
38
I3cTestGetTestConfig(struct I3cTestConfig * config)39 static int32_t I3cTestGetTestConfig(struct I3cTestConfig *config)
40 {
41 int32_t ret;
42 struct HdfSBuf *reply = NULL;
43 struct HdfIoService *service = NULL;
44 const void *buf = NULL;
45 uint32_t len;
46
47 service = HdfIoServiceBind("I3C_TEST");
48 if (service == NULL) {
49 HDF_LOGE("I3cTestGetTestConfig: service is null!");
50 return HDF_ERR_NOT_SUPPORT;
51 }
52
53 do {
54 reply = HdfSbufObtain(sizeof(*config) + sizeof(uint64_t));
55 if (reply == NULL) {
56 HDF_LOGE("I3cTestGetTestConfig: fail to obtain reply!");
57 ret = HDF_ERR_MALLOC_FAIL;
58 break;
59 }
60
61 ret = service->dispatcher->Dispatch(&service->object, 0, NULL, reply);
62 if (ret != HDF_SUCCESS) {
63 HDF_LOGE("I3cTestGetTestConfig: remote dispatch fail!");
64 break;
65 }
66
67 if (!HdfSbufReadBuffer(reply, &buf, &len)) {
68 HDF_LOGE("I3cTestGetTestConfig: read buf fail!");
69 ret = HDF_ERR_IO;
70 break;
71 }
72
73 if (len != sizeof(*config)) {
74 HDF_LOGE("I3cTestGetTestConfig: config size:%zu, read size:%u!", sizeof(*config), len);
75 ret = HDF_ERR_IO;
76 break;
77 }
78
79 if (memcpy_s(config, sizeof(*config), buf, sizeof(*config)) != EOK) {
80 HDF_LOGE("I3cTestGetTestConfig: memcpy buf fail!");
81 ret = HDF_ERR_IO;
82 break;
83 }
84 HDF_LOGD("I3cTestGetTestConfig: done!");
85 ret = HDF_SUCCESS;
86 } while (0);
87 HdfIoServiceRecycle(service);
88 HdfSbufRecycle(reply);
89 return ret;
90 }
91
I3cTesterGet(void)92 static struct I3cTester *I3cTesterGet(void)
93 {
94 int32_t ret;
95 static struct I3cTester tester;
96 static bool hasInit = false;
97
98 if (hasInit) {
99 return &tester;
100 }
101 ret = I3cTestGetTestConfig(&tester.config);
102 if (ret != HDF_SUCCESS) {
103 HDF_LOGE("I3cTesterGet: read config fail, ret = %d!", ret);
104 return NULL;
105 }
106 tester.handle = I3cOpen(tester.config.busId);
107 if (tester.handle == NULL) {
108 HDF_LOGE("I3cTesterGet: open i3c controller: %hu fail!", tester.config.busId);
109 return NULL;
110 }
111 hasInit = true;
112 HDF_LOGD("I3cTesterGet: done!");
113 return &tester;
114 }
115
I3cTestMallocBuf(struct I3cTester * tester)116 static int32_t I3cTestMallocBuf(struct I3cTester *tester)
117 {
118 struct I3cTestConfig *config = &tester->config;
119
120 if (g_buf == NULL) {
121 g_buf = OsalMemCalloc(config->bufSize);
122 if (g_buf == NULL) {
123 HDF_LOGE("I3cTestMallocBuf: malloc buf fail!");
124 return HDF_ERR_MALLOC_FAIL;
125 }
126 }
127
128 g_regs[0] = (uint8_t)config->regAddr;
129 if (config->regLen > 1) {
130 g_regs[1] = g_regs[0];
131 g_regs[0] = (uint8_t)(config->regAddr >> I3C_TEST_8BIT);
132 }
133
134 g_msgs[0].addr = config->devAddr;
135 g_msgs[0].flags = 0;
136 g_msgs[0].len = config->regLen;
137 g_msgs[0].buf = g_regs;
138
139 g_msgs[1].addr = config->devAddr;
140 g_msgs[1].flags = I3C_FLAG_READ;
141 g_msgs[1].len = config->bufSize;
142 g_msgs[1].buf = g_buf;
143
144 return HDF_SUCCESS;
145 }
146
I3cTestSetUpAll(void * param)147 static int32_t I3cTestSetUpAll(void *param)
148 {
149 struct I3cTester *tester = NULL;
150 struct I3cTestConfig *cfg = NULL;
151 int32_t ret;
152
153 (void)param;
154 HDF_LOGD("I3cTestSetUpAll: enter!");
155 tester = I3cTesterGet();
156 if (tester == NULL) {
157 HDF_LOGE("I3cTestSetUpAll: get tester fail!");
158 return HDF_ERR_INVALID_OBJECT;
159 }
160 tester->total = I3C_TEST_CMD_MAX;
161 tester->fails = 0;
162
163 cfg = &tester->config;
164 HDF_LOGD("I3cTestSetUpAll: test on bus:0x%x, addr:0x%x, reg:0x%x, reglen:0x%x, size:0x%x",
165 cfg->busId, cfg->devAddr, cfg->regAddr, cfg->regLen, cfg->bufSize);
166 ret = I3cTestMallocBuf(tester);
167 if (ret != HDF_SUCCESS) {
168 HDF_LOGE("I3cTestSetUpAll: set up test case fail!");
169 return ret;
170 }
171 HDF_LOGD("I3cTestSetUpAll: exit!");
172
173 return HDF_SUCCESS;
174 }
175
I3cTestTearDownAll(void * param)176 static int32_t I3cTestTearDownAll(void *param)
177 {
178 if (g_buf != NULL) {
179 OsalMemFree(g_buf);
180 g_buf = NULL;
181 }
182 *((int32_t *)param) = 1;
183
184 return HDF_SUCCESS;
185 }
186
I3cTestSetUpSingle(void)187 int32_t I3cTestSetUpSingle(void)
188 {
189 return HDF_SUCCESS;
190 }
191
I3cTestTearDownSingle(void)192 int32_t I3cTestTearDownSingle(void)
193 {
194 return HDF_SUCCESS;
195 }
196
I3cTestTransfer(void * param)197 static int32_t I3cTestTransfer(void *param)
198 {
199 struct I3cTester *tester = NULL;
200 int32_t ret;
201
202 tester = I3cTesterGet();
203 if (tester == NULL) {
204 HDF_LOGE("I3cTestTransfer: get tester fail!");
205 *((int32_t *)param) = 1;
206 return HDF_ERR_INVALID_OBJECT;
207 }
208 /* transfer one write msg */
209 ret = I3cTransfer(tester->handle, g_msgs, 1, I3C_MODE);
210 if (ret != 1) {
211 HDF_LOGE("I3cTestTransfer: I3cTransfer(write) err, ret: %d!", ret);
212 *((int32_t *)param) = 1;
213 return HDF_FAILURE;
214 }
215
216 /* transfer one read msg */
217 ret = I3cTransfer(tester->handle, g_msgs + 1, 1, I3C_MODE);
218 if (ret != 1) {
219 HDF_LOGE("I3cTestTransfer: I3cTransfer(read) err, ret: %d!", ret);
220 *((int32_t *)param) = 1;
221 return HDF_FAILURE;
222 }
223
224 /* transfer two msgs including a read msg and a write msg */
225 ret = I3cTransfer(tester->handle, g_msgs, I3C_TEST_MSG_NUM, I3C_MODE);
226 if (ret != I3C_TEST_MSG_NUM) {
227 HDF_LOGE("I3cTestTransfer: I3cTransfer(mix) err, ret: %d!", ret);
228 *((int32_t *)param) = 1;
229 return HDF_FAILURE;
230 }
231 *((int32_t *)param) = 1;
232 HDF_LOGD("I3cTestTransfer: done!");
233 return HDF_SUCCESS;
234 }
235
I3cTestSetConfig(void * param)236 static int32_t I3cTestSetConfig(void *param)
237 {
238 struct I3cTester *tester = NULL;
239 struct I3cConfig *config = NULL;
240 int32_t ret;
241
242 tester = I3cTesterGet();
243 if (tester == NULL) {
244 HDF_LOGE("I3cTestSetConfig: get tester fail!");
245 *((int32_t *)param) = 1;
246 return HDF_ERR_INVALID_OBJECT;
247 }
248
249 config = (struct I3cConfig*)OsalMemCalloc(sizeof(*config));
250 if (config == NULL) {
251 HDF_LOGE("I3cTestSetConfig: memcalloc fail!");
252 *((int32_t *)param) = 1;
253 return HDF_ERR_MALLOC_FAIL;
254 }
255
256 config->busMode = I3C_BUS_HDR_MODE;
257 config->curHost = NULL;
258 ret = I3cSetConfig(tester->handle, config);
259 if (ret != HDF_SUCCESS) {
260 HDF_LOGE("I3cTestSetConfig: set config fail!, busId = %hu!", tester->config.busId);
261 OsalMemFree(config);
262 *((int32_t *)param) = 1;
263 return HDF_FAILURE;
264 }
265 OsalMemFree(config);
266 config = NULL;
267 HDF_LOGD("I3cTestSetConfig: done!");
268 *((int32_t *)param) = 1;
269
270 return HDF_SUCCESS;
271 }
272
I3cTestGetConfig(void * param)273 static int32_t I3cTestGetConfig(void *param)
274 {
275 struct I3cTester *tester = NULL;
276 struct I3cConfig *config = NULL;
277 int32_t ret;
278
279 tester = I3cTesterGet();
280 if (tester == NULL) {
281 HDF_LOGE("I3cTestGetConfig: get tester fail!");
282 *((int32_t *)param) = 1;
283 return HDF_ERR_INVALID_OBJECT;
284 }
285
286 config = (struct I3cConfig*)OsalMemCalloc(sizeof(*config));
287 if (config == NULL) {
288 HDF_LOGE("I3cTestGetConfig: memcalloc fail!");
289 *((int32_t *)param) = 1;
290 return HDF_ERR_MALLOC_FAIL;
291 }
292
293 ret = I3cGetConfig(tester->handle, config);
294 if (ret != HDF_SUCCESS) {
295 HDF_LOGE("I3cTestGetConfig: Get config fail!, busId = %hu!", tester->config.busId);
296 OsalMemFree(config);
297 *((int32_t *)param) = 1;
298 return HDF_FAILURE;
299 }
300
301 OsalMemFree(config);
302 config = NULL;
303 *((int32_t *)param) = 1;
304 HDF_LOGD("I3cTestGetConfig: done!");
305
306 return HDF_SUCCESS;
307 }
308
TestI3cIbiFunc(DevHandle handle,uint16_t addr,struct I3cIbiData data)309 static int32_t TestI3cIbiFunc(DevHandle handle, uint16_t addr, struct I3cIbiData data)
310 {
311 (void)handle;
312 (void)addr;
313 HDF_LOGD("TestI3cIbiFunc: %.16s", (char *)data.buf);
314
315 return HDF_SUCCESS;
316 }
317
I3cTestRequestIbi(void * param)318 static int32_t I3cTestRequestIbi(void *param)
319 {
320 struct I3cTester *tester = NULL;
321 int32_t ret;
322
323 tester = I3cTesterGet();
324 if (tester == NULL) {
325 HDF_LOGE("I3cTestRequestIbi: get tester fail!");
326 *((int32_t *)param) = 1;
327 return HDF_ERR_INVALID_OBJECT;
328 }
329
330 ret = I3cRequestIbi(tester->handle, tester->config.devAddr, TestI3cIbiFunc, I3C_TEST_IBI_PAYLOAD);
331 if (ret != HDF_SUCCESS) {
332 *((int32_t *)param) = 1;
333 HDF_LOGE("I3cTestRequestIbi: request IBI fail!, busId = %hu!", tester->config.busId);
334 return HDF_FAILURE;
335 }
336 *((int32_t *)param) = 1;
337 HDF_LOGD("I3cTestRequestIbi: done!");
338
339 return HDF_SUCCESS;
340 }
341
I3cTestFreeIbi(void * param)342 static int32_t I3cTestFreeIbi(void *param)
343 {
344 struct I3cTester *tester = NULL;
345 int32_t ret;
346
347 tester = I3cTesterGet();
348 if (tester == NULL) {
349 HDF_LOGE("I3cTestFreeIbi: get tester fail!");
350 *((int32_t *)param) = 1;
351 return HDF_ERR_INVALID_OBJECT;
352 }
353
354 ret = I3cFreeIbi(tester->handle, tester->config.devAddr);
355 if (ret != HDF_SUCCESS) {
356 HDF_LOGE("I3cTestFreeIbi: free IBI fail, busId = %hu!", tester->config.busId);
357 *((int32_t *)param) = 1;
358 return ret;
359 }
360 *((int32_t *)param) = 1;
361 HDF_LOGD("I3cTestFreeIbi: done!");
362
363 return HDF_SUCCESS;
364 }
365
I3cTestStartThread(struct OsalThread * thread1,struct OsalThread * thread2,const int32_t * count1,const int32_t * count2)366 static int32_t I3cTestStartThread(struct OsalThread *thread1, struct OsalThread *thread2,
367 const int32_t *count1, const int32_t *count2)
368 {
369 int32_t ret;
370 uint32_t time = 0;
371 struct OsalThreadParam cfg1;
372 struct OsalThreadParam cfg2;
373
374 if (memset_s(&cfg1, sizeof(cfg1), 0, sizeof(cfg1)) != EOK ||
375 memset_s(&cfg2, sizeof(cfg2), 0, sizeof(cfg2)) != EOK) {
376 HDF_LOGE("I3cTestStartThread: memset_s fail!");
377 return HDF_ERR_IO;
378 }
379 cfg1.name = "I3cTestThread-1";
380 cfg2.name = "I3cTestThread-2";
381 cfg1.priority = cfg2.priority = OSAL_THREAD_PRI_DEFAULT;
382 cfg1.stackSize = cfg2.stackSize = I3C_TEST_STACK_SIZE;
383
384 ret = OsalThreadStart(thread1, &cfg1);
385 if (ret != HDF_SUCCESS) {
386 HDF_LOGE("I3cTestStartThread: start test thread1 fail, ret: %d!", ret);
387 return ret;
388 }
389
390 ret = OsalThreadStart(thread2, &cfg2);
391 if (ret != HDF_SUCCESS) {
392 HDF_LOGE("I3cTestStartThread: start test thread2 fail, ret: %d!", ret);
393 }
394
395 while (*count1 == 0 || *count2 == 0) {
396 HDF_LOGV("I3cTestStartThread: waitting testing I3c thread finish...");
397 OsalMSleep(I3C_TEST_WAIT_TIMES);
398 time++;
399 if (time > I3C_TEST_WAIT_TIMEOUT) {
400 break;
401 }
402 }
403 return ret;
404 }
405
I3cTestThreadFunc(OsalThreadEntry func)406 static int32_t I3cTestThreadFunc(OsalThreadEntry func)
407 {
408 int32_t ret;
409 struct OsalThread thread1;
410 struct OsalThread thread2;
411 int32_t count1 = 0;
412 int32_t count2 = 0;
413
414 ret = OsalThreadCreate(&thread1, func, (void *)&count1);
415 if (ret != HDF_SUCCESS) {
416 HDF_LOGE("I3cTestThreadFunc: create test thread1 fail, ret: %d!", ret);
417 return ret;
418 }
419
420 ret = OsalThreadCreate(&thread2, func, (void *)&count2);
421 if (ret != HDF_SUCCESS) {
422 HDF_LOGE("I3cTestThreadFunc: create test thread2 fail, ret: %d!", ret);
423 (void)OsalThreadDestroy(&thread1);
424 return ret;
425 }
426
427 ret = I3cTestStartThread(&thread1, &thread2, &count1, &count2);
428 if (ret != HDF_SUCCESS) {
429 HDF_LOGE("I3cTestThreadFunc: test start thread fail, ret: %d!", ret);
430 }
431
432 (void)OsalThreadDestroy(&thread1);
433 (void)OsalThreadDestroy(&thread2);
434 return ret;
435 }
436
437 static struct I3cTestEntry g_multiThreadEntry[] = {
438 { I3C_TEST_CMD_TRANSFER, I3cTestTransfer, "I3cTestTransfer" },
439 { I3C_TEST_CMD_SET_CONFIG, I3cTestSetConfig, "I3cTestSetConfig" },
440 { I3C_TEST_CMD_GET_CONFIG, I3cTestGetConfig, "I3cTestGetConfig" },
441 { I3C_TEST_CMD_REQUEST_IBI, I3cTestRequestIbi, "I3cTestRequestIbi" },
442 { I3C_TEST_CMD_FREE_IBI, I3cTestFreeIbi, "I3cTestFreeIbi" },
443 };
444
I3cTestMultiThread(void * param)445 static int32_t I3cTestMultiThread(void *param)
446 {
447 uint32_t i;
448 int32_t ret;
449
450 for (i = 0; i < sizeof(g_multiThreadEntry) / sizeof(g_multiThreadEntry[0]); i++) {
451 if (g_multiThreadEntry[i].func == NULL) {
452 HDF_LOGE("I3cTestMultiThread: func is null!");
453 return HDF_FAILURE;
454 }
455 HDF_LOGI("I3cTestMultiThread: =================calling func %u =========================", i);
456 ret = I3cTestThreadFunc((OsalThreadEntry)g_multiThreadEntry[i].func);
457 if (ret != HDF_SUCCESS) {
458 HDF_LOGE("I3cTestMultiThread: Multithreading test fail: %u", i);
459 return ret;
460 }
461 }
462 *((int32_t *)param) = 1;
463
464 return HDF_SUCCESS;
465 }
466
I3cTestReliability(void * param)467 static int32_t I3cTestReliability(void *param)
468 {
469 struct I3cTester *tester = NULL;
470 struct I3cConfig *config = NULL;
471
472 (void)param;
473 tester = I3cTesterGet();
474 if (tester == NULL || tester->handle == NULL) {
475 HDF_LOGE("I3cTestReliability: tester or handle is null!");
476 return HDF_ERR_INVALID_OBJECT;
477 }
478 config = (struct I3cConfig *)OsalMemCalloc(sizeof(*config));
479 if (config == NULL) {
480 HDF_LOGE("I3cTestReliability: config is null!");
481 return HDF_ERR_MALLOC_FAIL;
482 }
483 config->busMode = I3C_BUS_HDR_MODE;
484 config->curHost = NULL;
485 // invalid handle
486 (void)I3cTransfer(NULL, g_msgs, 1, I3C_MODE);
487 (void)I3cSetConfig(NULL, config);
488 (void)I3cGetConfig(NULL, config);
489 (void)I3cRequestIbi(NULL, tester->config.devAddr, TestI3cIbiFunc, I3C_TEST_IBI_PAYLOAD);
490 (void)I3cFreeIbi(NULL, tester->config.devAddr);
491 // Invalid msg
492 (void)I3cTransfer(tester->handle, NULL, 1, I3C_MODE);
493 // Invalid config
494 (void)I3cSetConfig(tester->handle, NULL);
495 (void)I3cGetConfig(tester->handle, NULL);
496 // Invalid function
497 (void)I3cRequestIbi(tester->handle, tester->config.devAddr, NULL, I3C_TEST_IBI_PAYLOAD);
498 // Invalid number
499 (void)I3cTransfer(tester->handle, g_msgs, -1, I3C_MODE);
500 HDF_LOGD("I3cTestReliability: done!");
501
502 return HDF_SUCCESS;
503 }
504
505 static struct I3cTestEntry g_entry[] = {
506 { I3C_TEST_CMD_TRANSFER, I3cTestTransfer, "I3cTestTransfer" },
507 { I3C_TEST_CMD_SET_CONFIG, I3cTestSetConfig, "I3cTestSetConfig" },
508 { I3C_TEST_CMD_GET_CONFIG, I3cTestGetConfig, "I3cTestGetConfig" },
509 { I3C_TEST_CMD_REQUEST_IBI, I3cTestRequestIbi, "I3cTestRequestIbi" },
510 { I3C_TEST_CMD_FREE_IBI, I3cTestFreeIbi, "I3cTestFreeIbi" },
511 { I3C_TEST_CMD_MULTI_THREAD, I3cTestMultiThread, "I3cTestMultiThread" },
512 { I3C_TEST_CMD_RELIABILITY, I3cTestReliability, "I3cTestReliability" },
513 { I3C_TEST_CMD_SETUP_ALL, I3cTestSetUpAll, "I3cTestSetUpAll" },
514 { I3C_TEST_CMD_TEARDOWN_ALL, I3cTestTearDownAll, "I3cTestTearDownAll" },
515 };
516
I3cTestExecute(int cmd)517 int32_t I3cTestExecute(int cmd)
518 {
519 uint32_t i;
520 int32_t count;
521 int32_t ret = HDF_ERR_NOT_SUPPORT;
522
523 if (cmd > I3C_TEST_CMD_MAX) {
524 HDF_LOGE("I3cTestExecute: invalid cmd: %d!", cmd);
525 ret = HDF_ERR_NOT_SUPPORT;
526 HDF_LOGI("[I3cTestExecute][======cmd:%d====ret:%d======]", cmd, ret);
527 return ret;
528 }
529
530 for (i = 0; i < sizeof(g_entry) / sizeof(g_entry[0]); i++) {
531 if (g_entry[i].cmd != cmd || g_entry[i].func == NULL) {
532 continue;
533 }
534 count = 0;
535 ret = g_entry[i].func((void *)&count);
536 break;
537 }
538
539 HDF_LOGI("[I3cTestExecute][======cmd:%d====ret:%d======]", cmd, ret);
540 return ret;
541 }
542