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);