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