/* * Copyright (c) 2019, 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 #include #include #include #include #include #include #include "hal/mc/mc_gp10b.h" #include "hal/fb/fb_gm20b.h" #include "hal/fb/fb_gv11b.h" #include "hal/fb/intr/fb_intr_gv11b.h" #include #include "fb_fusa.h" #define TEST_REG_VALUE 0x8080A0A0 int fb_gm20b_tlb_invalidate_test(struct unit_module *m, struct gk20a *g, void *args) { int err; struct nvgpu_mem pdb = {0}; struct nvgpu_posix_fault_inj *timer_fi = nvgpu_timers_get_fault_injection(); /* Define the operations being tested in this unit test */ g->ops.fb.tlb_invalidate = gm20b_fb_tlb_invalidate; /* Setup PDB */ pdb.aperture = APERTURE_SYSMEM; /* First NVGPU is powered off */ err = g->ops.fb.tlb_invalidate(g, &pdb); if (err != 0) { unit_return_fail(m, "tlb_invalidate failed (1)\n"); } /* Set NVGPU as powered on */ g->power_on_state = NVGPU_STATE_POWERED_ON; /* Timeout init fault injection (MMU FIFO space) */ nvgpu_posix_enable_fault_injection(timer_fi, true, 0); err = g->ops.fb.tlb_invalidate(g, &pdb); if (err != -ETIMEDOUT) { unit_return_fail(m, "tlb_invalidate did not fail as expected (1)\n"); } nvgpu_posix_enable_fault_injection(timer_fi, false, 0); /* Timeout fail on fb_mmu_ctrl_r() read */ err = g->ops.fb.tlb_invalidate(g, &pdb); if (err != -ETIMEDOUT) { unit_return_fail(m, "tlb_invalidate did not fail as expected (2)\n"); } /* * Prevent timeout on fb_mmu_ctrl_r() by setting a non-zero value in * the fb_mmu_ctrl_pri_fifo_space_v field. */ nvgpu_writel(g, fb_mmu_ctrl_r(), 1 << 16U); /* Timeout init fault injection (MMU invalidate) */ nvgpu_posix_enable_fault_injection(timer_fi, true, 1); err = g->ops.fb.tlb_invalidate(g, &pdb); if (err != -ETIMEDOUT) { unit_return_fail(m, "tlb_invalidate did not fail as expected (3)\n"); } nvgpu_posix_enable_fault_injection(timer_fi, false, 0); /* * Timeout on fb_mmu_ctrl_r read after MMU invalidate (does not return * a failure) */ helper_intercept_mmu_write(0); err = g->ops.fb.tlb_invalidate(g, &pdb); if (err != 0) { unit_return_fail(m, "tlb_invalidate failed (2)\n"); } /* Success */ nvgpu_writel(g, fb_mmu_ctrl_r(), 1 << 16U); helper_intercept_mmu_write(1 << 15U); err = g->ops.fb.tlb_invalidate(g, &pdb); if (err != 0) { unit_return_fail(m, "tlb_invalidate failed (3)\n"); } return UNIT_SUCCESS; } int fb_gm20b_mmu_ctrl_test(struct unit_module *m, struct gk20a *g, void *args) { int err; u64 wpr_base, wpr_size; struct nvgpu_posix_fault_inj *timer_fi = nvgpu_timers_get_fault_injection(); /* Define the operations being tested in this unit test */ g->ops.fb.mmu_ctrl = gm20b_fb_mmu_ctrl; g->ops.fb.mmu_debug_ctrl = gm20b_fb_mmu_debug_ctrl; g->ops.fb.mmu_debug_wr = gm20b_fb_mmu_debug_wr; g->ops.fb.mmu_debug_rd = gm20b_fb_mmu_debug_rd; g->ops.fb.vpr_info_fetch = gm20b_fb_vpr_info_fetch; g->ops.fb.dump_vpr_info = gm20b_fb_dump_vpr_info; g->ops.fb.dump_wpr_info = gm20b_fb_dump_wpr_info; g->ops.fb.read_wpr_info = gm20b_fb_read_wpr_info; /* g->ops.mmu_ctrl must return the value in fb_mmu_ctrl_r */ nvgpu_writel(g, fb_mmu_ctrl_r(), TEST_REG_VALUE); if (g->ops.fb.mmu_ctrl(g) != TEST_REG_VALUE) { unit_return_fail(m, "ops.mmu_ctrl: incorrect value\n"); } /* g->ops.mmu_debug_ctrl must return the value in fb_mmu_debug_ctrl_r */ nvgpu_writel(g, fb_mmu_debug_ctrl_r(), TEST_REG_VALUE); if (g->ops.fb.mmu_debug_ctrl(g) != TEST_REG_VALUE) { unit_return_fail(m, "ops.mmu_debug_ctrl: incorrect value\n"); } /* g->ops.mmu_debug_wr must return the value in fb_mmu_debug_wr_r */ nvgpu_writel(g, fb_mmu_debug_wr_r(), TEST_REG_VALUE); if (g->ops.fb.mmu_debug_wr(g) != TEST_REG_VALUE) { unit_return_fail(m, "ops.mmu_debug_wr: incorrect value\n"); } /* g->ops.mmu_debug_rd must return the value in fb_mmu_debug_rd_r */ nvgpu_writel(g, fb_mmu_debug_rd_r(), TEST_REG_VALUE); if (g->ops.fb.mmu_debug_rd(g) != TEST_REG_VALUE) { unit_return_fail(m, "ops.mmu_debug_rd: incorrect value\n"); } /* For code coverage, run the VPR/WPR dump ops */ g->ops.fb.dump_vpr_info(g); g->ops.fb.dump_wpr_info(g); g->ops.fb.read_wpr_info(g, &wpr_base, &wpr_size); g->ops.fb.vpr_info_fetch(g); /* Error injection for g->ops.fb.vpr_info_fetch */ nvgpu_posix_enable_fault_injection(timer_fi, true, 0); err = g->ops.fb.vpr_info_fetch(g); nvgpu_posix_enable_fault_injection(timer_fi, false, 0); if (err != -ETIMEDOUT) { unit_return_fail(m, "vpr_info_fetch did not fail as expected (1)\n"); } nvgpu_posix_enable_fault_injection(timer_fi, true, 1); err = g->ops.fb.vpr_info_fetch(g); nvgpu_posix_enable_fault_injection(timer_fi, false, 0); if (err != -ETIMEDOUT) { unit_return_fail(m, "vpr_info_fetch did not fail as expected (2)\n"); } /* * Trigger timeout in the gm20b_fb_vpr_info_fetch_wait function on * fb_mmu_vpr_info_fetch_v(val) == fb_mmu_vpr_info_fetch_false_v() */ nvgpu_writel(g, fb_mmu_vpr_info_r(), 1 << 2U); err = g->ops.fb.vpr_info_fetch(g); if (err != -ETIMEDOUT) { unit_return_fail(m, "vpr_info_fetch did not fail as expected (3)\n"); } return UNIT_SUCCESS; }