From 966938d3e60ada932e01cc8d02989a17a22260d0 Mon Sep 17 00:00:00 2001 From: ajesh Date: Fri, 28 May 2021 21:11:27 +0300 Subject: [PATCH] gpu: nvgpu: update queue unit tests Update the unit tests for Posix queue implementation. Add new tests to check the boundary values and modify some of the existing tests according to the changes in queue implementation. JIRA NVGPU-6908 Change-Id: Ie216e1281ca0f354c66c458830ca1ac2193fddb9 Signed-off-by: ajesh Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2536556 (cherry picked from commit 9a528c13093314296b928720d8f8ace3a5ddaf8a) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2536970 Tested-by: mobile promotions Reviewed-by: mobile promotions --- libs/dgpu/libnvgpu-drv-dgpu_safe.export | 1 + libs/igpu/libnvgpu-drv-igpu_safe.export | 1 + userspace/units/posix/queue/posix-queue.c | 117 +++++++++++++++++++--- userspace/units/posix/queue/posix-queue.h | 116 ++++++++++++++------- 4 files changed, 186 insertions(+), 49 deletions(-) diff --git a/libs/dgpu/libnvgpu-drv-dgpu_safe.export b/libs/dgpu/libnvgpu-drv-dgpu_safe.export index a7cf01904..0912d3a87 100644 --- a/libs/dgpu/libnvgpu-drv-dgpu_safe.export +++ b/libs/dgpu/libnvgpu-drv-dgpu_safe.export @@ -642,6 +642,7 @@ nvgpu_queue_in_locked nvgpu_queue_out nvgpu_queue_out_locked nvgpu_queue_out_get_fault_injection +nvgpu_queue_available nvgpu_preempt_channel nvgpu_preempt_get_timeout nvgpu_preempt_poll_tsg_on_pbdma diff --git a/libs/igpu/libnvgpu-drv-igpu_safe.export b/libs/igpu/libnvgpu-drv-igpu_safe.export index f0f7e8192..418f4e79c 100644 --- a/libs/igpu/libnvgpu-drv-igpu_safe.export +++ b/libs/igpu/libnvgpu-drv-igpu_safe.export @@ -659,6 +659,7 @@ nvgpu_queue_in_locked nvgpu_queue_out nvgpu_queue_out_locked nvgpu_queue_out_get_fault_injection +nvgpu_queue_available nvgpu_preempt_channel nvgpu_preempt_get_timeout nvgpu_preempt_poll_tsg_on_pbdma diff --git a/userspace/units/posix/queue/posix-queue.c b/userspace/units/posix/queue/posix-queue.c index ddf72ecf4..f2cd3f47a 100644 --- a/userspace/units/posix/queue/posix-queue.c +++ b/userspace/units/posix/queue/posix-queue.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020-2021, 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"), @@ -98,6 +98,14 @@ int test_nvgpu_queue_alloc_and_free(struct unit_module *m, struct gk20a *g, } nvgpu_queue_free(&q); + ret = nvgpu_queue_alloc(&q, (unsigned int)INT32_MAX); + if (ret != 0) { + err = UNIT_FAIL; + unit_err(m, "%d. test_queue_alloc failed err=%d\n", __LINE__, + ret); + goto fail; + } + nvgpu_queue_free(&q); fail: return err; } @@ -119,9 +127,10 @@ int test_nvgpu_queue_in(struct unit_module *m, struct gk20a *g, void *args) goto fail; } +#ifdef CONFIG_NVGPU_NON_FUSA /* Enqueue message of length BUF_LEN */ ret = nvgpu_queue_in(&q, buf, BUF_LEN); - if (ret != BUF_LEN) { + if (ret != 0) { err = UNIT_FAIL; unit_err(m, "%d. queue_in failed err=%d\n", __LINE__, ret); goto fail; @@ -134,12 +143,12 @@ int test_nvgpu_queue_in(struct unit_module *m, struct gk20a *g, void *args) q.in = BUF_LEN; q.out = BUF_LEN; ret = nvgpu_queue_in(&q, buf, BUF_LEN); - if (ret != BUF_LEN) { + if (ret != 0) { err = UNIT_FAIL; unit_err(m, "%d. queue_in failed err=%d\n", __LINE__, ret); goto fail; } - +#endif /* * Reset "in" and "out" indexes and enqueue message of length BUF_LEN * with the lock. @@ -147,7 +156,7 @@ int test_nvgpu_queue_in(struct unit_module *m, struct gk20a *g, void *args) q.in = 0; q.out = 0; ret = nvgpu_queue_in_locked(&q, buf, BUF_LEN, &lock); - if (ret != BUF_LEN) { + if (ret != 0) { err = UNIT_FAIL; unit_err(m, "%d. queue_in failed err=%d\n", __LINE__, ret); goto fail; @@ -161,6 +170,16 @@ int test_nvgpu_queue_in(struct unit_module *m, struct gk20a *g, void *args) goto fail; } + q.in = (UINT32_MAX - (BUF_LEN/2)); + q.out = q.in; + ret = nvgpu_queue_in_locked(&q, buf, BUF_LEN, &lock); + if (ret != 0) { + err = UNIT_FAIL; + unit_err(m, "%d. queue in failed err=%d\n", __LINE__, ret); + goto fail; + } + +#ifdef CONFIG_NVGPU_NON_FUSA /* Enqueue message of length BUF_LEN again (without lock) and expect * memory full. */ @@ -170,6 +189,7 @@ int test_nvgpu_queue_in(struct unit_module *m, struct gk20a *g, void *args) unit_err(m, "%d. queue_in failed err=%d\n", __LINE__, ret); goto fail; } +#endif fail: if (q.data != NULL) @@ -198,6 +218,7 @@ int test_nvgpu_queue_out(struct unit_module *m, struct gk20a *g, void *args) goto fail; } +#ifdef CONFIG_NVGPU_NON_FUSA /* Queue is empty. Dequeue message should return "-ENOMEM" */ ret = nvgpu_queue_out(&q, buf, BUF_LEN); if (ret != -ENOMEM) { @@ -205,6 +226,7 @@ int test_nvgpu_queue_out(struct unit_module *m, struct gk20a *g, void *args) unit_err(m, "%d. queue_out failed err=%d\n", __LINE__, ret); goto fail; } +#endif /* Queue is empty. Dequeue message with lock should return "-ENOMEM" */ ret = nvgpu_queue_out_locked(&q, buf, BUF_LEN, &lock); @@ -214,18 +236,19 @@ int test_nvgpu_queue_out(struct unit_module *m, struct gk20a *g, void *args) goto fail; } +#ifdef CONFIG_NVGPU_NON_FUSA /* * Advance "in" index by "BUF_LEN" and dequeue message of length BUF_LEN */ q.in = BUF_LEN; q.out = 0; ret = nvgpu_queue_out(&q, buf, BUF_LEN); - if (ret != BUF_LEN) { + if (ret != 0) { err = UNIT_FAIL; unit_err(m, "%d. queue_out failed err=%d\n", __LINE__, ret); goto fail; } - +#endif /* * Advance "in" index by "BUF_LEN" and dequeue message of length BUF_LEN * with the lock. @@ -233,24 +256,35 @@ int test_nvgpu_queue_out(struct unit_module *m, struct gk20a *g, void *args) q.in = BUF_LEN; q.out = 0; ret = nvgpu_queue_out_locked(&q, buf, BUF_LEN, &lock); - if (ret != BUF_LEN) { + if (ret != 0) { err = UNIT_FAIL; unit_err(m, "%d. queue_out failed err=%d\n", __LINE__, ret); goto fail; } +#ifdef CONFIG_NVGPU_NON_FUSA /* * Update "in" and "out" indexes and dequeue message of length BUF_LEN * such that we wrap around the Queue while dequeuing the message. */ - q.in = 1; - q.out = QUEUE_LEN_POW_2 -(BUF_LEN -1); + q.in = 0; + q.out = UINT32_MAX - BUF_LEN; ret = nvgpu_queue_out(&q, buf, BUF_LEN); - if (ret != BUF_LEN) { + if (ret != 0) { err = UNIT_FAIL; unit_err(m, "%d. queue_out failed err=%d\n", __LINE__, ret); goto fail; } +#endif + + q.in = 0; + q.out = UINT32_MAX - BUF_LEN; + ret = nvgpu_queue_out_locked(&q, buf, BUF_LEN, &lock); + if (ret != 0) { + err = UNIT_FAIL; + unit_err(m, "%d. queue in failed err=%d\n", __LINE__, ret); + goto fail; + } /* * Fault injection so that immediate call to nvgpu_queue_out_locked() @@ -274,11 +308,70 @@ fail: return err; } +int test_nvgpu_queue_available(struct unit_module *m, + struct gk20a *g, void *args) +{ + int ret = 0, err = UNIT_SUCCESS; + unsigned int count = 0; + struct nvgpu_queue q = {0}; + struct nvgpu_mutex lock; + + nvgpu_mutex_init(&lock); + + ret = nvgpu_queue_alloc(&q, QUEUE_LEN_POW_2); + if (ret != 0) { + err = UNIT_FAIL; + unit_err(m, "%d. queue_alloc failed err=%d\n", __LINE__, ret); + goto fail; + } + + q.out = 10; + q.in = 10; + count = nvgpu_queue_available(&q); + if (count != 0) { + err = UNIT_FAIL; + unit_err(m, "%d. incorrect queue available count=%d\n", + __LINE__, count); + goto fail; + } + + q.out = 0; + q.in = BUF_LEN; + count = nvgpu_queue_available(&q); + if (count != BUF_LEN) { + err = UNIT_FAIL; + unit_err(m, "%d. incorrect queue available count=%d\n", + __LINE__, count); + goto fail; + } + + /* + * This is to test the wrap around condition for IN index. + */ + q.out = UINT32_MAX - (BUF_LEN - 1); + q.in = 0; + count = nvgpu_queue_available(&q); + if (count != BUF_LEN) { + err = UNIT_FAIL; + unit_err(m, "%d. Invalid out index accepted, count=%d\n", + __LINE__, count); + goto fail; + } + +fail: + if (q.data != NULL) + free(q.data); + nvgpu_mutex_destroy(&lock); + + return err; +} + struct unit_module_test posix_queue_tests[] = { UNIT_TEST(nvgpu_queue_alloc_free, test_nvgpu_queue_alloc_and_free, NULL, 0), UNIT_TEST(nvgpu_queue_in, test_nvgpu_queue_in, NULL, 0), UNIT_TEST(nvgpu_queue_out, test_nvgpu_queue_out, NULL, 0), + UNIT_TEST(nvgpu_queue_available, test_nvgpu_queue_available, + NULL, 0), }; - UNIT_MODULE(posix_queue, posix_queue_tests, UNIT_PRIO_POSIX_TEST); diff --git a/userspace/units/posix/queue/posix-queue.h b/userspace/units/posix/queue/posix-queue.h index 109f4ae83..08d73136f 100644 --- a/userspace/units/posix/queue/posix-queue.h +++ b/userspace/units/posix/queue/posix-queue.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2020-2021, 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"), @@ -44,25 +44,30 @@ * * Steps: * - Pass NULL nvgpu_queue pointer as argument to nvgpu_queue_alloc() API and - * check that the API returns "-EINVAL" error. + * check that the API returns -EINVAL error. * - Pass zero size queue length as argument to nvgpu_queue_alloc() API and - * check that the API returns "-EINVAL" error. - * - Pass "INT64_MAX" size queue length as argument to nvgpu_queue_alloc() API - * and check that the API returns "-EINVAL" error. + * check that the API returns -EINVAL error. + * - Pass INT64_MAX size queue length as argument to nvgpu_queue_alloc() API + * and check that the API returns -EINVAL error. * - Inject fault so that immediate call to nvgpu_kzalloc() API would fail. * - Check that when the nvgpu_queue_alloc() API is called with valid arguments, - * it would fail by returning "-ENOMEM" error. + * it would fail by returning -ENOMEM error. * - Remove the injected fault in nvgpu_kzalloc() API. * - Pass below valid arguments to nvgpu_queue_alloc() API and check that the * API returns success. - * - Valid pointer to "struct nvgpu_queue" + * - Valid pointer to struct nvgpu_queue * - Queue size which is not power of 2 * - Free the allocated queue by caling nvgpu_queue_free() API. * - Pass below valid arguments to nvgpu_queue_alloc() API and check that the * API returns success. - * - Valid pointer to "struct nvgpu_queue" + * - Valid pointer to struct nvgpu_queue * - Queue size which is power of 2 * - Free the allocated queue by caling nvgpu_queue_free() API. + * - Pass below valid arguments to nvgpu_queue_alloc() API and check that the + * API returns success. + * - Valid pointer to struct nvgpu_queue + * - Queue size equal to INT32_MAX + * - Free the allocated queue by caling nvgpu_queue_free() API. * * Output: Returns PASS if the steps above were executed successfully. FAIL * otherwise. @@ -86,21 +91,25 @@ int test_nvgpu_queue_alloc_and_free(struct unit_module *m, struct gk20a *g, * Steps: * - Pass below valid arguments to nvgpu_queue_alloc() API and check that the * API returns success. - * - Valid pointer to "struct nvgpu_queue" - * - Queue size which is power of 2 - * - Enqueue message of length "BUF_LEN" calling nvgpu_queue_in() API and check - * that the API returns "BUF_LEN". - * - Update "in" and "out" indexes and enqueue message of length BUF_LEN such + * - Valid pointer to struct nvgpu_queue + * - Queue size which is power of 2 and less than INT_MAX, exact value used + * is 16. + * - Enqueue message of length BUF_LEN calling nvgpu_queue_in() API and check + * that the API returns 0. + * - Update In and Out indexes and enqueue message of length BUF_LEN such * that we wrap around the Queue while enqueuing the message using - * nvgpu_queue_in() API. Check that the API returns "BUF_LEN". - * - Reset "in" and "out" indexes and enqueue message of length "BUF_LEN" with - * the lock using nvgpu_queue_in_locked() API. Check that the API returns - * "BUF_LEN". - * - Enqueue message of length "BUF_LEN" again using nvgpu_queue_in_locked() - * API. Check that the API returns error "-ENOMEM". - * - Enqueue message of length "BUF_LEN" again using nvgpu_queue_in() API. Check - * that the API returns error "-ENOMEM". - * - Uninitialize the allocated resources. + * nvgpu_queue_in() API. Check that the API returns 0. + * - Reset In and Out indexes and enqueue message of length BUF_LEN with + * the lock using nvgpu_queue_in_locked() API. Check that the API returns 0. + * - Enqueue message of length BUF_LEN again using nvgpu_queue_in_locked() + * API. Check that the API returns error -ENOMEM. + * - Set In and Out index to UINT32_MAX - BUf_LEN/2, which indicates that the + * queue is empty and try to enqueue BUF_LEN size message. This should cause + * a wrap around of In index, but the API should be able to handle it and + * return 0 to indicate successful enqueue operation. + * - Enqueue message of length BUF_LEN again using nvgpu_queue_in() API. Check + * that the API returns error -ENOMEM. + * - Free the allocated resources. * * Output: Returns PASS if the steps above were executed successfully. FAIL * otherwise. @@ -122,32 +131,65 @@ int test_nvgpu_queue_in(struct unit_module *m, struct gk20a *g, void *args); * Steps: * - Pass below valid arguments to nvgpu_queue_alloc() API and check that the * API returns success. - * - Valid pointer to "struct nvgpu_queue" - * - Queue size which is power of 2 - * - Dequeue message of length "BUF_LEN" from the empty queue calling - * nvgpu_queue_out() API and check that the API returns "-ENOMEM" error. - * - Dequeue message of length "BUF_LEN" from the empty queue calling - * nvgpu_queue_out_locked() API and check that the API returns "-ENOMEM" + * - Valid pointer to struct nvgpu_queue + * - Queue size which is power of 2 and less than INT_MAX. Exact value used + * is 16. + * - Dequeue message of length BUF_LEN from the empty queue calling + * nvgpu_queue_out() API and check that the API returns -ENOMEM error. + * - Dequeue message of length BUF_LEN from the empty queue calling + * nvgpu_queue_out_locked() API and check that the API returns -ENOMEM * error. - * - Advance "in" index by "BUF_LEN" and dequeue message of length BUF_LEN by - * calling nvgpu_queue_out() API and check that the API returns "BUF_LEN". - * - Advance "in" index by "BUF_LEN" and dequeue message of length BUF_LEN by - * calling nvgpu_queue_out_locked() API and check that the API returns - * "BUF_LEN". - * - Update "in" and "out" indexes and dequeue message of length BUF_LEN such - * that we wrap around the Queue while dequeuing the message using - * nvgpu_queue_out() API. Check that the API returns "BUF_LEN". + * - Set In index as BUF_LEN and dequeue message of length BUF_LEN by + * calling nvgpu_queue_out() API and check that the API returns 0. + * - Set In index as BUF_LEN and dequeue message of length BUF_LEN by + * calling nvgpu_queue_out_locked() API and check that the API returns 0. + * - Set In index as 0 and Out index as (UINT32_MAX - BUF_LEN). This + * indicates a condition were In index has wrapped around due to an enqueue + * operation. Use nvgpu_queue_out API to dequeue message of length BUF_LEN. + * The dequeue operation should successfully return 0. + * - Repeat the above step to test API nvgpu_queue_out_locked. * - Do fault injection so that immediate call to nvgpu_queue_out_locked() API * would return error. * - Invoke nvgpu_queue_out_locked() API and check that API returns -1 error. * - Remove the injected fault. - * - Uninitialize the allocated resources. + * - Free the allocated resources. * * Output: Returns PASS if the steps above were executed successfully. FAIL * otherwise. */ int test_nvgpu_queue_out(struct unit_module *m, struct gk20a *g, void *args); +/** + * Test specification for: test_nvgpu_queue_available + * + * Description: Test the functionality of the function which returns the + * available data in the queue. + * + * Test Type: Feature + * + * Targets: nvgpu_queue_available + * + * Input: None + * + * Steps: + * - The following combinations of Out and In index values are provided to the + * public API, + * - Out and In are populated with same value. Expected return value is 0. + * - Out is populated with a value less than In. The difference is less than + * the size allocated for the queue. Expected return value is the difference + * between In and Out values indicating the number of bytes of data present + * in the queue. + * - Out is populated with a value greater than In. This scenario can happen + * when In index is wrapped around explicitly. The API should handle this + * scenario and return the valid number of bytes present in the queue. Out + * and In value are selected so as the size of the queue is not violated. + * + * Output: Returns PASS if the steps above returns expected values, FAIL + * otherwise. + */ +int test_nvgpu_queue_available(struct unit_module *m, struct gk20a *g, + void *args); + #endif /* __UNIT_POSIX_QUEUE_H__ */ /* * @}