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__ */ /* * @}