From 6eef1a486cbd8ef9b34d7d345fd31fe6c0b6a38b Mon Sep 17 00:00:00 2001 From: Sagar Kamble Date: Mon, 9 Dec 2019 12:15:39 +0530 Subject: [PATCH] gpu: nvgpu: falcon: add unit tests and update functions Add unit tests to cover the invalid falcon port access, falcon sw init switch cases, nvgpu_falcon_set_irq, nvgpu_timeout_init failure branch coverage. Compile out the functions nvgpu_falcon_get_mem_size & falcon_bootstrap as they are needed by LS PMU and VBIOS code. For iGPU safety the falcon functions needing these will call the HAL APIs directly. This way we avoid the unreachable code as well. Updated the prototype of falcon bootstrap HAL API as that doesn't return any error. With these changes, we get 100% line coverage for common.falcon unit. JIRA NVGPU-2214 Change-Id: I1fe653d97c1a6a1521d7da38f171928dda58c5b5 Signed-off-by: Sagar Kamble Reviewed-on: https://git-master.nvidia.com/r/2258311 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/falcon/falcon.c | 56 ++--- drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h | 2 +- .../gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c | 4 +- drivers/gpu/nvgpu/include/nvgpu/falcon.h | 84 +++---- drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h | 2 +- drivers/gpu/nvgpu/libnvgpu-drv_safe.export | 3 +- userspace/required_tests.json | 12 + userspace/units/falcon/falcon_tests/falcon.c | 236 +++++++++++++++--- .../units/falcon/falcon_tests/nvgpu-falcon.h | 55 +++- 9 files changed, 340 insertions(+), 114 deletions(-) diff --git a/drivers/gpu/nvgpu/common/falcon/falcon.c b/drivers/gpu/nvgpu/common/falcon/falcon.c index 13931f03d..9df3411f1 100644 --- a/drivers/gpu/nvgpu/common/falcon/falcon.c +++ b/drivers/gpu/nvgpu/common/falcon/falcon.c @@ -199,10 +199,7 @@ static int falcon_memcpy_params_check(struct nvgpu_falcon *flcn, goto exit; } - ret = nvgpu_falcon_get_mem_size(flcn, mem_type, &mem_size); - if (ret != 0) { - goto exit; - } + mem_size = g->ops.falcon.get_mem_size(flcn, mem_type); if (!(offset <= mem_size && (offset + size) <= mem_size)) { nvgpu_err(g, "flcn-id 0x%x, copy overflow ", @@ -270,15 +267,6 @@ exit: return status; } -int nvgpu_falcon_bootstrap(struct nvgpu_falcon *flcn, u32 boot_vector) -{ - if (!is_falcon_valid(flcn)) { - return -EINVAL; - } - - return flcn->g->ops.falcon.bootstrap(flcn, boot_vector); -} - u32 nvgpu_falcon_mailbox_read(struct nvgpu_falcon *flcn, u32 mailbox_index) { struct gk20a *g; @@ -386,29 +374,12 @@ int nvgpu_falcon_hs_ucode_load_bootstrap(struct nvgpu_falcon *flcn, u32 *ucode, nvgpu_falcon_mailbox_write(flcn, FALCON_MAILBOX_0, 0xdeadbeefU); /* set BOOTVEC to start of non-secure code */ - err = nvgpu_falcon_bootstrap(flcn, 0U); - if (err != 0) { - nvgpu_err(g, "HS ucode bootstrap failed err-%d on falcon-%d", err, - nvgpu_falcon_get_id(flcn)); - goto exit; - } + g->ops.falcon.bootstrap(flcn, 0U); exit: return err; } -int nvgpu_falcon_get_mem_size(struct nvgpu_falcon *flcn, - enum falcon_mem_type type, u32 *size) -{ - if (!is_falcon_valid(flcn)) { - return -EINVAL; - } - - *size = flcn->g->ops.falcon.get_mem_size(flcn, type); - - return 0; -} - u32 nvgpu_falcon_get_id(struct nvgpu_falcon *flcn) { return flcn->flcn_id; @@ -628,6 +599,29 @@ void nvgpu_falcon_dump_stats(struct nvgpu_falcon *flcn) #endif #ifdef CONFIG_NVGPU_FALCON_NON_FUSA +int nvgpu_falcon_bootstrap(struct nvgpu_falcon *flcn, u32 boot_vector) +{ + if (!is_falcon_valid(flcn)) { + return -EINVAL; + } + + flcn->g->ops.falcon.bootstrap(flcn, boot_vector); + + return 0; +} + +int nvgpu_falcon_get_mem_size(struct nvgpu_falcon *flcn, + enum falcon_mem_type type, u32 *size) +{ + if (!is_falcon_valid(flcn)) { + return -EINVAL; + } + + *size = flcn->g->ops.falcon.get_mem_size(flcn, type); + + return 0; +} + int nvgpu_falcon_clear_halt_intr_status(struct nvgpu_falcon *flcn, unsigned int timeout) { diff --git a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h index 493a370b9..c2fa5dd6a 100644 --- a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h +++ b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a.h @@ -73,7 +73,7 @@ int gk20a_falcon_copy_to_dmem(struct nvgpu_falcon *flcn, u32 dst, u8 *src, u32 size, u8 port); int gk20a_falcon_copy_to_imem(struct nvgpu_falcon *flcn, u32 dst, u8 *src, u32 size, u8 port, bool sec, u32 tag); -int gk20a_falcon_bootstrap(struct nvgpu_falcon *flcn, +void gk20a_falcon_bootstrap(struct nvgpu_falcon *flcn, u32 boot_vector); u32 gk20a_falcon_mailbox_read(struct nvgpu_falcon *flcn, u32 mailbox_index); diff --git a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c index 1712ce43d..98d35ca93 100644 --- a/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c +++ b/drivers/gpu/nvgpu/hal/falcon/falcon_gk20a_fusa.c @@ -328,7 +328,7 @@ int gk20a_falcon_copy_to_imem(struct nvgpu_falcon *flcn, u32 dst, return 0; } -int gk20a_falcon_bootstrap(struct nvgpu_falcon *flcn, +void gk20a_falcon_bootstrap(struct nvgpu_falcon *flcn, u32 boot_vector) { nvgpu_log_info(flcn->g, "boot vec 0x%x", boot_vector); @@ -341,8 +341,6 @@ int gk20a_falcon_bootstrap(struct nvgpu_falcon *flcn, gk20a_falcon_writel(flcn, falcon_falcon_cpuctl_r(), falcon_falcon_cpuctl_startcpu_f(1)); - - return 0; } u32 gk20a_falcon_mailbox_read(struct nvgpu_falcon *flcn, diff --git a/drivers/gpu/nvgpu/include/nvgpu/falcon.h b/drivers/gpu/nvgpu/include/nvgpu/falcon.h index cca2677ce..8aee1b790 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/falcon.h +++ b/drivers/gpu/nvgpu/include/nvgpu/falcon.h @@ -105,11 +105,9 @@ * + nvgpu_falcon_mem_scrub_wait() * + nvgpu_falcon_copy_to_dmem() * + nvgpu_falcon_copy_to_imem() - * + nvgpu_falcon_bootstrap() * + nvgpu_falcon_mailbox_read() * + nvgpu_falcon_mailbox_write() * + nvgpu_falcon_hs_ucode_load_bootstrap() - * + nvgpu_falcon_get_mem_size() * + nvgpu_falcon_get_id() * + nvgpu_falcon_set_irq() */ @@ -403,25 +401,6 @@ int nvgpu_falcon_copy_to_dmem(struct nvgpu_falcon *flcn, int nvgpu_falcon_copy_to_imem(struct nvgpu_falcon *flcn, u32 dst, u8 *src, u32 size, u8 port, bool sec, u32 tag); -/** - * @brief Bootstrap the falcon. - * - * @param flcn [in] The falcon. - * @param boot_vector [in] Address to start the falcon execution. - * - * This function is called after setting up IMEM and DMEM with uCode - * instructions and data to start the execution. - * - * Steps: - * - Validate that the passed in falcon struct is not NULL and is for supported - * falcon. If not valid, return -EINVAL. - * - Set the boot vector address, DMA control and start the falcon CPU - * execution. - * - * @return 0 in case of success, < 0 in case of failure. - */ -int nvgpu_falcon_bootstrap(struct nvgpu_falcon *flcn, u32 boot_vector); - /** * @brief Read the falcon mailbox register. * @@ -494,28 +473,6 @@ void nvgpu_falcon_mailbox_write(struct nvgpu_falcon *flcn, u32 mailbox_index, int nvgpu_falcon_hs_ucode_load_bootstrap(struct nvgpu_falcon *flcn, u32 *ucode, u32 *ucode_header); -/** - * @brief Get the size of falcon's memory. - * - * @param flcn [in] The falcon. - * @param type [in] Falcon memory type (IMEM, DMEM). - * - Supported types: MEM_DMEM (0), MEM_IMEM (1) - * @param size [out] Size of the falcon memory type. - * - * This function is called to get the size of falcon's memory for validation - * while copying to IMEM/DMEM. - * - * Steps: - * - Validate that the passed in falcon struct is not NULL and is for supported - * falcon. If not valid, return -EINVAL. - * - Read the size of the falcon memory of \a type in bytes from the HW config - * register in output parameter \a size. - * - * @return 0 in case of success, < 0 in case of failure. - */ -int nvgpu_falcon_get_mem_size(struct nvgpu_falcon *flcn, - enum falcon_mem_type type, u32 *size); - /** * @brief Get the falcon ID. * @@ -639,6 +596,47 @@ void nvgpu_falcon_dump_stats(struct nvgpu_falcon *flcn); #endif #ifdef CONFIG_NVGPU_FALCON_NON_FUSA +/** + * @brief Bootstrap the falcon. + * + * @param flcn [in] The falcon. + * @param boot_vector [in] Address to start the falcon execution. + * + * This function is called after setting up IMEM and DMEM with uCode + * instructions and data to start the execution. + * + * Steps: + * - Validate that the passed in falcon struct is not NULL and is for supported + * falcon. If not valid, return -EINVAL. + * - Set the boot vector address, DMA control and start the falcon CPU + * execution. + * + * @return 0 in case of success, < 0 in case of failure. + */ +int nvgpu_falcon_bootstrap(struct nvgpu_falcon *flcn, u32 boot_vector); + +/** + * @brief Get the size of falcon's memory. + * + * @param flcn [in] The falcon. + * @param type [in] Falcon memory type (IMEM, DMEM). + * - Supported types: MEM_DMEM (0), MEM_IMEM (1) + * @param size [out] Size of the falcon memory type. + * + * This function is called to get the size of falcon's memory for validation + * while copying to IMEM/DMEM. + * + * Steps: + * - Validate that the passed in falcon struct is not NULL and is for supported + * falcon. If not valid, return -EINVAL. + * - Read the size of the falcon memory of \a type in bytes from the HW config + * register in output parameter \a size. + * + * @return 0 in case of success, < 0 in case of failure. + */ +int nvgpu_falcon_get_mem_size(struct nvgpu_falcon *flcn, + enum falcon_mem_type type, u32 *size); + int nvgpu_falcon_clear_halt_intr_status(struct nvgpu_falcon *flcn, unsigned int timeout); int nvgpu_falcon_copy_from_dmem(struct nvgpu_falcon *flcn, diff --git a/drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h b/drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h index 0c9114435..b3263ac58 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gops_falcon.h @@ -50,7 +50,7 @@ struct gops_falcon { int (*copy_to_imem)(struct nvgpu_falcon *flcn, u32 dst, u8 *src, u32 size, u8 port, bool sec, u32 tag); - int (*bootstrap)(struct nvgpu_falcon *flcn, + void (*bootstrap)(struct nvgpu_falcon *flcn, u32 boot_vector); u32 (*mailbox_read)(struct nvgpu_falcon *flcn, u32 mailbox_index); diff --git a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export index 2c2839ed8..9617128da 100644 --- a/drivers/gpu/nvgpu/libnvgpu-drv_safe.export +++ b/drivers/gpu/nvgpu/libnvgpu-drv_safe.export @@ -435,15 +435,14 @@ nvgpu_engine_get_gr_runlist_id nvgpu_engine_is_valid_runlist_id nvgpu_get nvgpu_falcon_hs_ucode_load_bootstrap -nvgpu_falcon_bootstrap nvgpu_falcon_copy_to_dmem nvgpu_falcon_copy_to_imem nvgpu_falcon_get_instance -nvgpu_falcon_get_mem_size nvgpu_falcon_mailbox_read nvgpu_falcon_mailbox_write nvgpu_falcon_mem_scrub_wait nvgpu_falcon_reset +nvgpu_falcon_set_irq nvgpu_falcon_sw_free nvgpu_falcon_sw_init nvgpu_falcon_wait_for_halt diff --git a/userspace/required_tests.json b/userspace/required_tests.json index 41deccb4f..f8c08bcc7 100644 --- a/userspace/required_tests.json +++ b/userspace/required_tests.json @@ -575,6 +575,12 @@ "unit": "falcon", "test_level": 0 }, + { + "test": "test_falcon_irq", + "case": "falcon_irq", + "unit": "falcon", + "test_level": 0 + }, { "test": "test_falcon_mailbox", "case": "falcon_mailbox", @@ -593,6 +599,12 @@ "unit": "falcon", "test_level": 0 }, + { + "test": "test_falcon_mem_rw_inval_port", + "case": "falcon_mem_rw_inval_port", + "unit": "falcon", + "test_level": 0 + }, { "test": "test_falcon_mem_rw_range", "case": "falcon_mem_rw_range", diff --git a/userspace/units/falcon/falcon_tests/falcon.c b/userspace/units/falcon/falcon_tests/falcon.c index 7cfc40c27..36c7d689f 100644 --- a/userspace/units/falcon/falcon_tests/falcon.c +++ b/userspace/units/falcon/falcon_tests/falcon.c @@ -25,6 +25,8 @@ #include #include +#include + #include #include #include @@ -338,6 +340,22 @@ out: return ret; } +static int verify_valid_falcon_sw_init(struct unit_module *m, struct gk20a *g, + u32 flcn_id) +{ + int err; + + err = nvgpu_falcon_sw_init(g, flcn_id); + if (err != 0) { + unit_err(m, "falcon init with valid ID %d failed\n", flcn_id); + return err; + } + + nvgpu_falcon_sw_free(g, flcn_id); + + return 0; +} + /* * Valid/Invalid: Passing valid ID should succeed the call to function * nvgpu_falcon_sw_init|free. Otherwise it should fail with error. @@ -367,19 +385,31 @@ int test_falcon_sw_init_free(struct unit_module *m, struct gk20a *g, nvgpu_falcon_sw_free(g, FALCON_ID_INVALID); - err = nvgpu_falcon_sw_init(g, FALCON_ID_FECS); + err = verify_valid_falcon_sw_init(m, g, FALCON_ID_FECS); if (err != 0) { - unit_return_fail(m, "falcon init with valid ID failed\n"); + unit_return_fail(m, "FECS falcon sw not initialized\n"); } - nvgpu_falcon_sw_free(g, FALCON_ID_FECS); - - err = nvgpu_falcon_sw_init(g, FALCON_ID_SEC2); + err = verify_valid_falcon_sw_init(m, g, FALCON_ID_GSPLITE); if (err != 0) { - unit_return_fail(m, "falcon init with valid ID failed\n"); + unit_return_fail(m, "GSPLITE falcon sw not initialized\n"); + } + + err = verify_valid_falcon_sw_init(m, g, FALCON_ID_NVDEC); + if (err != 0) { + unit_return_fail(m, "NVDEC falcon sw not initialized\n"); + } + + err = verify_valid_falcon_sw_init(m, g, FALCON_ID_SEC2); + if (err != 0) { + unit_return_fail(m, "SEC2 falcon sw not initialized\n"); + } + + err = verify_valid_falcon_sw_init(m, g, FALCON_ID_MINION); + if (err != 0) { + unit_return_fail(m, "MINION falcon sw not initialized\n"); } - nvgpu_falcon_sw_free(g, FALCON_ID_SEC2); return UNIT_SUCCESS; } @@ -479,6 +509,8 @@ int test_falcon_reset(struct unit_module *m, struct gk20a *g, void *__args) */ int test_falcon_mem_scrub(struct unit_module *m, struct gk20a *g, void *__args) { + struct nvgpu_posix_fault_inj *timer_fi = + nvgpu_timers_get_fault_injection(); struct { struct nvgpu_falcon *flcn; void (*pre_scrub)(void *); @@ -502,6 +534,16 @@ int test_falcon_mem_scrub(struct unit_module *m, struct gk20a *g, void *__args) } } + /* enable fault injection for the timer init call for branch coverage */ + nvgpu_posix_enable_fault_injection(timer_fi, true, 0); + err = nvgpu_falcon_mem_scrub_wait(gpccs_flcn); + nvgpu_posix_enable_fault_injection(timer_fi, false, 0); + + if (err != -ETIMEDOUT) { + unit_return_fail(m, "falcon mem scrub err: %d " + "expected err: -ETIMEDOUT\n", err); + } + return UNIT_SUCCESS; } @@ -546,6 +588,8 @@ static void flcn_idle_fail(void *data) */ int test_falcon_idle(struct unit_module *m, struct gk20a *g, void *__args) { + struct nvgpu_posix_fault_inj *timer_fi = + nvgpu_timers_get_fault_injection(); struct { struct nvgpu_falcon *flcn; void (*pre_idle)(void *); @@ -569,6 +613,16 @@ int test_falcon_idle(struct unit_module *m, struct gk20a *g, void *__args) } } + /* enable fault injection for the timer init call for branch coverage */ + nvgpu_posix_enable_fault_injection(timer_fi, true, 0); + err = nvgpu_falcon_wait_idle(gpccs_flcn); + nvgpu_posix_enable_fault_injection(timer_fi, false, 0); + + if (err != -ETIMEDOUT) { + unit_return_fail(m, "falcon wait for idle err: %d " + "expected err: -ETIMEDOUT\n", err); + } + return UNIT_SUCCESS; } @@ -607,6 +661,8 @@ static void flcn_halt_fail(void *data) int test_falcon_halt(struct unit_module *m, struct gk20a *g, void *__args) { #define FALCON_WAIT_HALT 200 + struct nvgpu_posix_fault_inj *timer_fi = + nvgpu_timers_get_fault_injection(); struct { struct nvgpu_falcon *flcn; void (*pre_halt)(void *); @@ -625,12 +681,23 @@ int test_falcon_halt(struct unit_module *m, struct gk20a *g, void *__args) err = nvgpu_falcon_wait_for_halt(test_data[i].flcn, FALCON_WAIT_HALT); if (err != test_data[i].exp_err) { - unit_return_fail(m, "falcon wait for idle err: %d " + unit_return_fail(m, "falcon wait for halt err: %d " "expected err: %d\n", err, test_data[i].exp_err); } } + /* enable fault injection for the timer init call for branch coverage */ + nvgpu_posix_enable_fault_injection(timer_fi, true, 0); + err = nvgpu_falcon_wait_for_halt(gpccs_flcn, + FALCON_WAIT_HALT); + nvgpu_posix_enable_fault_injection(timer_fi, false, 0); + + if (err != -ETIMEDOUT) { + unit_return_fail(m, "falcon wait for halt err: %d " + "expected err: -ETIMEDOUT\n", err); + } + return UNIT_SUCCESS; } @@ -667,6 +734,38 @@ int test_falcon_mem_rw_init(struct unit_module *m, struct gk20a *g, return UNIT_SUCCESS; } +/* + * Invalid: Read and write for invalid Falcon port should fail + * with error -EINVAL. + */ +int test_falcon_mem_rw_inval_port(struct unit_module *m, struct gk20a *g, + void *__args) +{ + int err = 0, size = RAND_DATA_SIZE, port = 2; + + if (pmu_flcn == NULL || !pmu_flcn->is_falcon_supported) { + unit_return_fail(m, "test environment not initialized."); + } + + /* write to invalid port */ + unit_info(m, "Writing %d bytes to imem port %d\n", size, port); + err = nvgpu_falcon_copy_to_imem(pmu_flcn, 0, (u8 *) rand_test_data, + size, port, false, 0); + if (err != -EINVAL) { + unit_return_fail(m, "Copy to IMEM invalid port should fail\n"); + } + +#ifdef CONFIG_NVGPU_FALCON_NON_FUSA + err = nvgpu_falcon_copy_from_imem(pmu_flcn, 0, + NULL, size, port); + if (err != -EINVAL) { + unit_err(m, "Copy from IMEM invalid port should fail\n"); + } +#endif + + return UNIT_SUCCESS; +} + /* * Reading and writing data from/to unaligned data should succeed. */ @@ -942,8 +1041,6 @@ static bool falcon_check_reg_group(struct gk20a *g, * Invalid: Invoke nvgpu_falcon_hs_ucode_load_bootstrap with invalid ucode data * and verify that call fails. * - * Valid: Invoke nvgpu_falcon_bootstrap with initialized falcon and verify - * that call succeeds. * Valid: Invoke nvgpu_falcon_hs_ucode_load_bootstrap with initialized * falcon with ACR firmware, verify the expected state of falcon * registers - falcon_falcon_dmactl_r, falcon_falcon_bootvec_r, @@ -964,11 +1061,14 @@ int test_falcon_bootstrap(struct unit_module *m, struct gk20a *g, void *__args) struct bin_hdr *hs_bin_hdr = NULL; struct nvgpu_firmware *acr_fw; u32 *ucode_header = NULL; +#ifdef CONFIG_NVGPU_FALCON_NON_FUSA u32 boot_vector = 0xF000; +#endif u32 *ucode = NULL; u32 valid_size; int err; +#ifdef CONFIG_NVGPU_FALCON_NON_FUSA /** Invalid falcon bootstrap. */ err = nvgpu_falcon_bootstrap(uninit_flcn, boot_vector); if (err != -EINVAL) { @@ -981,6 +1081,7 @@ int test_falcon_bootstrap(struct unit_module *m, struct gk20a *g, void *__args) if (err) { unit_return_fail(m, "PMU falcon bootstrap failed\n"); } +#endif acr_fw = nvgpu_request_firmware(g, HSBIN_ACR_UCODE_IMAGE, 0); if (acr_fw == NULL) { @@ -1020,11 +1121,8 @@ int test_falcon_bootstrap(struct unit_module *m, struct gk20a *g, void *__args) */ valid_size = ucode_header[OS_CODE_SIZE]; - err = nvgpu_falcon_get_mem_size(gpccs_flcn, MEM_IMEM, - &ucode_header[OS_CODE_SIZE]); - if (err) { - unit_return_fail(m, "PMU falcon IMEM get size failed\n"); - } + ucode_header[OS_CODE_SIZE] = g->ops.falcon.get_mem_size(gpccs_flcn, + MEM_IMEM); ucode_header[OS_CODE_SIZE] += 4; @@ -1043,12 +1141,8 @@ int test_falcon_bootstrap(struct unit_module *m, struct gk20a *g, void *__args) */ valid_size = ucode_header[APP_0_CODE_SIZE]; - err = nvgpu_falcon_get_mem_size(gpccs_flcn, MEM_IMEM, - &ucode_header[APP_0_CODE_SIZE]); - if (err) { - unit_return_fail(m, "PMU falcon IMEM get size failed\n"); - } - + ucode_header[APP_0_CODE_SIZE] = g->ops.falcon.get_mem_size(gpccs_flcn, + MEM_IMEM); ucode_header[APP_0_CODE_SIZE] += 4; err = nvgpu_falcon_hs_ucode_load_bootstrap(gpccs_flcn, @@ -1066,12 +1160,8 @@ int test_falcon_bootstrap(struct unit_module *m, struct gk20a *g, void *__args) */ valid_size = ucode_header[OS_DATA_SIZE]; - err = nvgpu_falcon_get_mem_size(gpccs_flcn, MEM_DMEM, - &ucode_header[OS_DATA_SIZE]); - if (err) { - unit_return_fail(m, "PMU falcon DMEM get size failed\n"); - } - + ucode_header[OS_DATA_SIZE] = g->ops.falcon.get_mem_size(gpccs_flcn, + MEM_DMEM); ucode_header[OS_DATA_SIZE] += 4; err = nvgpu_falcon_hs_ucode_load_bootstrap(gpccs_flcn, @@ -1098,6 +1188,91 @@ int test_falcon_bootstrap(struct unit_module *m, struct gk20a *g, void *__args) return UNIT_SUCCESS; } +static void flcn_irq_not_supported(struct nvgpu_falcon *flcn) +{ + flcn->is_interrupt_enabled = false; +} + +static void flcn_irq_supported(struct nvgpu_falcon *flcn) +{ + flcn->is_interrupt_enabled = true; +} + +static bool check_flcn_irq_status(struct nvgpu_falcon *flcn, bool enable, + u32 irq_mask, u32 irq_dest) +{ + u32 tmp_mask, tmp_dest; + + if (enable) { + tmp_mask = nvgpu_posix_io_readl_reg_space(flcn->g, + flcn->flcn_base + falcon_falcon_irqmset_r()); + tmp_dest = nvgpu_posix_io_readl_reg_space(flcn->g, + flcn->flcn_base + falcon_falcon_irqdest_r()); + + if (tmp_mask != irq_mask || tmp_dest != irq_dest) { + return false; + } else { + return true; + } + } else { + tmp_mask = nvgpu_posix_io_readl_reg_space(flcn->g, + flcn->flcn_base + falcon_falcon_irqmclr_r()); + + if (tmp_mask != 0xffffffff) { + return false; + } else { + return true; + } + } +} + +int test_falcon_irq(struct unit_module *m, struct gk20a *g, void *__args) +{ + struct { + struct nvgpu_falcon *flcn; + bool enable; + u32 intr_mask; + u32 intr_dest; + void (*pre_irq)(struct nvgpu_falcon *); + bool (*post_irq)(struct nvgpu_falcon *, bool, u32, u32); + } test_data[] = {{uninit_flcn, true, 0, 0, NULL, NULL}, + {gpccs_flcn, true, 0, 0, flcn_irq_not_supported, NULL}, + {gpccs_flcn, true, 0xdeadbeee, 0xbeeedead, + flcn_irq_supported, check_flcn_irq_status}, + {gpccs_flcn, false, 0xdeadbeee, 0xbeeedead, + flcn_irq_supported, check_flcn_irq_status} }; + int size = ARRAY_SIZE(test_data); + bool intr_enabled; + bool err; + int i; + + intr_enabled = gpccs_flcn->is_interrupt_enabled; + + for (i = 0; i < size; i++) { + if (test_data[i].pre_irq) { + test_data[i].pre_irq(test_data[i].flcn); + } + + nvgpu_falcon_set_irq(test_data[i].flcn, test_data[i].enable, + test_data[i].intr_mask, + test_data[i].intr_dest); + + if (test_data[i].post_irq) { + err = test_data[i].post_irq(test_data[i].flcn, + test_data[i].enable, + test_data[i].intr_mask, + test_data[i].intr_dest); + if (!err) { + unit_return_fail(m, "falcon set_irq err"); + } + } + } + + gpccs_flcn->is_interrupt_enabled = intr_enabled; + + return UNIT_SUCCESS; +} + struct unit_module_test falcon_tests[] = { UNIT_TEST(falcon_sw_init_free, test_falcon_sw_init_free, NULL, 0), UNIT_TEST(falcon_reset, test_falcon_reset, NULL, 0), @@ -1105,13 +1280,16 @@ struct unit_module_test falcon_tests[] = { UNIT_TEST(falcon_idle, test_falcon_idle, NULL, 0), UNIT_TEST(falcon_halt, test_falcon_halt, NULL, 0), UNIT_TEST(falcon_mem_rw_init, test_falcon_mem_rw_init, NULL, 0), + UNIT_TEST(falcon_mem_rw_inval_port, + test_falcon_mem_rw_inval_port, NULL, 0), + UNIT_TEST(falcon_mem_rw_unaligned_cpu_buffer, + test_falcon_mem_rw_unaligned_cpu_buffer, NULL, 0), UNIT_TEST(falcon_mem_rw_range, test_falcon_mem_rw_range, NULL, 0), UNIT_TEST(falcon_mem_rw_aligned, test_falcon_mem_rw_aligned, NULL, 0), UNIT_TEST(falcon_mem_rw_zero, test_falcon_mem_rw_zero, NULL, 0), UNIT_TEST(falcon_mailbox, test_falcon_mailbox, NULL, 0), UNIT_TEST(falcon_bootstrap, test_falcon_bootstrap, NULL, 0), - UNIT_TEST(falcon_mem_rw_unaligned_cpu_buffer, - test_falcon_mem_rw_unaligned_cpu_buffer, NULL, 0), + UNIT_TEST(falcon_irq, test_falcon_irq, NULL, 0), /* Cleanup */ UNIT_TEST(falcon_free_test_env, free_falcon_test_env, NULL, 0), diff --git a/userspace/units/falcon/falcon_tests/nvgpu-falcon.h b/userspace/units/falcon/falcon_tests/nvgpu-falcon.h index a01d3fa50..5d4becff4 100644 --- a/userspace/units/falcon/falcon_tests/nvgpu-falcon.h +++ b/userspace/units/falcon/falcon_tests/nvgpu-falcon.h @@ -290,10 +290,6 @@ int test_falcon_mailbox(struct unit_module *m, struct gk20a *g, void *__args); * Input: None. * * Steps: - * - Invoke nvgpu_falcon_bootstrap with uninitialized falcon struct. - * - Verify that call fails with -EINVAL return value. - * - Invoke nvgpu_falcon_bootstrap with initialized falcon struct. - * - Verify that call succeeds. * - Invoke nvgpu_falcon_hs_ucode_load_bootstrap with uninitialized * falcon struct. * - Verify that call fails with -EINVAL return value. @@ -345,3 +341,54 @@ int test_falcon_bootstrap(struct unit_module *m, struct gk20a *g, void *__args); */ int test_falcon_mem_rw_unaligned_cpu_buffer(struct unit_module *m, struct gk20a *g, void *__args); + +/** + * Test specification for: test_falcon_mem_rw_inval_port + * + * Description: The falcon unit shall not be able to read/write from/to falcon's + * memory from invalid port. + * + * Test Type: Error guessing based + * + * Input: None. + * + * Steps: + * - Invoke nvgpu_falcon_copy_to_imem and nvgpu_falcon_copy_from_imem with + * initialized falcon struct with initialized sample random data, valid + * range but invalid port. + * - Verify that return value is -EINVAL. + * + * Output: Returns PASS if the steps above were executed successfully. FAIL + * otherwise. + */ +int test_falcon_mem_rw_inval_port(struct unit_module *m, struct gk20a *g, + void *__args); +/** + * Test specification for: test_falcon_irq + * + * Description: The falcon unit shall be able to set or clear the falcon irq + * mask and destination registers for supported falcons. + * + * Test Type: Feature based + * + * Input: None. + * + * Steps: + * - Invoke nvgpu_falcon_set_irq with uninitialized falcon struct. + * - Invoke nvgpu_falcon_set_irq with initialized falcon struct where + * underlying falcon has interrupt support disabled. + * - Invoke nvgpu_falcon_set_irq to enable the interrupts with + * initialized falcon struct and sample interrupt mask and + * destination values and the underlying falcon has + * interrupt support enabled. + * - Verify that falcon_irqmset_r and falcon_irqdest_r are set as + * expected. + * - Invoke nvgpu_falcon_set_irq to disable the interrupts with + * initialized falcon struct and the underlying falcon has + * interrupt support enabled. + * - Verify that falcon_irqmclr_r is set to 0xffffffff. + * + * Output: Returns PASS if the steps above were executed successfully. FAIL + * otherwise. + */ +int test_falcon_irq(struct unit_module *m, struct gk20a *g, void *__args);