1 /*
2 * Copyright (c) 2020-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 "i2c_test.h"
10 #include "hdf_base.h"
11 #include "hdf_io_service_if.h"
12 #include "hdf_log.h"
13 #include "i2c_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 i2c_test
20
21 #define I2C_TEST_8BIT 8
22 #define I2C_TEST_MSG_NUM 2
23 #define I2C_TEST_BUF_SIZE_MAX 128
24 #define I2C_TEST_REG_LEN 2
25 #define I2C_TEST_MLTTHD_TIMES 1000
26 #define I2C_TEST_STACK_SIZE (1024 * 100)
27 #define I2C_TEST_WAIT_TIMES 200
28 #define I2C_TEST_WAIT_TIMEOUT 40
29
30 static struct I2cMsg g_msgs[I2C_TEST_MSG_NUM];
31 static uint8_t *g_buf;
32 static uint8_t g_regs[I2C_TEST_REG_LEN];
33
I2cTestGetConfig(struct I2cTestConfig * config)34 static int32_t I2cTestGetConfig(struct I2cTestConfig *config)
35 {
36 int32_t ret;
37 struct HdfSBuf *reply = NULL;
38 struct HdfIoService *service = NULL;
39 const void *buf = NULL;
40 uint32_t len;
41
42 HDF_LOGD("I2cTestGetConfig: enter!");
43 service = HdfIoServiceBind("I2C_TEST");
44 if (service == NULL) {
45 return HDF_ERR_NOT_SUPPORT;
46 }
47
48 reply = HdfSbufObtain(sizeof(*config) + sizeof(uint64_t));
49 if (reply == NULL) {
50 HDF_LOGE("I2cTestGetConfig: failed to obtain reply!");
51 HdfIoServiceRecycle(service);
52 return HDF_ERR_MALLOC_FAIL;
53 }
54
55 ret = service->dispatcher->Dispatch(&service->object, 0, NULL, reply);
56 if (ret != HDF_SUCCESS) {
57 HDF_LOGE("I2cTestGetConfig: remote dispatch fail:%d", ret);
58 ret = HDF_ERR_IO;
59 goto EXIT;
60 }
61
62 if (!HdfSbufReadBuffer(reply, &buf, &len)) {
63 HDF_LOGE("I2cTestGetConfig: read buf fail!");
64 ret = HDF_ERR_IO;
65 goto EXIT;
66 }
67
68 if (len != sizeof(*config)) {
69 ret = HDF_ERR_IO;
70 goto EXIT;
71 }
72
73 if (memcpy_s(config, sizeof(*config), buf, sizeof(*config)) != EOK) {
74 HDF_LOGE("I2cTestGetConfig: memcpy buf fail!");
75 ret = HDF_ERR_IO;
76 goto EXIT;
77 }
78 ret = HDF_SUCCESS;
79 EXIT:
80 HdfSbufRecycle(reply);
81 HDF_LOGD("I2cTestGetConfig: exit!");
82 HdfIoServiceRecycle(service);
83 return ret;
84 }
85
I2cTesterGet(void)86 static struct I2cTester *I2cTesterGet(void)
87 {
88 int32_t ret;
89 static struct I2cTester tester;
90 static bool hasInit = false;
91
92 if (hasInit) {
93 return &tester;
94 }
95
96 ret = I2cTestGetConfig(&tester.config);
97 if (ret != HDF_SUCCESS) {
98 HDF_LOGE("I2cTesterGet: read config fail:%d", ret);
99 return NULL;
100 }
101
102 tester.handle = I2cOpen(tester.config.busNum);
103 if (tester.handle == NULL) {
104 HDF_LOGE("I2cTesterGet: open i2cBus:%u fail!", tester.config.busNum);
105 return NULL;
106 }
107
108 hasInit = true;
109 return &tester;
110 }
111
I2cTestMallocBuf(struct I2cTester * tester)112 static int32_t I2cTestMallocBuf(struct I2cTester *tester)
113 {
114 struct I2cTestConfig *config = &tester->config;
115
116 if (g_buf == NULL) {
117 g_buf = OsalMemCalloc(config->bufSize);
118 if (g_buf == NULL) {
119 HDF_LOGE("I2cTestMallocBuf: malloc buf fail!");
120 return HDF_ERR_MALLOC_FAIL;
121 }
122 }
123
124 g_regs[0] = (uint8_t)config->regAddr;
125 if (config->regLen > 1) {
126 g_regs[1] = g_regs[0];
127 g_regs[0] = (uint8_t)(config->regAddr >> I2C_TEST_8BIT);
128 }
129
130 g_msgs[0].addr = config->devAddr;
131 g_msgs[0].flags = 0;
132 g_msgs[0].len = config->regLen;
133 g_msgs[0].buf = g_regs;
134
135 g_msgs[1].addr = config->devAddr;
136 g_msgs[1].flags = I2C_FLAG_READ;
137 g_msgs[1].len = config->bufSize;
138 g_msgs[1].buf = g_buf;
139
140 return HDF_SUCCESS;
141 }
142
I2cTestSetUpAll(void)143 static int32_t I2cTestSetUpAll(void)
144 {
145 struct I2cTester *tester = NULL;
146 struct I2cTestConfig *cfg = NULL;
147
148 HDF_LOGD("I2cTestSetUpAll: enter!");
149 tester = I2cTesterGet();
150 if (tester == NULL) {
151 HDF_LOGE("I2cTestSetUpAll: get tester fail!");
152 return HDF_ERR_INVALID_OBJECT;
153 }
154 tester->total = I2C_TEST_CMD_MAX;
155 tester->fails = 0;
156
157 cfg = &tester->config;
158 HDF_LOGE("I2cTestSetUpAll: test on bus:0x%x, addr:0x%x, reg:0x%x, reglen:0x%x, size:0x%x",
159 cfg->busNum, cfg->devAddr, cfg->regAddr, cfg->regLen, cfg->bufSize);
160 if (I2cTestMallocBuf(tester) != HDF_SUCCESS) {
161 HDF_LOGE("I2cTestSetUpAll: set up test case fail!");
162 }
163 HDF_LOGD("I2cTestSetUpAll: exit!");
164 return HDF_SUCCESS;
165 }
166
I2cTestTearDownAll(void)167 static int32_t I2cTestTearDownAll(void)
168 {
169 if (g_buf != NULL) {
170 OsalMemFree(g_buf);
171 g_buf = NULL;
172 }
173
174 return HDF_SUCCESS;
175 }
176
I2cTestSetUpSingle(void)177 static int32_t I2cTestSetUpSingle(void)
178 {
179 return HDF_SUCCESS;
180 }
181
I2cTestTearDownSingle(void)182 static int32_t I2cTestTearDownSingle(void)
183 {
184 return HDF_SUCCESS;
185 }
186
I2cTestTransfer(void)187 static int32_t I2cTestTransfer(void)
188 {
189 int32_t ret;
190 struct I2cTester *tester = NULL;
191
192 tester = I2cTesterGet();
193 if (tester == NULL || tester->handle == NULL) {
194 return HDF_ERR_INVALID_OBJECT;
195 }
196
197 /* transfer one write msg */
198 ret = I2cTransfer(tester->handle, g_msgs, 1);
199 if (ret != 1) {
200 HDF_LOGE("I2cTestTransfer: I2cTransfer(write) err:%d", ret);
201 return HDF_FAILURE;
202 }
203
204 /* transfer one read msg */
205 ret = I2cTransfer(tester->handle, g_msgs + 1, 1);
206 if (ret != 1) {
207 HDF_LOGE("I2cTestTransfer: I2cTransfer(read) err:%d", ret);
208 return HDF_FAILURE;
209 }
210
211 /* transfer two msgs including a read msg and a write msg */
212 ret = I2cTransfer(tester->handle, g_msgs, I2C_TEST_MSG_NUM);
213 if (ret != I2C_TEST_MSG_NUM) {
214 HDF_LOGE("I2cTestTransfer: I2cTransfer(mix) err:%d", ret);
215 return HDF_FAILURE;
216 }
217 return HDF_SUCCESS;
218 }
219
I2cTestThreadFunc(void * param)220 static int I2cTestThreadFunc(void *param)
221 {
222 int32_t i;
223 int32_t ret;
224 struct I2cTester *tester = NULL;
225
226 tester = I2cTesterGet();
227 if (tester == NULL || tester->handle == NULL) {
228 *((int32_t *)param) = 1;
229 return HDF_ERR_INVALID_OBJECT;
230 }
231
232 for (i = 0; i < I2C_TEST_MLTTHD_TIMES; i++) {
233 ret = I2cTransfer(tester->handle, g_msgs, I2C_TEST_MSG_NUM);
234 if (ret != I2C_TEST_MSG_NUM) {
235 #ifdef __USER__
236 HDF_LOGE("I2cTestThreadFunc: I2cTransfer-user err in multithread test, ret: %d", ret);
237 #else
238 HDF_LOGE("I2cTestThreadFunc: I2cTransfer-kerl err in multithread test, ret: %d", ret);
239 #endif
240 }
241 }
242
243 *((int32_t *)param) = 1;
244 return HDF_SUCCESS;
245 }
246
I2cTestStartThread(struct OsalThread * thread1,struct OsalThread * thread2,const int32_t * count1,const int32_t * count2)247 static int32_t I2cTestStartThread(struct OsalThread *thread1, struct OsalThread *thread2,
248 const int32_t *count1, const int32_t *count2)
249 {
250 int32_t ret;
251 uint32_t time = 0;
252 struct OsalThreadParam cfg1;
253 struct OsalThreadParam cfg2;
254
255 if (memset_s(&cfg1, sizeof(cfg1), 0, sizeof(cfg1)) != EOK ||
256 memset_s(&cfg2, sizeof(cfg2), 0, sizeof(cfg2)) != EOK) {
257 HDF_LOGE("I2cTestStartThread: memset_s fail!");
258 return HDF_ERR_IO;
259 }
260 cfg1.name = "I2cTestThread-1";
261 cfg2.name = "I2cTestThread-2";
262 cfg1.priority = cfg2.priority = OSAL_THREAD_PRI_DEFAULT;
263 cfg1.stackSize = cfg2.stackSize = I2C_TEST_STACK_SIZE;
264
265 ret = OsalThreadStart(thread1, &cfg1);
266 if (ret != HDF_SUCCESS) {
267 HDF_LOGE("I2cTestStartThread: start test thread1 fail, ret: %d!", ret);
268 return ret;
269 }
270
271 ret = OsalThreadStart(thread2, &cfg2);
272 if (ret != HDF_SUCCESS) {
273 HDF_LOGE("I2cTestStartThread: start test thread2 fail, ret: %d!", ret);
274 }
275
276 while (*count1 == 0 || *count2 == 0) {
277 HDF_LOGD("I2cTestStartThread: waitting testing thread finish...");
278 OsalMSleep(I2C_TEST_WAIT_TIMES);
279 time++;
280 if (time > I2C_TEST_WAIT_TIMEOUT) {
281 break;
282 }
283 }
284 return ret;
285 }
286
I2cTestMultiThread(void)287 static int32_t I2cTestMultiThread(void)
288 {
289 int32_t ret;
290 struct OsalThread thread1;
291 struct OsalThread thread2;
292 int32_t count1 = 0;
293 int32_t count2 = 0;
294
295 ret = OsalThreadCreate(&thread1, (OsalThreadEntry)I2cTestThreadFunc, (void *)&count1);
296 if (ret != HDF_SUCCESS) {
297 HDF_LOGE("I2cTestMultiThread: create test thread1 fail, ret: %d!", ret);
298 return ret;
299 }
300
301 ret = OsalThreadCreate(&thread2, (OsalThreadEntry)I2cTestThreadFunc, (void *)&count2);
302 if (ret != HDF_SUCCESS) {
303 (void)OsalThreadDestroy(&thread1);
304 HDF_LOGE("I2cTestMultiThread: create test thread2 fail, ret: %d!", ret);
305 return ret;
306 }
307
308 ret = I2cTestStartThread(&thread1, &thread2, &count1, &count2);
309 if (ret != HDF_SUCCESS) {
310 HDF_LOGE("I2cTestMultiThread: test start thread fail, ret: %d!", ret);
311 }
312
313 (void)OsalThreadDestroy(&thread1);
314 (void)OsalThreadDestroy(&thread2);
315 return ret;
316 }
317
I2cTestReliability(void)318 static int32_t I2cTestReliability(void)
319 {
320 struct I2cTester *tester = NULL;
321
322 HDF_LOGD("I2cTestReliability: test dfr for I2cTransfer ...");
323 tester = I2cTesterGet();
324 if (tester == NULL || tester->handle == NULL) {
325 return HDF_ERR_INVALID_OBJECT;
326 }
327 /* invalid device handle */
328 (void)I2cTransfer(NULL, g_msgs, I2C_TEST_MSG_NUM);
329 /* invalid device msgs */
330 (void)I2cTransfer(tester->handle, NULL, I2C_TEST_MSG_NUM);
331 /* invalid device msg number */
332 (void)I2cTransfer(tester->handle, g_msgs, -1);
333
334 return HDF_SUCCESS;
335 }
336
I2cTestPeformance(void)337 static int32_t I2cTestPeformance(void)
338 {
339 #ifdef __LITEOS__
340 // liteos the accuracy of the obtained time is too large and inaccurate.
341 return HDF_SUCCESS;
342 #endif
343 uint64_t startMs;
344 uint64_t endMs;
345 uint64_t useTime; // ms
346 struct I2cTester *tester = NULL;
347 DevHandle handle = NULL;
348
349 tester = I2cTesterGet();
350 if (tester == NULL || tester->handle == NULL) {
351 HDF_LOGE("I2cTestPeformance: get tester fail!");
352 return HDF_ERR_INVALID_OBJECT;
353 }
354
355 startMs = OsalGetSysTimeMs();
356 handle = I2cOpen(tester->config.busNum);
357 endMs = OsalGetSysTimeMs();
358
359 if (handle != NULL) {
360 useTime = endMs - startMs;
361 HDF_LOGI("I2cTestPeformance: ----->interface performance test:[start - end] < 1ms[%s]\r\n",
362 useTime < 1 ? "yes" : "no");
363 I2cClose(handle);
364 return HDF_SUCCESS;
365 }
366
367 return HDF_FAILURE;
368 }
369
I2cMiniWriteReadTest(void)370 static int32_t I2cMiniWriteReadTest(void)
371 {
372 #ifdef __KERNEL__
373 struct I2cTester *tester = NULL;
374 uint8_t buf;
375 int32_t ret;
376
377 tester = I2cTesterGet();
378 if (tester == NULL || tester->handle == NULL) {
379 HDF_LOGE("I2cMiniWriteReadTest: get tester fail!");
380 return HDF_ERR_INVALID_OBJECT;
381 }
382
383 ret = I2cWrite(tester->handle, &buf, sizeof(buf));
384 if (ret != HDF_SUCCESS) {
385 HDF_LOGE("I2cMiniWriteReadTest: i2c write fail, ret: %d!", ret);
386 return ret;
387 }
388
389 HDF_LOGI("I2cMiniWriteReadTest: i2c write test done, then test i2c read!");
390 ret = I2cRead(tester->handle, &buf, sizeof(buf));
391 if (ret != HDF_SUCCESS) {
392 HDF_LOGE("I2cMiniWriteReadTest: i2c read fail, ret: %d!", ret);
393 return ret;
394 }
395 #endif
396 HDF_LOGI("I2cMiniWriteReadTest: all test done!");
397 return HDF_SUCCESS;
398 }
399
400 struct I2cTestEntry {
401 int cmd;
402 int32_t (*func)(void);
403 const char *name;
404 };
405
406 static struct I2cTestEntry g_entry[] = {
407 { I2C_TEST_CMD_TRANSFER, I2cTestTransfer, "I2cTestTransfer" },
408 { I2C_TEST_CMD_MULTI_THREAD, I2cTestMultiThread, "I2cTestMultiThread" },
409 { I2C_TEST_CMD_RELIABILITY, I2cTestReliability, "I2cTestReliability" },
410 { I2C_TEST_CMD_PERFORMANCE, I2cTestPeformance, "I2cTestPeformance" },
411 { I2C_TEST_CMD_SETUP_ALL, I2cTestSetUpAll, "I2cTestSetUpAll" },
412 { I2C_TEST_CMD_TEARDOWN_ALL, I2cTestTearDownAll, "I2cTestTearDownAll" },
413 { I2C_TEST_CMD_SETUP_SINGLE, I2cTestSetUpSingle, "I2cTestSetUpSingle" },
414 { I2C_TEST_CMD_TEARDOWN_SINGLE, I2cTestTearDownSingle, "I2cTestTearDownSingle" },
415 { I2C_MINI_WRITE_READ_TEST, I2cMiniWriteReadTest, "I2cMiniWriteReadTest" },
416 };
417
I2cTestExecute(int cmd)418 int32_t I2cTestExecute(int cmd)
419 {
420 uint32_t i;
421 int32_t ret = HDF_ERR_NOT_SUPPORT;
422
423 if (cmd > I2C_TEST_CMD_MAX) {
424 HDF_LOGE("I2cTestExecute: invalid cmd:%d", cmd);
425 ret = HDF_ERR_NOT_SUPPORT;
426 HDF_LOGE("[I2cTestExecute][======cmd:%d====ret:%d======]", cmd, ret);
427 return ret;
428 }
429
430 for (i = 0; i < sizeof(g_entry) / sizeof(g_entry[0]); i++) {
431 if (g_entry[i].cmd != cmd || g_entry[i].func == NULL) {
432 continue;
433 }
434 ret = g_entry[i].func();
435 break;
436 }
437
438 HDF_LOGE("[I2cTestExecute][======cmd:%d====ret:%d======]", cmd, ret);
439 return ret;
440 }
441
I2cTestExecuteAll(void)442 void I2cTestExecuteAll(void)
443 {
444 int32_t i;
445 int32_t ret;
446 int32_t fails = 0;
447
448 /* setup env for all test cases */
449 (void)I2cTestExecute(I2C_TEST_CMD_SETUP_ALL);
450
451 for (i = 0; i <= I2C_TEST_CMD_RELIABILITY; i++) {
452 ret = I2cTestExecute(i);
453 fails += (ret != HDF_SUCCESS) ? 1 : 0;
454 }
455
456 /* teardown env for all test cases */
457 (void)I2cTestExecute(I2C_TEST_CMD_TEARDOWN_ALL);
458
459 HDF_LOGE("I2cTestExecuteALL: **********PASS:%d FAIL:%d************\n\n",
460 I2C_TEST_CMD_RELIABILITY + 1 - fails, fails);
461 }
462