diff --git a/userspace/units/posix/timers/posix-timers.c b/userspace/units/posix/timers/posix-timers.c index 9194ea621..90fbccd89 100644 --- a/userspace/units/posix/timers/posix-timers.c +++ b/userspace/units/posix/timers/posix-timers.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2019-2020, NVIDIA CORPORATION. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), @@ -27,6 +27,7 @@ #include #include +#include #include "posix-timers.h" struct test_timer_args { @@ -207,6 +208,20 @@ int test_timer_duration(struct unit_module *m, unit_return_fail(m, "Timer init failed %d\n", ret); } + /* + * Timer should not be expired. + * However, test execution may not be atomic and might get preempted. + * In that scenario, the return value might not be zero. + * Reading timer value also takes many cycles, hence it is difficult + * to confirm if timer timedout before set timeout value. + * So, here we print an error message if return value is not zero. + */ + ret = nvgpu_timeout_expired(&test_timeout); + if (ret != 0) { + unit_err(m, + "Duration timer expired when not expected %d\n", ret); + } + /* Sleep for TEST_TIMER_DURATION */ usleep((TEST_TIMER_DURATION * 1000)); @@ -227,6 +242,60 @@ int test_timer_duration(struct unit_module *m, return UNIT_SUCCESS; } +int test_timer_fault_injection(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret; + struct nvgpu_posix_fault_inj *timers_fi = + nvgpu_timers_get_fault_injection(); + + memset(&test_timeout, 0, sizeof(struct nvgpu_timeout)); + + ret = nvgpu_timeout_init(g, &test_timeout, + TEST_TIMER_DURATION, + NVGPU_TIMER_CPU_TIMER); + + if (ret != 0) { + unit_return_fail(m, "Timer init failed %d\n", ret); + } + + nvgpu_posix_enable_fault_injection(timers_fi, true, 1); + + /* Timer should not be expired */ + ret = nvgpu_timeout_expired(&test_timeout); + if (ret != 0) { + unit_return_fail(m, + "Fault injected timer expired when not expected %d\n", + ret); + } + + /* Timer should be expired */ + ret = nvgpu_timeout_expired(&test_timeout); + if (ret != -ETIMEDOUT) { + unit_return_fail(m, + "Fault injected timer expired when not expected %d\n", + ret); + } + + nvgpu_posix_enable_fault_injection(timers_fi, false, 0); + + /* Sleep for TEST_TIMER_DURATION */ + usleep((TEST_TIMER_DURATION * 1000)); + + do { + usleep(10); + ret = nvgpu_timeout_expired(&test_timeout); + + } while (ret == 0); + + if (ret != -ETIMEDOUT) { + unit_return_fail(m, "Fault injected timer not expired %d\n", + ret); + } + + return UNIT_SUCCESS; +} + int test_timer_delay(struct unit_module *m, struct gk20a *g, void *args) { @@ -336,6 +405,7 @@ struct unit_module_test posix_timers_tests[] = { UNIT_TEST(init_err, test_timer_init_err, NULL, 0), UNIT_TEST(counter, test_timer_counter, NULL, 0), UNIT_TEST(duration, test_timer_duration, NULL, 0), + UNIT_TEST(fault_injection, test_timer_fault_injection, NULL, 0), UNIT_TEST(delay, test_timer_delay, NULL, 0), UNIT_TEST(msleep, test_timer_msleep, NULL, 0), UNIT_TEST(hr_cycles, test_timer_hrtimestamp, NULL, 0), diff --git a/userspace/units/posix/timers/posix-timers.h b/userspace/units/posix/timers/posix-timers.h index e1a501a00..f6368e0b5 100644 --- a/userspace/units/posix/timers/posix-timers.h +++ b/userspace/units/posix/timers/posix-timers.h @@ -142,20 +142,54 @@ int test_timer_counter(struct unit_module *m, * 1) Reset the global nvgpu_timeout structure to all 0s. * 2) Initialise the timeout structure. * 3) Check the return value for error. - * 4) Sleep for the required duration + 500ms to ensure the timer expires. - * 5) Check for the timer status. - * 6) Reconfirm the timer status. + * 4) Check for timer status. Confirm that timer has not expired. + * 5) Sleep for the required duration + 500ms to ensure the timer expires. + * 6) Check for the timer status. + * 7) Reconfirm the timer status. * * Output: * Test returns PASS if the timer expires after the programmed * duration. - * Test returns FAIL if the initialisation routine returns error or if - * the timer does not expire even after the programmed duration. + * Test returns FAIL if initialisation routine returns error, if the timer + * does not expire after programmed duration or if timer expires before + * programmed duration. * */ int test_timer_duration(struct unit_module *m, struct gk20a *g, void *args); +/** + * Test specification for test_timer_duration + * + * Description: Test fault injection timer functionality. + * + * Test Type: Feature + * + * Input: + * 1) Global nvgpu_timeout structure instance. + * 2) Global defines for flag and duration parameters. + * + * Steps: + * 1) Reset the global nvgpu_timeout structure to all 0s. + * 2) Initialise the timeout structure. + * 3) Check the return value for error. + * 4) Initialize fault injection counter and enable fault injection. + * 5) Check for the timer status. Confirm that return value is 0. + * 6) Check for the timer status. Confirm that return value is 0. + * 7) Sleep for the required duration + 500ms to ensure the timer expires. + * 8) Check for the timer status. + * + * Output: + * Test returns PASS if the timer expires after the programmed + * duration. + * Test returns FAIL if the initialisation routine returns error, if function + * returns non-zero value when fault injection is enabled or if the timer does + * not expire even after the programmed duration. + * + */ +int test_timer_fault_injection(struct unit_module *m, + struct gk20a *g, void *args); + /** * Test specification for test_timer_delay *