mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
Add BVEC tests for following common.ltc unit API: gops_ltc_intr.isr Add unit test for boundary value check for ltc parameter of the LTC isr. JIRA NVGPU-6398 Change-Id: I0e075a3244d969d11faa4fd99e7e364218da6e30 Signed-off-by: Sagar Kamble <skamble@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2549802 (cherry picked from commit 3133a7173b0853a699e4ebf2fc50e866e3ac6211) Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2623636 Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com> Reviewed-by: svc-mobile-cert <svc-mobile-cert@nvidia.com> Reviewed-by: Shashank Singh <shashsingh@nvidia.com> Reviewed-by: Vaibhav Kachore <vkachore@nvidia.com> GVS: Gerrit_Virtual_Submit
747 lines
22 KiB
C
747 lines
22 KiB
C
/*
|
|
* Copyright (c) 2019-2022, 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"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
#include <unit/unit.h>
|
|
#include <unit/io.h>
|
|
#include <nvgpu/posix/io.h>
|
|
|
|
#include <nvgpu/gk20a.h>
|
|
#include <nvgpu/mc.h>
|
|
#include <nvgpu/cic_mon.h>
|
|
#include <nvgpu/cic_rm.h>
|
|
#include <nvgpu/hal_init.h>
|
|
#include <nvgpu/device.h>
|
|
#include <nvgpu/engines.h>
|
|
#include <nvgpu/ltc.h>
|
|
#include <nvgpu/hw/gp10b/hw_mc_gp10b.h>
|
|
|
|
#include <nvgpu/posix/cond.h>
|
|
#include <nvgpu/posix/posix-fault-injection.h>
|
|
|
|
#include "nvgpu-mc.h"
|
|
|
|
#define MC_ADDR_SPACE_START 0x00000000
|
|
#define MC_ADDR_SPACE_SIZE 0xfff
|
|
|
|
/* value for GV11B */
|
|
#define MC_BOOT_0_GV11B (NVGPU_GPUID_GV11B << 20)
|
|
/* to set the security fuses */
|
|
#define GP10B_FUSE_REG_BASE 0x00021000U
|
|
#define GP10B_FUSE_OPT_PRIV_SEC_EN (GP10B_FUSE_REG_BASE+0x434U)
|
|
#define ACTIVE_GR_ID 1
|
|
#define ACTIVE_CE_ID 2
|
|
|
|
#define STALL_EN_REG mc_intr_en_r(NVGPU_CIC_INTR_STALLING)
|
|
#define NONSTALL_EN_REG mc_intr_en_r(NVGPU_CIC_INTR_NONSTALLING)
|
|
|
|
#define STALL_EN_SET_REG mc_intr_en_set_r(NVGPU_CIC_INTR_STALLING)
|
|
#define STALL_EN_CLEAR_REG mc_intr_en_clear_r(NVGPU_CIC_INTR_STALLING)
|
|
#define NONSTALL_EN_SET_REG mc_intr_en_set_r(NVGPU_CIC_INTR_NONSTALLING)
|
|
#define NONSTALL_EN_CLEAR_REG mc_intr_en_clear_r(NVGPU_CIC_INTR_NONSTALLING)
|
|
|
|
#define STALL_PENDING_REG mc_intr_r(NVGPU_CIC_INTR_STALLING)
|
|
#define NONSTALL_PENDING_REG mc_intr_r(NVGPU_CIC_INTR_NONSTALLING)
|
|
|
|
struct mc_unit {
|
|
u32 num;
|
|
u32 bit;
|
|
};
|
|
static struct mc_unit mc_units[] = {
|
|
{ NVGPU_CIC_INTR_UNIT_BUS, mc_intr_pbus_pending_f() },
|
|
{ NVGPU_CIC_INTR_UNIT_PRIV_RING, mc_intr_priv_ring_pending_f() },
|
|
{ NVGPU_CIC_INTR_UNIT_FIFO, mc_intr_pfifo_pending_f() },
|
|
{ NVGPU_CIC_INTR_UNIT_LTC, mc_intr_ltc_pending_f() },
|
|
{ NVGPU_CIC_INTR_UNIT_HUB, mc_intr_replayable_fault_pending_f() },
|
|
{ NVGPU_CIC_INTR_UNIT_GR, (1 << ACTIVE_GR_ID) /* nvgpu_gr_engine_interrupt_mask() */},
|
|
{ NVGPU_CIC_INTR_UNIT_PMU, mc_intr_pmu_pending_f() },
|
|
{ NVGPU_CIC_INTR_UNIT_CE, (1 << ACTIVE_CE_ID) /* nvgpu_ce_engine_interrupt_mask() */ },
|
|
};
|
|
#define NUM_MC_UNITS ARRAY_SIZE(mc_units)
|
|
|
|
#define INVALID_UNIT 100
|
|
/*
|
|
* Mock I/O
|
|
*/
|
|
|
|
/*
|
|
* Write callback. Forward the write access to the mock IO framework.
|
|
*/
|
|
static void writel_access_reg_fn(struct gk20a *g,
|
|
struct nvgpu_reg_access *access)
|
|
{
|
|
u32 value;
|
|
|
|
if (access->addr == STALL_EN_SET_REG) {
|
|
value = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG) | access->value;
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, value);
|
|
}
|
|
|
|
if (access->addr == NONSTALL_EN_SET_REG) {
|
|
value = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG) | access->value;
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, value);
|
|
}
|
|
|
|
|
|
if (access->addr == STALL_EN_CLEAR_REG) {
|
|
value = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG) & ~access->value;
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, value);
|
|
}
|
|
|
|
if (access->addr == NONSTALL_EN_CLEAR_REG) {
|
|
value = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG) & ~access->value;
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, value);
|
|
}
|
|
|
|
nvgpu_posix_io_writel_reg_space(g, access->addr, access->value);
|
|
}
|
|
|
|
/*
|
|
* Read callback. Get the register value from the mock IO framework.
|
|
*/
|
|
static void readl_access_reg_fn(struct gk20a *g,
|
|
struct nvgpu_reg_access *access)
|
|
{
|
|
access->value = nvgpu_posix_io_readl_reg_space(g, access->addr);
|
|
}
|
|
|
|
static struct nvgpu_posix_io_callbacks test_reg_callbacks = {
|
|
/* Write APIs all can use the same accessor. */
|
|
.writel = writel_access_reg_fn,
|
|
.writel_check = writel_access_reg_fn,
|
|
.bar1_writel = writel_access_reg_fn,
|
|
.usermode_writel = writel_access_reg_fn,
|
|
|
|
/* Likewise for the read APIs. */
|
|
.__readl = readl_access_reg_fn,
|
|
.readl = readl_access_reg_fn,
|
|
.bar1_readl = readl_access_reg_fn,
|
|
};
|
|
|
|
struct unit_ctx {
|
|
bool bus_isr;
|
|
bool ce_isr;
|
|
bool fb_isr;
|
|
bool fifo_isr;
|
|
bool gr_isr;
|
|
bool ltc_isr;
|
|
bool pmu_isr;
|
|
bool priv_ring_isr;
|
|
|
|
u32 ce_isr_return;
|
|
u32 fifo_isr_return;
|
|
int gr_isr_return;
|
|
};
|
|
|
|
static struct unit_ctx u;
|
|
|
|
static void reset_ctx(void)
|
|
{
|
|
u.bus_isr = false;
|
|
u.ce_isr = false;
|
|
u.fb_isr = false;
|
|
u.fifo_isr = false;
|
|
u.gr_isr = false;
|
|
u.gr_isr_return = 0;
|
|
u.ltc_isr = false;
|
|
u.pmu_isr = false;
|
|
u.priv_ring_isr = false;
|
|
}
|
|
|
|
static void mock_bus_isr(struct gk20a *g)
|
|
{
|
|
u.bus_isr = true;
|
|
}
|
|
|
|
static void mock_ce_stall_isr(struct gk20a *g, u32 inst_id, u32 pri_base,
|
|
bool *needs_rc, bool *needs_quiesce)
|
|
{
|
|
u.ce_isr = true;
|
|
}
|
|
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
static u32 mock_ce_nonstall_isr(struct gk20a *g, u32 inst_id, u32 pri_base)
|
|
{
|
|
u.ce_isr = true;
|
|
return u.ce_isr_return;
|
|
}
|
|
#endif
|
|
|
|
static void mock_fb_isr(struct gk20a *g, u32 intr_unit_bitmask)
|
|
{
|
|
u.fb_isr = true;
|
|
}
|
|
|
|
static void mock_fifo_stall_isr(struct gk20a *g)
|
|
{
|
|
u.fifo_isr = true;
|
|
}
|
|
|
|
static u32 mock_fifo_nonstall_isr(struct gk20a *g)
|
|
{
|
|
u.fifo_isr = true;
|
|
return u.fifo_isr_return;
|
|
}
|
|
|
|
static u32 mock_gr_nonstall_isr(struct gk20a *g)
|
|
{
|
|
u.gr_isr = true;
|
|
return (u32)u.gr_isr_return;
|
|
}
|
|
|
|
static int mock_gr_stall_isr(struct gk20a *g)
|
|
{
|
|
u.gr_isr = true;
|
|
return u.gr_isr_return;
|
|
}
|
|
|
|
static int mock_ltc_isr(struct gk20a *g, u32 ltc)
|
|
{
|
|
u.ltc_isr = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void mock_pmu_isr(struct gk20a *g)
|
|
{
|
|
u.pmu_isr = true;
|
|
}
|
|
|
|
static void mock_priv_ring_isr(struct gk20a *g)
|
|
{
|
|
u.priv_ring_isr = true;
|
|
}
|
|
|
|
int test_mc_setup_env(struct unit_module *m,
|
|
struct gk20a *g, void *args)
|
|
{
|
|
/* Create mc register space */
|
|
if (nvgpu_posix_io_add_reg_space(g, MC_ADDR_SPACE_START,
|
|
MC_ADDR_SPACE_SIZE) != 0) {
|
|
unit_err(m, "%s: failed to create register space\n",
|
|
__func__);
|
|
return UNIT_FAIL;
|
|
}
|
|
/* Create fuse register space */
|
|
if (nvgpu_posix_io_add_reg_space(g, GP10B_FUSE_REG_BASE, 0xfff) != 0) {
|
|
unit_err(m, "%s: failed to create register space\n",
|
|
__func__);
|
|
return UNIT_FAIL;
|
|
}
|
|
(void)nvgpu_posix_register_io(g, &test_reg_callbacks);
|
|
|
|
nvgpu_posix_io_writel_reg_space(g, mc_boot_0_r(), MC_BOOT_0_GV11B);
|
|
nvgpu_posix_io_writel_reg_space(g, GP10B_FUSE_OPT_PRIV_SEC_EN, 0x0);
|
|
|
|
if (nvgpu_detect_chip(g) != 0) {
|
|
unit_err(m, "%s: failed to init HAL\n", __func__);
|
|
return UNIT_FAIL;
|
|
}
|
|
|
|
/* override HALs */
|
|
g->ops.bus.isr = mock_bus_isr;
|
|
g->ops.ce.isr_stall = mock_ce_stall_isr;
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
g->ops.ce.isr_nonstall = mock_ce_nonstall_isr;
|
|
#endif
|
|
g->ops.fb.intr.isr = mock_fb_isr;
|
|
g->ops.fifo.intr_0_isr = mock_fifo_stall_isr;
|
|
g->ops.fifo.intr_1_isr = mock_fifo_nonstall_isr;
|
|
g->ops.gr.intr.stall_isr = mock_gr_stall_isr;
|
|
g->ops.gr.intr.nonstall_isr = mock_gr_nonstall_isr;
|
|
g->ops.ltc.intr.isr = mock_ltc_isr;
|
|
g->ops.pmu.pmu_isr = mock_pmu_isr;
|
|
g->ops.priv_ring.isr = mock_priv_ring_isr;
|
|
|
|
nvgpu_device_init(g);
|
|
|
|
/* setup engines for getting interrupt info */
|
|
g->fifo.g = g;
|
|
if (nvgpu_engine_setup_sw(g) != 0) {
|
|
unit_return_fail(m, "failed to setup engines\n");
|
|
}
|
|
|
|
/* setup LTC just enough */
|
|
g->ltc = nvgpu_kzalloc(g, sizeof(struct nvgpu_ltc));
|
|
if (g->ltc == NULL) {
|
|
unit_return_fail(m, "failed to alloc\n");
|
|
}
|
|
g->ltc->ltc_count = 1;
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_mc_free_env(struct unit_module *m, struct gk20a *g, void *args)
|
|
{
|
|
/* Free mc register space */
|
|
nvgpu_posix_io_delete_reg_space(g, MC_ADDR_SPACE_START);
|
|
nvgpu_posix_io_delete_reg_space(g, GP10B_FUSE_REG_BASE);
|
|
|
|
nvgpu_engine_cleanup_sw(g);
|
|
|
|
nvgpu_kfree(g, g->ltc);
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_unit_config(struct unit_module *m, struct gk20a *g, void *args)
|
|
{
|
|
u32 invalid_units[] = {NUM_MC_UNITS, INVALID_UNIT, U32_MAX};
|
|
u32 i;
|
|
u32 unit;
|
|
u32 val;
|
|
|
|
/* clear regs */
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, 0x0);
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, 0x0);
|
|
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_SET_REG, 0x0);
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_CLEAR_REG, 0x0);
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_SET_REG, 0x0);
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_CLEAR_REG, 0x0);
|
|
|
|
for (i = 0; i < NUM_MC_UNITS; i++) {
|
|
unit = mc_units[i].num;
|
|
|
|
/* enable stall intr */
|
|
nvgpu_cic_mon_intr_stall_unit_config(g, unit, true);
|
|
val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG);
|
|
if ((val & mc_units[i].bit) == 0) {
|
|
unit_return_fail(m, "failed to enable stall intr for unit %u val=0x%08x\n",
|
|
unit, val);
|
|
}
|
|
|
|
/* disable stall intr */
|
|
nvgpu_cic_mon_intr_stall_unit_config(g, unit, false);
|
|
val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG);
|
|
if ((val & mc_units[i].bit) != 0) {
|
|
unit_return_fail(m, "failed to disable stall intr for unit %u val=0x%08x\n",
|
|
unit, val);
|
|
}
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
/* enable nonstall intr */
|
|
nvgpu_cic_mon_intr_nonstall_unit_config(g, unit, true);
|
|
val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG);
|
|
if ((val & mc_units[i].bit) == 0) {
|
|
unit_return_fail(m, "failed to enable nonstall intr for unit %u val=0x%08x\n",
|
|
unit, val);
|
|
}
|
|
|
|
/* disable stall intr */
|
|
nvgpu_cic_mon_intr_nonstall_unit_config(g, unit, false);
|
|
val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG);
|
|
if ((val & mc_units[i].bit) != 0) {
|
|
unit_return_fail(m, "failed to disable nonstall intr for unit %u val=0x%08x\n",
|
|
unit, val);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
for (i = 0; i < ARRAY_SIZE(invalid_units); i++) {
|
|
/* negative testing - invalid unit enable set - stall */
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, 0x0); /* clear en reg */
|
|
nvgpu_cic_mon_intr_stall_unit_config(g, invalid_units[i], true);
|
|
val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG);
|
|
if (val != 0U) {
|
|
unit_return_fail(m, "Incorrectly enabled stall interrupt for invalid unit, val=0x%08x\n",
|
|
val);
|
|
}
|
|
|
|
/* negative testing - invalid unit enable clear - stall */
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, U32_MAX); /* set en reg */
|
|
nvgpu_cic_mon_intr_stall_unit_config(g, invalid_units[i], false);
|
|
val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG);
|
|
if (val != U32_MAX) {
|
|
unit_return_fail(m, "Incorrectly disabled stall interrupt for invalid unit, val=0x%08x\n",
|
|
val);
|
|
}
|
|
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
/* negative testing - invalid unit enable set - nonstall */
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, 0x0); /* clear en reg */
|
|
nvgpu_cic_mon_intr_nonstall_unit_config(g, invalid_units[i], true);
|
|
val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG);
|
|
if (val != 0U) {
|
|
unit_return_fail(m, "Incorrectly enabled non-stall interrupt for invalid unit, val=0x%08x\n",
|
|
val);
|
|
}
|
|
|
|
/* negative testing - invalid unit enable clear - nonstall */
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, U32_MAX); /* set en reg */
|
|
nvgpu_cic_mon_intr_nonstall_unit_config(g, invalid_units[i], false);
|
|
val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG);
|
|
if (val != U32_MAX) {
|
|
unit_return_fail(m, "Incorrectly enabled non-stall interrupt for invalid unit, val=0x%08x\n",
|
|
val);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_pause_resume_mask(struct unit_module *m, struct gk20a *g, void *args)
|
|
{
|
|
u32 val;
|
|
u32 expected_stall_val = mc_intr_priv_ring_pending_f();
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
u32 expected_nonstall_val = mc_intr_pbus_pending_f();
|
|
#endif
|
|
void (*save_func)(struct gk20a *g);
|
|
|
|
/* clear regs */
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_REG, 0x0);
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_REG, 0x0);
|
|
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_SET_REG, 0x0);
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_CLEAR_REG, 0x0);
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_SET_REG, 0x0);
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_CLEAR_REG, 0x0);
|
|
|
|
/* cleanup anything from previous tests */
|
|
g->mc.intr_mask_restore[0] = 0U;
|
|
g->mc.intr_mask_restore[1] = 0U;
|
|
|
|
/* enable something to pause and resume */
|
|
nvgpu_cic_mon_intr_stall_unit_config(g, NVGPU_CIC_INTR_UNIT_PRIV_RING, true);
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
nvgpu_cic_mon_intr_nonstall_unit_config(g, NVGPU_CIC_INTR_UNIT_BUS, true);
|
|
#endif
|
|
|
|
/* pause stall */
|
|
nvgpu_cic_mon_intr_stall_pause(g);
|
|
val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG);
|
|
if (val != 0) {
|
|
unit_return_fail(m, "failed to pause stall intr\n");
|
|
}
|
|
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
/* pause nonstall */
|
|
nvgpu_cic_mon_intr_nonstall_pause(g);
|
|
val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG);
|
|
if (val != 0) {
|
|
unit_return_fail(m, "failed to pause nonstall intr\n");
|
|
}
|
|
#endif
|
|
|
|
/* resume stall */
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_SET_REG, 0x0);
|
|
nvgpu_cic_mon_intr_stall_resume(g);
|
|
val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG);
|
|
if (val != expected_stall_val) {
|
|
unit_return_fail(m, "failed to resume stall intr\n");
|
|
}
|
|
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
/* resume nonstall */
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_SET_REG, 0x0);
|
|
nvgpu_cic_mon_intr_nonstall_resume(g);
|
|
val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG);
|
|
if (val != expected_nonstall_val) {
|
|
unit_return_fail(m, "failed to resume nonstall intr\n");
|
|
}
|
|
#endif
|
|
|
|
/* clear regs */
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_EN_CLEAR_REG, 0x0);
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_EN_CLEAR_REG, 0x0);
|
|
#endif
|
|
|
|
/* mask all */
|
|
nvgpu_cic_mon_intr_mask(g);
|
|
val = nvgpu_posix_io_readl_reg_space(g, STALL_EN_REG);
|
|
if (val != 0) {
|
|
unit_return_fail(m, "failed to mask stall intr\n");
|
|
}
|
|
val = nvgpu_posix_io_readl_reg_space(g, NONSTALL_EN_REG);
|
|
if (val != 0) {
|
|
unit_return_fail(m, "failed to mask nonstall intr\n");
|
|
}
|
|
|
|
/* make this HAL NULL for branch coverage */
|
|
save_func = g->ops.mc.intr_mask;
|
|
g->ops.mc.intr_mask = NULL;
|
|
nvgpu_cic_mon_intr_mask(g);
|
|
g->ops.mc.intr_mask = save_func;
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_intr_stall(struct unit_module *m, struct gk20a *g, void *args)
|
|
{
|
|
u32 i, pend, val;
|
|
|
|
for (i = 0; i < 32; i++) {
|
|
pend = (1 << i);
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, pend);
|
|
val = g->ops.mc.intr_stall(g);
|
|
if (val != pend) {
|
|
unit_return_fail(m, "incorrect stall value returned\n");
|
|
}
|
|
}
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_is_stall_and_eng_intr_pending(struct unit_module *m, struct gk20a *g,
|
|
void *args)
|
|
{
|
|
u32 act_eng_id = 0; /* GR engine */
|
|
u32 eng_intr_pending = 0;
|
|
u32 intrs_pending = 0;
|
|
u32 expected_eng_intr_pending = 0;
|
|
bool result;
|
|
unsigned int i;
|
|
|
|
/* test with nothing pending */
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, 0);
|
|
result = g->ops.mc.is_stall_and_eng_intr_pending(g, act_eng_id,
|
|
&eng_intr_pending);
|
|
if (result) {
|
|
unit_return_fail(m, "incorrect value returned\n");
|
|
}
|
|
|
|
/* test with everything pending */
|
|
for (i = 0U; i < NUM_MC_UNITS; i++) {
|
|
intrs_pending |= mc_units[i].bit;
|
|
if (mc_units[i].num == NVGPU_CIC_INTR_UNIT_GR) {
|
|
expected_eng_intr_pending = mc_units[i].bit;
|
|
}
|
|
}
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending);
|
|
result = g->ops.mc.is_stall_and_eng_intr_pending(g, act_eng_id,
|
|
&eng_intr_pending);
|
|
if (!result || (eng_intr_pending != expected_eng_intr_pending)) {
|
|
unit_return_fail(m, "incorrect value returned\n");
|
|
}
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_isr_stall(struct unit_module *m, struct gk20a *g, void *args)
|
|
{
|
|
u32 intrs_pending = 0;
|
|
u32 i;
|
|
bool (*save_intr_hub_pending)(struct gk20a *g, u32 intr);
|
|
|
|
/* for branch coverage, test with nothing pending */
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, 0);
|
|
reset_ctx();
|
|
g->ops.mc.isr_stall(g);
|
|
if (u.bus_isr || u.ce_isr || u.fb_isr || u.fifo_isr || u.gr_isr ||
|
|
u.pmu_isr || u.priv_ring_isr) {
|
|
unit_return_fail(m, "unexpected ISR called\n");
|
|
}
|
|
|
|
/* setup regs for basic test with all units intr pending */
|
|
for (i = 0; i < NUM_MC_UNITS; i++) {
|
|
intrs_pending |= mc_units[i].bit;
|
|
}
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending);
|
|
nvgpu_posix_io_writel_reg_space(g, mc_intr_ltc_r(), 1U);
|
|
reset_ctx();
|
|
g->ops.mc.isr_stall(g);
|
|
if (u.bus_isr) {
|
|
unit_return_fail(m, "BUS ISR called from Stall\n");
|
|
}
|
|
if (!u.ce_isr || !u.fb_isr || !u.fifo_isr || !u.gr_isr ||
|
|
!u.pmu_isr || !u.priv_ring_isr) {
|
|
unit_return_fail(m, "not all ISRs called\n");
|
|
}
|
|
|
|
/* for branch coverage set this HAL to NULL */
|
|
save_intr_hub_pending = g->ops.mc.is_intr_hub_pending;
|
|
g->ops.mc.is_intr_hub_pending = NULL;
|
|
for (i = 0; i < NUM_MC_UNITS; i++) {
|
|
intrs_pending |= mc_units[i].bit;
|
|
}
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending);
|
|
reset_ctx();
|
|
g->ops.mc.isr_stall(g);
|
|
if (u.fb_isr) {
|
|
unit_return_fail(m, "unexpected ISR called\n");
|
|
}
|
|
g->ops.mc.is_intr_hub_pending = save_intr_hub_pending;
|
|
|
|
/* for branch coverage return error from GR ISR */
|
|
for (i = 0; i < NUM_MC_UNITS; i++) {
|
|
intrs_pending |= mc_units[i].bit;
|
|
}
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending);
|
|
reset_ctx();
|
|
u.gr_isr_return = -1;
|
|
g->ops.mc.isr_stall(g);
|
|
|
|
/* for branch coverage set this HAL to NULL */
|
|
g->ops.ce.isr_stall = NULL;
|
|
for (i = 0; i < NUM_MC_UNITS; i++) {
|
|
intrs_pending |= mc_units[i].bit;
|
|
}
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending);
|
|
reset_ctx();
|
|
g->ops.mc.isr_stall(g);
|
|
g->ops.ce.isr_stall = mock_ce_stall_isr;
|
|
|
|
/*
|
|
* for branch coverage set LTC intr in main intr reg, but not ltc
|
|
* intr reg
|
|
*/
|
|
for (i = 0; i < NUM_MC_UNITS; i++) {
|
|
intrs_pending |= mc_units[i].bit;
|
|
}
|
|
nvgpu_posix_io_writel_reg_space(g, STALL_PENDING_REG, intrs_pending);
|
|
nvgpu_posix_io_writel_reg_space(g, mc_intr_ltc_r(), 0U);
|
|
reset_ctx();
|
|
g->ops.mc.isr_stall(g);
|
|
if (u.ltc_isr) {
|
|
unit_return_fail(m, "unexpected ISR called\n");
|
|
}
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_is_intr1_pending(struct unit_module *m, struct gk20a *g, void *args)
|
|
{
|
|
struct match_struct {
|
|
u32 unit;
|
|
u32 mask;
|
|
bool expect;
|
|
};
|
|
const struct match_struct match_table[] = {
|
|
{ NVGPU_UNIT_FIFO, ~mc_enable_pfifo_enabled_f(), false },
|
|
{ NVGPU_UNIT_FIFO, mc_enable_pfifo_enabled_f(), true },
|
|
{ INVALID_UNIT, 0x0, false },
|
|
};
|
|
unsigned int i;
|
|
bool val;
|
|
|
|
for (i = 0; i < ARRAY_SIZE(match_table); i++) {
|
|
val = g->ops.mc.is_intr1_pending(g, match_table[i].unit,
|
|
match_table[i].mask);
|
|
if (val != match_table[i].expect) {
|
|
unit_return_fail(m, "incorrect stall value returned\n");
|
|
}
|
|
}
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_isr_nonstall(struct unit_module *m, struct gk20a *g, void *args)
|
|
{
|
|
u32 intrs_pending = 0;
|
|
u32 i;
|
|
u32 val;
|
|
|
|
/* for branch coverage, test with nothing pending */
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_PENDING_REG, 0);
|
|
reset_ctx();
|
|
val = g->ops.mc.isr_nonstall(g);
|
|
if (u.bus_isr || u.ce_isr || u.fb_isr || u.fifo_isr || u.gr_isr ||
|
|
u.priv_ring_isr) {
|
|
unit_return_fail(m, "unexpected ISR called\n");
|
|
}
|
|
|
|
/* setup regs for basic test with all units intr pending */
|
|
for (i = 0; i < NUM_MC_UNITS; i++) {
|
|
intrs_pending |= mc_units[i].bit;
|
|
}
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_PENDING_REG, intrs_pending);
|
|
reset_ctx();
|
|
u.ce_isr_return = 0x1;
|
|
u.fifo_isr_return = 0x2;
|
|
u.gr_isr_return = 0x4;
|
|
val = g->ops.mc.isr_nonstall(g);
|
|
if (!u.bus_isr || !u.ce_isr || !u.fifo_isr || !u.gr_isr) {
|
|
unit_return_fail(m, "not all ISRs called\n");
|
|
}
|
|
if (val != 0x7) {
|
|
unit_return_fail(m, "incorrect ops returned 0x%08x\n", val);
|
|
}
|
|
|
|
/* for branch coverage set this HAL to NULL */
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
g->ops.ce.isr_nonstall = NULL;
|
|
#endif
|
|
for (i = 0; i < NUM_MC_UNITS; i++) {
|
|
intrs_pending |= mc_units[i].bit;
|
|
}
|
|
nvgpu_posix_io_writel_reg_space(g, NONSTALL_PENDING_REG, intrs_pending);
|
|
reset_ctx();
|
|
g->ops.mc.isr_nonstall(g);
|
|
#ifdef CONFIG_NVGPU_NONSTALL_INTR
|
|
g->ops.ce.isr_nonstall = mock_ce_nonstall_isr;
|
|
#endif
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
int test_enable_disable_reset(struct unit_module *m, struct gk20a *g, void *args)
|
|
{
|
|
u32 units = (mc_enable_pfifo_enabled_f() |
|
|
mc_enable_pgraph_enabled_f() |
|
|
mc_enable_blg_enabled_f() | mc_enable_ce2_enabled_f());
|
|
u32 val;
|
|
|
|
/* test enable */
|
|
nvgpu_posix_io_writel_reg_space(g, mc_enable_r(), 0);
|
|
g->ops.mc.enable_units(g, (NVGPU_UNIT_FIFO | NVGPU_UNIT_GRAPH |
|
|
NVGPU_UNIT_BLG | NVGPU_UNIT_CE2), true);
|
|
val = nvgpu_posix_io_readl_reg_space(g, mc_enable_r());
|
|
if (val != units) {
|
|
unit_return_fail(m, "failed to reset units val=0x%08x\n", val);
|
|
}
|
|
|
|
/* test disable */
|
|
g->ops.mc.enable_units(g, (NVGPU_UNIT_FIFO | NVGPU_UNIT_GRAPH |
|
|
NVGPU_UNIT_BLG | NVGPU_UNIT_CE2), false);
|
|
val = nvgpu_posix_io_readl_reg_space(g, mc_enable_r());
|
|
if (val != 0U) {
|
|
unit_return_fail(m, "failed to reset units val=0x%08x\n", val);
|
|
}
|
|
|
|
/* test reset */
|
|
nvgpu_posix_io_writel_reg_space(g, mc_enable_r(), units);
|
|
nvgpu_mc_reset_units(g, (NVGPU_UNIT_FIFO | NVGPU_UNIT_GRAPH |
|
|
NVGPU_UNIT_BLG | NVGPU_UNIT_CE2));
|
|
val = nvgpu_posix_io_readl_reg_space(g, mc_enable_r());
|
|
if (val != units) {
|
|
unit_return_fail(m, "failed to reset units val=0x%08x\n", val);
|
|
}
|
|
|
|
return UNIT_SUCCESS;
|
|
}
|
|
|
|
struct unit_module_test mc_tests[] = {
|
|
UNIT_TEST(mc_setup_env, test_mc_setup_env, NULL, 0),
|
|
UNIT_TEST(unit_config, test_unit_config, NULL, 2),
|
|
UNIT_TEST(pause_resume_mask, test_pause_resume_mask, NULL, 0),
|
|
UNIT_TEST(intr_stall, test_intr_stall, NULL, 0),
|
|
UNIT_TEST(intr_is_stall_and_eng_intr_pending,
|
|
test_is_stall_and_eng_intr_pending, NULL, 2),
|
|
UNIT_TEST(isr_stall, test_isr_stall, NULL, 2),
|
|
UNIT_TEST(isr_nonstall, test_isr_nonstall, NULL, 2),
|
|
UNIT_TEST(is_intr1_pending, test_is_intr1_pending, NULL, 0),
|
|
UNIT_TEST(enable_disable_reset, test_enable_disable_reset, NULL, 0),
|
|
UNIT_TEST(mc_free_env, test_mc_free_env, NULL, 0),
|
|
};
|
|
|
|
UNIT_MODULE(mc, mc_tests, UNIT_PRIO_NVGPU_TEST);
|