gpu: nvgpu: unit: add fb HAL unit tests

Unit tests covering the FB related HALs.

JIRA NVGPU-932

Change-Id: I46de25ea2a495e22ca6485d1fae1778261a804bd
Signed-off-by: Nicolas Benech <nbenech@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/2259666
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
Nicolas Benech
2019-12-10 18:12:57 -05:00
committed by Alex Waterman
parent ce6fc269a1
commit 92d5c53c59
14 changed files with 1467 additions and 7 deletions

View File

@@ -70,6 +70,7 @@ NV_REPOSITORY_COMPONENTS += userspace/units/mm/mm
NV_REPOSITORY_COMPONENTS += userspace/units/mm/page_table_faults
NV_REPOSITORY_COMPONENTS += userspace/units/mm/vm
NV_REPOSITORY_COMPONENTS += userspace/units/netlist
NV_REPOSITORY_COMPONENTS += userspace/units/fb
NV_REPOSITORY_COMPONENTS += userspace/units/fbp
NV_REPOSITORY_COMPONENTS += userspace/units/fifo
NV_REPOSITORY_COMPONENTS += userspace/units/fifo/channel

View File

@@ -3,10 +3,7 @@
bitmap_find_next_zero_area_off
bug_handler_cancel
bug_handler_register
gv11b_fb_read_mmu_fault_buffer_size
gv11b_fb_read_mmu_fault_status
gv11b_fb_write_mmu_fault_buffer_lo_hi
gv11b_fb_write_mmu_fault_buffer_size
fb_gv11b_write_mmu_fault_buffer_get
find_first_bit
find_first_zero_bit
find_next_bit
@@ -39,7 +36,15 @@ gk20a_vm_release_share
gm20b_channel_bind
gm20b_channel_force_ctx_reload
gm20b_device_info_parse_enum
gm20b_fb_dump_vpr_info
gm20b_fb_dump_wpr_info
gm20b_fb_mmu_ctrl
gm20b_fb_mmu_debug_ctrl
gm20b_fb_mmu_debug_rd
gm20b_fb_mmu_debug_wr
gm20b_fb_read_wpr_info
gm20b_fb_tlb_invalidate
gm20b_fb_vpr_info_fetch
gm20b_gr_falcon_get_fecs_ctx_state_store_major_rev_id
gm20b_is_engine_gr
gm20b_mm_get_big_page_sizes
@@ -100,13 +105,33 @@ gv11b_channel_debug_dump
gv11b_channel_read_state
gv11b_channel_reset_faulted
gv11b_channel_unbind
gv11b_fb_intr_enable
gv11b_fb_ecc_free
gv11b_fb_ecc_init
gv11b_fb_fault_buf_configure_hw
gv11b_fb_fault_buf_set_state_hw
gv11b_fb_fault_buffer_get_ptr_update
gv11b_fb_fault_buffer_size_val
gv11b_fb_handle_bar2_fault
gv11b_fb_handle_mmu_fault
gv11b_fb_init_fs_state
gv11b_fb_init_hw
gv11b_fb_is_fault_buf_enabled
gv11b_fb_intr_disable
gv11b_fb_intr_enable
gv11b_fb_intr_is_mmu_fault_pending
gv11b_fb_intr_isr
gv11b_fb_is_fault_buf_enabled
gv11b_fb_is_fault_buffer_empty
gv11b_fb_mmu_fault_info_dump
gv11b_fb_read_mmu_fault_addr_lo_hi
gv11b_fb_read_mmu_fault_buffer_get
gv11b_fb_read_mmu_fault_buffer_put
gv11b_fb_read_mmu_fault_buffer_size
gv11b_fb_read_mmu_fault_info
gv11b_fb_read_mmu_fault_inst_lo_hi
gv11b_fb_read_mmu_fault_status
gv11b_fb_write_mmu_fault_buffer_lo_hi
gv11b_fb_write_mmu_fault_buffer_size
gv11b_fb_write_mmu_fault_status
gv11b_fifo_handle_sched_error
gv11b_fifo_intr_0_enable
gv11b_fifo_intr_0_isr
@@ -119,6 +144,7 @@ gv11b_init_fifo_reset_enable_hw
gv11b_init_fifo_setup_hw
gv11b_init_hal
gv11b_is_fault_engine_subid_gpc
gv11b_mm_copy_from_fault_snap_reg
gv11b_mm_is_bar1_supported
gv11b_mm_init_inst_block
gv11b_mm_l2_flush

View File

@@ -78,6 +78,7 @@ UNITS := \
$(UNIT_SRC)/mm/nvgpu_mem \
$(UNIT_SRC)/mm/vm \
$(UNIT_SRC)/netlist \
$(UNIT_SRC)/fb \
$(UNIT_SRC)/fbp \
$(UNIT_SRC)/fifo \
$(UNIT_SRC)/fifo/fifo/gk20a \

View File

@@ -74,6 +74,7 @@
* - @ref SWUTS-mm-page_table_faults
* - @ref SWUTS-mm-mm
* - @ref SWUTS-mm-vm
* - @ref SWUTS-fb
* - @ref SWUTS-fbp
* - @ref SWUTS-fuse
* - @ref SWUTS-posix-bitops

View File

@@ -7,6 +7,7 @@ INPUT += ../../../userspace/units/interface/rbtree/rbtree.h
INPUT += ../../../userspace/units/falcon/falcon_tests/nvgpu-falcon.h
INPUT += ../../../userspace/units/netlist/nvgpu-netlist.h
INPUT += ../../../userspace/units/fbp/nvgpu-fbp.h
INPUT += ../../../userspace/units/fb/fb_fusa.h
INPUT += ../../../userspace/units/fifo/channel/nvgpu-channel.h
INPUT += ../../../userspace/units/fifo/channel/gk20a/nvgpu-channel-gk20a.h
INPUT += ../../../userspace/units/fifo/channel/gm20b/nvgpu-channel-gm20b.h

View File

@@ -0,0 +1,27 @@
# 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.
.SUFFIXES:
OBJS = fb_fusa.o fb_gv11b_fusa.o fb_gm20b_fusa.o fb_mmu_fault_gv11b_fusa.o \
fb_intr_gv11b_fusa.o
MODULE = fb
include ../Makefile.units

View File

@@ -0,0 +1,23 @@
################################### tell Emacs this is a -*- makefile-gmake -*-
#
# Copyright (c) 2019, NVIDIA CORPORATION. All Rights Reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#
# tmake for SW Mobile component makefile
#
###############################################################################
NVGPU_UNIT_NAME=fb
include $(NV_COMPONENT_DIR)/../Makefile.units.common.interface.tmk
# Local Variables:
# indent-tabs-mode: t
# tab-width: 8
# End:
# vi: set tabstop=8 noexpandtab:

View File

@@ -0,0 +1,25 @@
################################### tell Emacs this is a -*- makefile-gmake -*-
#
# Copyright (c) 2019, NVIDIA CORPORATION. All Rights Reserved.
#
# NVIDIA CORPORATION and its licensors retain all intellectual property
# and proprietary rights in and to this software, related documentation
# and any modifications thereto. Any use, reproduction, disclosure or
# distribution of this software and related documentation without an express
# license agreement from NVIDIA CORPORATION is strictly prohibited.
#
# tmake for SW Mobile component makefile
#
###############################################################################
NVGPU_UNIT_NAME=fb
NVGPU_UNIT_SRCS=fb_fusa.c fb_gv11b_fusa.c fb_gm20b_fusa.c \
fb_mmu_fault_gv11b_fusa.c fb_intr_gv11b_fusa.c
include $(NV_COMPONENT_DIR)/../Makefile.units.common.tmk
# Local Variables:
# indent-tabs-mode: t
# tab-width: 8
# End:
# vi: set tabstop=8 noexpandtab:

View File

@@ -0,0 +1,158 @@
/*
* 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 <unit/unit.h>
#include <unit/io.h>
#include <nvgpu/posix/io.h>
#include <nvgpu/posix/posix-fault-injection.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/io.h>
#include "hal/fb/intr/fb_intr_gv11b.h"
#include <nvgpu/hw/gv11b/hw_fb_gv11b.h>
#include <nvgpu/hw/gv11b/hw_mc_gv11b.h>
#include "fb_fusa.h"
static bool intercept_mmu_invalidate;
static u32 intercept_fb_mmu_ctrl_r;
void helper_intercept_mmu_write(u32 val)
{
intercept_fb_mmu_ctrl_r = val;
intercept_mmu_invalidate = true;
}
/*
* Write callback (for all nvgpu_writel calls).
*/
static void writel_access_reg_fn(struct gk20a *g,
struct nvgpu_reg_access *access)
{
if (intercept_mmu_invalidate &&
(access->addr == fb_mmu_invalidate_pdb_r())) {
intercept_mmu_invalidate = false;
nvgpu_writel(g, fb_mmu_ctrl_r(), intercept_fb_mmu_ctrl_r);
}
nvgpu_posix_io_writel_reg_space(g, access->addr, access->value);
nvgpu_posix_io_record_access(g, access);
}
/*
* Read callback, similar to the write callback above.
*/
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);
}
/*
* Define all the callbacks to be used during the test. Typically all
* write operations use the same callback, likewise for all read operations.
*/
static struct nvgpu_posix_io_callbacks fb_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,
};
static int fb_gv11b_init(struct unit_module *m, struct gk20a *g, void *args)
{
nvgpu_posix_register_io(g, &fb_callbacks);
nvgpu_posix_io_init_reg_space(g);
/* Register space: FB */
if (nvgpu_posix_io_add_reg_space(g, fb_niso_intr_r(), SZ_4K) != 0) {
unit_return_fail(m, "nvgpu_posix_io_add_reg_space failed FB\n");
}
/* Register space: MC_INTR */
if (nvgpu_posix_io_add_reg_space(g, mc_intr_r(0), SZ_1K) != 0) {
unit_return_fail(m, "nvgpu_posix_io_add_reg_space failed MC\n");
}
/* Register space: HSHUB */
if (nvgpu_posix_io_add_reg_space(g, fb_hshub_num_active_ltcs_r(),
SZ_256) != 0) {
unit_return_fail(m,
"nvgpu_posix_io_add_reg_space failed HSHUB\n");
}
/* Register space: FBHUB */
if (nvgpu_posix_io_add_reg_space(g, fb_fbhub_num_active_ltcs_r(),
SZ_256) != 0) {
unit_return_fail(m,
"nvgpu_posix_io_add_reg_space failed FBHUB\n");
}
return UNIT_SUCCESS;
}
static int fb_gv11b_cleanup(struct unit_module *m, struct gk20a *g, void *args)
{
/* Unregister space: FB */
nvgpu_posix_io_delete_reg_space(g, fb_niso_intr_r());
nvgpu_posix_io_delete_reg_space(g, mc_intr_r(0));
nvgpu_posix_io_delete_reg_space(g, fb_hshub_num_active_ltcs_r());
nvgpu_posix_io_delete_reg_space(g, fb_fbhub_num_active_ltcs_r());
return UNIT_SUCCESS;
}
struct unit_module_test fb_tests[] = {
UNIT_TEST(fb_gv11b_init, fb_gv11b_init, NULL, 0),
UNIT_TEST(fb_gv11b_init_test, fb_gv11b_init_test, NULL, 0),
UNIT_TEST(fb_gm20b_tlb_invalidate_test, fb_gm20b_tlb_invalidate_test,
NULL, 0),
UNIT_TEST(fb_gm20b_mmu_ctrl_test, fb_gm20b_mmu_ctrl_test, NULL, 0),
UNIT_TEST(fb_mmu_fault_gv11b_init_test, fb_mmu_fault_gv11b_init_test,
NULL, 0),
UNIT_TEST(fb_mmu_fault_gv11b_buffer_test,
fb_mmu_fault_gv11b_buffer_test, NULL, 0),
UNIT_TEST(fb_mmu_fault_gv11b_snap_reg, fb_mmu_fault_gv11b_snap_reg,
NULL, 0),
UNIT_TEST(fb_mmu_fault_gv11b_handle_fault,
fb_mmu_fault_gv11b_handle_fault, NULL, 0),
UNIT_TEST(fb_mmu_fault_gv11b_handle_bar2_fault,
fb_mmu_fault_gv11b_handle_bar2_fault, NULL, 0),
UNIT_TEST(fb_intr_gv11b_init_test, fb_intr_gv11b_init_test, NULL, 0),
UNIT_TEST(fb_intr_gv11b_isr_test, fb_intr_gv11b_isr_test, NULL, 0),
UNIT_TEST(fb_intr_gv11b_ecc_test_L2TLB, fb_intr_gv11b_ecc_test,
(void *) TEST_ECC_L2TLB, 0),
UNIT_TEST(fb_intr_gv11b_ecc_test_HUBTLB, fb_intr_gv11b_ecc_test,
(void *) TEST_ECC_HUBTLB, 0),
UNIT_TEST(fb_intr_gv11b_ecc_test_FILLUNIT, fb_intr_gv11b_ecc_test,
(void *) TEST_ECC_FILLUNIT, 0),
UNIT_TEST(fb_gv11b_cleanup, fb_gv11b_cleanup, NULL, 0),
};
UNIT_MODULE(fb, fb_tests, UNIT_PRIO_NVGPU_TEST);

View File

@@ -0,0 +1,389 @@
/*
* 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.
*/
#ifndef UNIT_NVGPU_FB_H
#define UNIT_NVGPU_FB_H
struct gk20a;
struct unit_module;
/** @addtogroup SWUTS-fb
* @{
*
* Software Unit Test Specification for nvgpu.hal.fb
*/
/**
* Test specification for: fb_gv11b_init_test
*
* Description: Tests the init HALs for GV11B.
*
* Targets: nvgpu_ecc_init_support, gv11b_fb_init_hw, gv11b_fb_init_fs_state,
* gv11b_fb_ecc_init, gv11b_fb_ecc_free
*
* Test Type: Feature based, Init, Error injection
*
* Input: None
*
* Steps:
* - Set up the ops function pointer for all the HALs under test.
* - Initialize the g->mm structure with arbitrary addresses.
* - Call the ecc_init_support HAL to initialize ECC support.
* - Call the init_hw HAL and ensure the FB_NISO mask was set.
* - Call the init_fs_state HAL and ensure atomic mode was set in the MMU
* control register.
* - Perform dynamic memory error injection on the fb_ecc_init HAL to ensure
* it fails as expected.
* - Call the fb_ecc_init HAL and ensure it succeeds.
* - Call the fb_ecc_free HAL to free dynamic memory.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_gv11b_init_test(struct unit_module *m, struct gk20a *g, void *args);
/**
* Test specification for: fb_gm20b_tlb_invalidate_test
*
* Description: .
*
* Targets: gm20b_fb_tlb_invalidate
*
* Test Type: Feature based, Error injection
*
* Input: None
*
* Steps:
* - Initialize ops.fb.tlb_invalidate pointer to gm20b_fb_tlb_invalidate HAL.
* - Create a test nvgpu_mem PDB with SYSMEM aperture.
* - While the NVGPU is powered off, call gm20b_fb_tlb_invalidate and ensure
* it returned success.
* - The power on state of NVGPU.
* - Enable timer error injection (1st occurnce), call gm20b_fb_tlb_invalidate
* and ensure it failed.
* - Call gm20b_fb_tlb_invalidate again and check that it still failed (because
* the fb_mmu_ctrl_r register is not set properly)
* - Set the fb_mmu_ctrl_pri_fifo_space_v bit in fb_mmu_ctrl_r register.
* - Enable timer error injection (2nd occurnce), call gm20b_fb_tlb_invalidate
* and ensure it failed.
* - Using an helper during register writes, intercept writes to fb_mmu_ctrl_r
* to cause a timeout after the MMU invalidate. Ensure that
* gm20b_fb_tlb_invalidate returns a failure.
* - Set the fb_mmu_ctrl_pri_fifo_space_v bit again, and set the intercept
* helper to write the fb_mmu_ctrl_pri_fifo_empty_v bit upon a write to
* fb_mmu_ctrl_r. Ensure that gm20b_fb_tlb_invalidate succeeds.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_gm20b_tlb_invalidate_test(struct unit_module *m, struct gk20a *g,
void *args);
/**
* Test specification for: fb_gm20b_mmu_ctrl_test
*
* Description: Test GM20B HALs targeting MMU features.
*
* Targets: gm20b_fb_mmu_ctrl, gm20b_fb_mmu_debug_ctrl, gm20b_fb_mmu_debug_wr,
* gm20b_fb_mmu_debug_rd, gm20b_fb_vpr_info_fetch, gm20b_fb_dump_vpr_info,
* gm20b_fb_dump_wpr_info, gm20b_fb_read_wpr_info
*
* Test Type: Feature based, Error injection
*
* Input: None
*
* Steps:
* - Set up the ops function pointer for all the HALs under test.
* - Program an arbitrary value in the fb_mmu_ctrl_r register and ensure the
* gm20b_fb_mmu_ctrl HAL returns the same value.
* - Program an arbitrary value in the fb_mmu_debug_ctrl_r register and ensure
* the gm20b_fb_mmu_debug_ctrl HAL returns the same value.
* - Program an arbitrary value in the fb_mmu_debug_wr_r register and ensure the
* gm20b_fb_mmu_debug_wr HAL returns the same value.
* - Program an arbitrary value in the fb_mmu_debug_rd_r register and ensure the
* gm20b_fb_mmu_debug_rd HAL returns the same value.
* - Call the VPR/WPR dump operations for code coverage. Ensure that none of
* those operations cause a crash.
* - Enable timer error injection (1st occurnce), call gm20b_fb_vpr_info_fetch
* and ensure it failed.
* - Write in the fb_mmu_vpr_info register so that calling
* gm20b_fb_vpr_info_fetch triggers timeout in the
* gm20b_fb_vpr_info_fetch_wait function. Ensure the return values reflects
* a timeout.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_gm20b_mmu_ctrl_test(struct unit_module *m, struct gk20a *g, void *args);
/**
* Test specification for: fb_mmu_fault_gv11b_init_test
*
* Description: Init test to setup HAL pointers for FB_MMU fault testing.
*
* Targets: None
*
* Test Type: Init
*
* Input: None
*
* Steps:
* - Set up the ops function pointer for all the HALs under test.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_mmu_fault_gv11b_init_test(struct unit_module *m, struct gk20a *g,
void *args);
/**
* Test specification for: fb_mmu_fault_gv11b_buffer_test
*
* Description: Ensure all HAL functions work without causing an ABORT.
*
* Targets: gv11b_fb_is_fault_buf_enabled, gv11b_fb_fault_buffer_get_ptr_update,
* gv11b_fb_write_mmu_fault_buffer_size, gv11b_fb_fault_buf_set_state_hw,
* gv11b_fb_read_mmu_fault_status, gv11b_fb_fault_buf_configure_hw
*
* Test Type: Feature based
*
* Input: fb_mmu_fault_gv11b_init_test
*
* Steps:
* - Call gv11b_fb_fault_buffer_get_ptr_update.
* - Set the overflow bit in the fb_mmu_fault_buffer_get_r(0) register, and call
* gv11b_fb_fault_buffer_get_ptr_update.
* - Call gv11b_fb_fault_buffer_size_val and check that the fault buffer is
* empty.
* - Call the gv11b_fb_fault_buf_configure_hw HAL and enable fault buffer.
* - Enable fault buffer again which shouldn't cause any crash.
* - Disable the fault buffer.
* - Enable fault buffer, set the busy bit in fb_mmu_fault_status_r register,
* disable the fault buffer which should cause an internal timeout. Ensure
* that the fault buffer is disabled anyway.
* - Write test values in the fb_mmu_fault_addr_lo_r / fb_mmu_fault_addr_hi_r
* registers, call gv11b_fb_read_mmu_fault_addr_lo_hi and ensure the
* returned values match the test values.
* - Write test values in the fb_mmu_fault_inst_lo_r / fb_mmu_fault_inst_hi_r
* registers, call gv11b_fb_read_mmu_fault_inst_lo_hi and ensure the
* returned values match the test values.
* - Call the gv11b_fb_read_mmu_fault_info HAL and ensure it returns the same
* value as in the fb_mmu_fault_info_r register.
* - Call the gv11b_fb_write_mmu_fault_status HAL to write a test value, then
* read the fb_mmu_fault_status_r register to ensure it is the same value.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_mmu_fault_gv11b_buffer_test(struct unit_module *m, struct gk20a *g,
void *args);
/**
* Test specification for: fb_mmu_fault_gv11b_snap_reg
*
* Description: Test that gv11b_mm_copy_from_fault_snap_reg behaves correctly
* if the reported fault is valid/invalid.
*
* Targets: gv11b_mm_copy_from_fault_snap_reg
*
* Test Type: Feature based
*
* Input: fb_mmu_fault_gv11b_init_test
*
* Steps:
* - Create a test mmu_fault_info instance.
* - Call gv11b_mm_copy_from_fault_snap_reg with an invalid fault bit and
* ensure the chid of the mmu_fault_info was just set to a default value of 0.
* - Call gv11b_mm_copy_from_fault_snap_reg again with a valid fault bit and
* ensure the chid of the mmu_fault_info is now set to
* NVGPU_INVALID_CHANNEL_ID.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_mmu_fault_gv11b_snap_reg(struct unit_module *m, struct gk20a *g,
void *args);
/**
* Test specification for: fb_mmu_fault_gv11b_handle_fault
*
* Description: Test the gv11b_fb_handle_mmu_fault HAL for all supported
* interrupt statuses.
*
* Targets: gv11b_fb_handle_mmu_fault, gv11b_fb_fault_buf_set_state_hw
*
* Test Type: Feature based
*
* Input: fb_mmu_fault_gv11b_init_test
*
* Steps:
* - Call gv11b_fb_handle_mmu_fault with an interrupt source set to "other"
* and ensure it was handled by checking the "valid_clear" bit of the
* fb_mmu_fault_status_r register.
* - Enable the fault buffer.
* - Set interrupt source as dropped and ensure it is handled by
* gv11b_fb_handle_mmu_fault.
* - Repeat with a source as non-replayable.
* - Repeat with a source as non-replayable and overflow.
* - Repeat with a source as overflow and corrupted getptr.
* - Disable the fault buffer.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_mmu_fault_gv11b_handle_fault(struct unit_module *m, struct gk20a *g,
void *args);
/**
* Test specification for: fb_mmu_fault_gv11b_handle_bar2_fault
*
* Description: Test the gv11b_fb_handle_bar2_fault HAL for all supported
* interrupt statuses.
*
* Targets: gv11b_fb_handle_bar2_fault, gv11b_fb_mmu_fault_info_dump,
* gv11b_fb_fault_buf_set_state_hw
*
* Test Type: Feature based
*
* Input: fb_mmu_fault_gv11b_init_test
*
* Steps:
* - Create zero'ed test instances of mmu_fault_info and nvgpu_channel.
* - Call gv11b_fb_handle_bar2_fault with a fault_status of 0.
* - Ensure the gv11b_fb_mmu_fault_info_dump HAL does not cause a crash when
* called with a NULL pointer or a zero'ed out mmu_fault_info structure.
* - Set the minimum set of properties in the mmu_fault_info structure (valid
* and a pointer to the channel)
* - Call the gv11b_fb_mmu_fault_info_dump and ensure it doesn't cause a crash.
* - Set the fault_status to non-replayable and call gv11b_fb_handle_bar2_fault.
* - Repeat with the fault buffer disabled.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_mmu_fault_gv11b_handle_bar2_fault(struct unit_module *m, struct gk20a *g,
void *args);
/**
* Test specification for: fb_intr_gv11b_init_test
*
* Description: Init test to setup HAL pointers for FB_INTR testing.
*
* Targets: None
*
* Test Type: Init
*
* Input: None
*
* Steps:
* - Set up the ops function pointer for all the HALs under test.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_intr_gv11b_init_test(struct unit_module *m, struct gk20a *g, void *args);
/**
* Test specification for: fb_intr_gv11b_isr_test
*
* Description: Test ISR handling with all supported types of interrupts.
*
* Targets: gv11b_fb_intr_enable, gv11b_fb_intr_disable, gv11b_fb_intr_isr
*
* Test Type: Feature based
*
* Input: fb_intr_gv11b_init_test
*
* Steps:
* - Mask all interrupts in the fb_niso_intr_en_set_r register.
* - Call the gv11b_fb_intr_enable HAL and ensure several interrupts are
* unmasked.
* - Set the fb_niso_intr_r register to 0 (no interrupt), and ensure that
* gv11b_fb_intr_is_mmu_fault_pending indicates that no fault is pending.
* - Call the gv11b_fb_intr_isr HAL.
* - Set interrupt source as "access counter notify/error" and call the
* gv11b_fb_intr_isr HAL (this will only cause a nvgpu_info call)
* - Set interrupt source as "MMU fault" and ensure that
* gv11b_fb_intr_is_mmu_fault_pending indicates that a fault is pending.
* - Set interrupt source as "ECC fault" and call the gv11b_fb_intr_isr HAL
* (further ECC testing is done in other tests).
* - Use the gv11b_fb_intr_disable HAL to disable interrupts.
* - Ensure that what was written in the clear register matches the interrupts
* that were enabled at the beginning of this test.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_intr_gv11b_isr_test(struct unit_module *m, struct gk20a *g, void *args);
/**
* Test specification for: fb_intr_gv11b_ecc_test
*
* Description: Tests handling of ECC errors.
*
* Targets: gv11b_fb_ecc_init, gv11b_fb_intr_isr, gv11b_fb_intr_handle_ecc,
* gv11b_fb_ecc_free
*
* Test Type: Feature based
*
* Input: fb_intr_gv11b_init_test, args as a subcase with one of these values:
* - TEST_ECC_L2TLB
* - TEST_ECC_HUBTLB
* - TEST_ECC_FILLUNIT
*
* Steps:
* - Based on the subcase passed as an argument to this test, select the
* appropriate values for each HW unit:
* - Address of the status register
* - Address of the corrected error count register
* - Address of the uncorrected error count register
* - Expected status mask for corrected errors
* - Expected status mask for uncorrected errors
* - Expected status mask for corrected errors overflow
* - Expected status mask for uncorrected errors overflow
* - Call the gv11b_fb_ecc_init HAL.
* - Test the hanlding of ISRs in the following cases:
* - Corrected error
* - Uncorrected error
* - Corrected error and overflow (with >0 number of errors)
* - Uncorrected error and overflow (with >0 number of errors)
* - Corrected and uncorrected with overflow and 0 errors.
* - In the case of FILLUNIT, also test the case of corrected and uncorrected
* PDE0 errors.
* - Clear the interrupt status register.
* - Call the gv11b_fb_ecc_free HAL.
*
* Output: Returns PASS if the steps above were executed successfully. FAIL
* otherwise.
*/
int fb_intr_gv11b_ecc_test(struct unit_module *m, struct gk20a *g, void *args);
/* Values below are used by the fb_intr_gv11b_ecc_test test. */
#define TEST_ECC_L2TLB 1U
#define TEST_ECC_HUBTLB 2U
#define TEST_ECC_FILLUNIT 3U
/* Helper function to intercept writes to the MMU status register. */
void helper_intercept_mmu_write(u32 val);
/** @} */
#endif /* UNIT_NVGPU_FB_H */

View File

@@ -0,0 +1,184 @@
/*
* 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 <unit/unit.h>
#include <unit/io.h>
#include <nvgpu/posix/io.h>
#include <nvgpu/posix/posix-fault-injection.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/io.h>
#include <nvgpu/nvgpu_init.h>
#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 <nvgpu/hw/gv11b/hw_fb_gv11b.h>
#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;
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");
}
/*
* 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 (2)\n");
}
return UNIT_SUCCESS;
}

View File

@@ -0,0 +1,112 @@
/*
* 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 <unit/unit.h>
#include <unit/io.h>
#include <nvgpu/posix/io.h>
#include <nvgpu/posix/posix-fault-injection.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/io.h>
#include <nvgpu/nvgpu_init.h>
#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 <nvgpu/hw/gv11b/hw_fb_gv11b.h>
#include "fb_fusa.h"
int fb_gv11b_init_test(struct unit_module *m, struct gk20a *g, void *args)
{
int err;
struct nvgpu_posix_fault_inj *kmem_fi =
nvgpu_kmem_get_fault_injection();
/* Define the operations being targeted in this unit test */
g->ops.ecc.ecc_init_support = nvgpu_ecc_init_support;
g->ops.fb.init_hw = gv11b_fb_init_hw;
g->ops.fb.init_fs_state = gv11b_fb_init_fs_state;
g->ops.fb.fb_ecc_init = gv11b_fb_ecc_init;
g->ops.fb.fb_ecc_free = gv11b_fb_ecc_free;
/* Other HALs */
g->ops.mc.intr_stall_unit_config = mc_gp10b_intr_stall_unit_config;
g->ops.mc.intr_nonstall_unit_config =
mc_gp10b_intr_nonstall_unit_config;
g->ops.fb.intr.enable = gv11b_fb_intr_enable;
/*
* Define some arbitrary addresses for test purposes.
* Note: no need to malloc any memory as this unit only needs to trigger
* MMU faults via register mocking. No other memory accesses are done.
*/
g->mm.sysmem_flush.cpu_va = (void *) 0x10000000;
g->mm.mmu_wr_mem.cpu_va = (void *) 0x20000000;
g->mm.mmu_wr_mem.aperture = APERTURE_SYSMEM;
g->mm.mmu_rd_mem.cpu_va = (void *) 0x30000000;
g->mm.mmu_rd_mem.aperture = APERTURE_SYSMEM;
g->ops.ecc.ecc_init_support(g);
nvgpu_writel(g, fb_niso_intr_en_set_r(0), 0);
g->ops.fb.init_hw(g);
/* Ensure that g->ops.fb.intr.enable set up a mask */
if (nvgpu_readl(g, fb_niso_intr_en_set_r(0)) == 0) {
unit_return_fail(m, "FB_NISO mask not set\n");
}
g->ops.fb.init_fs_state(g);
/* Ensure atomic mode was enabled */
if ((nvgpu_readl(g, fb_mmu_ctrl_r()) &
fb_mmu_ctrl_atomic_capability_mode_m()) == 0) {
unit_return_fail(m, "Atomic mode not set\n");
}
/* For branch coverage */
nvgpu_set_enabled(g, NVGPU_SEC_PRIVSECURITY, true);
g->ops.fb.init_fs_state(g);
nvgpu_set_enabled(g, NVGPU_SEC_PRIVSECURITY, false);
/*
* gv11b_fb_ecc_init initializes 5 structures via kmem. Test the failure
* of all of them.
*/
for (int i = 0; i < 5; i++) {
nvgpu_posix_enable_fault_injection(kmem_fi, true, i);
err = g->ops.fb.fb_ecc_init(g);
nvgpu_posix_enable_fault_injection(kmem_fi, false, 0);
if (err != -ENOMEM) {
unit_return_fail(m, "gv11b_fb_ecc_init did not fail as expected (%d)\n", i);
}
}
err = g->ops.fb.fb_ecc_init(g);
if (err != 0) {
unit_return_fail(m, "gv11b_fb_ecc_init failed\n");
}
g->ops.fb.fb_ecc_free(g);
return UNIT_SUCCESS;
}

View File

@@ -0,0 +1,211 @@
/*
* 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 <unit/unit.h>
#include <unit/io.h>
#include <nvgpu/posix/io.h>
#include <nvgpu/posix/posix-fault-injection.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/sizes.h>
#include <nvgpu/io.h>
#include <nvgpu/nvgpu_init.h>
#include "hal/mc/mc_gp10b.h"
#include "hal/fb/fb_gm20b.h"
#include "hal/fb/fb_gv11b.h"
#include "hal/fb/fb_mmu_fault_gv11b.h"
#include "hal/fb/intr/fb_intr_gv11b.h"
#include <nvgpu/hw/gv11b/hw_fb_gv11b.h>
#include <nvgpu/hw/gv11b/hw_mc_gv11b.h>
#include "fb_fusa.h"
/* Arbitrary number of errors */
#define ECC_ERRORS 15U
int fb_intr_gv11b_init_test(struct unit_module *m, struct gk20a *g, void *args)
{
/* HALs under test */
g->ops.fb.fb_ecc_init = gv11b_fb_ecc_init;
g->ops.fb.fb_ecc_free = gv11b_fb_ecc_free;
return UNIT_SUCCESS;
}
int fb_intr_gv11b_isr_test(struct unit_module *m, struct gk20a *g, void *args)
{
/* Mask all interrupts */
nvgpu_writel(g, fb_niso_intr_en_set_r(0), 0);
/* Enable interrupts */
gv11b_fb_intr_enable(g);
if (nvgpu_readl(g, fb_niso_intr_en_set_r(0)) == 0) {
unit_return_fail(m, "FB_INTR not unmasked\n");
}
/* Set INTR status register to 0, i.e. no interrupt */
nvgpu_writel(g, fb_niso_intr_r(), 0);
if (gv11b_fb_intr_is_mmu_fault_pending(g)) {
unit_return_fail(m, "MMU fault should NOT be pending\n");
}
gv11b_fb_intr_isr(g);
/* Hub access counter notify/error: just causes a nvgpu_info call */
nvgpu_writel(g, fb_niso_intr_r(),
fb_niso_intr_hub_access_counter_notify_m());
gv11b_fb_intr_isr(g);
/* MMU fault: testing of MMU fault handling is done in other tests */
nvgpu_writel(g, fb_niso_intr_r(),
fb_niso_intr_mmu_other_fault_notify_m());
if (!gv11b_fb_intr_is_mmu_fault_pending(g)) {
unit_return_fail(m, "MMU fault should be pending\n");
}
gv11b_fb_intr_isr(g);
/* ECC fault: testing of ECC fault handling is done in other tests */
nvgpu_writel(g, fb_niso_intr_r(),
fb_niso_intr_mmu_ecc_uncorrected_error_notify_pending_f());
gv11b_fb_intr_isr(g);
/* Disable interrupts */
gv11b_fb_intr_disable(g);
/*
* In real HW it may not be possible to read the set/clear registers but
* here we can, and what was programmed in the set register should be
* the same as what was programmed in the clear register.
*/
if (nvgpu_readl(g, fb_niso_intr_en_set_r(0)) !=
nvgpu_readl(g, fb_niso_intr_en_clr_r(0))) {
unit_return_fail(m, "FB_INTR set/clear mismatch\n");
}
return UNIT_SUCCESS;
}
struct gv11b_ecc_test_parameters {
u32 status_reg;
u32 corrected_err_reg;
u32 uncorrected_err_reg;
u32 corrected_status, uncorrected_status;
u32 corrected_overflow, uncorrected_overflow;
};
static struct gv11b_ecc_test_parameters l2tlb_parameters = {
.status_reg = fb_mmu_l2tlb_ecc_status_r(),
.corrected_err_reg = fb_mmu_l2tlb_ecc_corrected_err_count_r(),
.uncorrected_err_reg = fb_mmu_l2tlb_ecc_uncorrected_err_count_r(),
.corrected_status = fb_mmu_l2tlb_ecc_status_corrected_err_l2tlb_sa_data_m(),
.uncorrected_status = fb_mmu_l2tlb_ecc_status_uncorrected_err_l2tlb_sa_data_m(),
.corrected_overflow = fb_mmu_l2tlb_ecc_status_corrected_err_total_counter_overflow_m(),
.uncorrected_overflow = fb_mmu_l2tlb_ecc_status_uncorrected_err_total_counter_overflow_m(),
};
static struct gv11b_ecc_test_parameters hubtlb_parameters = {
.status_reg = fb_mmu_hubtlb_ecc_status_r(),
.corrected_err_reg = fb_mmu_hubtlb_ecc_corrected_err_count_r(),
.uncorrected_err_reg = fb_mmu_hubtlb_ecc_uncorrected_err_count_r(),
.corrected_status = fb_mmu_hubtlb_ecc_status_corrected_err_sa_data_m(),
.uncorrected_status = fb_mmu_hubtlb_ecc_status_uncorrected_err_sa_data_m(),
.corrected_overflow = fb_mmu_hubtlb_ecc_status_corrected_err_total_counter_overflow_m(),
.uncorrected_overflow = fb_mmu_hubtlb_ecc_status_uncorrected_err_total_counter_overflow_m(),
};
static struct gv11b_ecc_test_parameters fillunit_parameters = {
.status_reg = fb_mmu_fillunit_ecc_status_r(),
.corrected_err_reg = fb_mmu_fillunit_ecc_corrected_err_count_r(),
.uncorrected_err_reg = fb_mmu_fillunit_ecc_uncorrected_err_count_r(),
.corrected_status = fb_mmu_fillunit_ecc_status_corrected_err_pte_data_m(),
.uncorrected_status = fb_mmu_fillunit_ecc_status_uncorrected_err_pte_data_m(),
.corrected_overflow = fb_mmu_fillunit_ecc_status_corrected_err_total_counter_overflow_m(),
.uncorrected_overflow = fb_mmu_fillunit_ecc_status_uncorrected_err_total_counter_overflow_m(),
};
int fb_intr_gv11b_ecc_test(struct unit_module *m, struct gk20a *g, void *args)
{
struct gv11b_ecc_test_parameters *p;
u64 subcase = (u64) args;
switch (subcase) {
case TEST_ECC_L2TLB:
p = &l2tlb_parameters;
break;
case TEST_ECC_HUBTLB:
p = &hubtlb_parameters;
break;
case TEST_ECC_FILLUNIT:
p = &fillunit_parameters;
break;
default:
unit_return_fail(m, "Invalid subcase\n");
}
g->ops.fb.fb_ecc_init(g);
/* Set the interrupt status as corrected */
nvgpu_writel(g, p->status_reg, p->corrected_status);
gv11b_fb_intr_isr(g);
/* Set the interrupt status as uncorrected */
nvgpu_writel(g, p->status_reg, p->uncorrected_status);
gv11b_fb_intr_isr(g);
/* Set arbitrary number of corrected and uncorrected errors */
nvgpu_writel(g, p->corrected_err_reg, ECC_ERRORS);
nvgpu_writel(g, p->uncorrected_err_reg, ECC_ERRORS);
gv11b_fb_intr_isr(g);
/* Same but with corrected overflow bit set */
nvgpu_writel(g, p->status_reg, 1 | p->corrected_overflow);
nvgpu_writel(g, p->corrected_err_reg, ECC_ERRORS);
nvgpu_writel(g, p->uncorrected_err_reg, ECC_ERRORS);
gv11b_fb_intr_isr(g);
/* Same but with uncorrected overflow bit set */
nvgpu_writel(g, p->status_reg, 1 | p->uncorrected_overflow);
nvgpu_writel(g, p->corrected_err_reg, ECC_ERRORS);
nvgpu_writel(g, p->uncorrected_err_reg, ECC_ERRORS);
gv11b_fb_intr_isr(g);
/* Both overflow but error counts at 0 */
nvgpu_writel(g, p->status_reg, 1 | p->corrected_overflow |
p->uncorrected_overflow);
nvgpu_writel(g, p->corrected_err_reg, 0);
nvgpu_writel(g, p->uncorrected_err_reg, 0);
gv11b_fb_intr_isr(g);
/* Extra case for fillunit */
if (subcase == TEST_ECC_FILLUNIT) {
/* PDE0 */
nvgpu_writel(g, p->status_reg,
fb_mmu_fillunit_ecc_status_corrected_err_pde0_data_m() |
fb_mmu_fillunit_ecc_status_uncorrected_err_pde0_data_m());
gv11b_fb_intr_isr(g);
}
/* Clear interrupt status */
nvgpu_writel(g, p->status_reg, 0);
g->ops.fb.fb_ecc_free(g);
return UNIT_SUCCESS;
}

View File

@@ -0,0 +1,301 @@
/*
* 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 <unit/unit.h>
#include <unit/io.h>
#include <nvgpu/posix/io.h>
#include <nvgpu/posix/posix-fault-injection.h>
#include <unistd.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/io.h>
#include <nvgpu/nvgpu_init.h>
#include "hal/mc/mc_gp10b.h"
#include "hal/fb/fb_gm20b.h"
#include "hal/fb/fb_gv11b.h"
#include "hal/fb/fb_mmu_fault_gv11b.h"
#include "hal/fb/intr/fb_intr_gv11b.h"
#include <nvgpu/hw/gv11b/hw_fb_gv11b.h>
#include "fb_fusa.h"
#define FAULT_STATUS_TEST_VAL 0x101U
#define TEST_VALUE_1 0x80801234
#define TEST_VALUE_2 0xABCD4567
static u32 hal_channel_count(struct gk20a *g)
{
/* Reasonable channel count for the purpose of this test */
return 0x00000200U;
}
static void hal_bar2_fault_nop(struct gk20a *g)
{
/* no-op */
}
static int hal_bar2_bind_nop(struct gk20a *g, struct nvgpu_mem *bar2_inst)
{
/* no-op */
return 0;
}
static u32 hal_fifo_mmu_fault_id_to_pbdma_id(struct gk20a *g, u32 mmu_fault_id)
{
return INVAL_ID;
}
int fb_mmu_fault_gv11b_init_test(struct unit_module *m, struct gk20a *g,
void *args)
{
/* HALs under test */
g->ops.fb.read_mmu_fault_buffer_size =
gv11b_fb_read_mmu_fault_buffer_size;
g->ops.fb.read_mmu_fault_buffer_get =
gv11b_fb_read_mmu_fault_buffer_get;
g->ops.fb.read_mmu_fault_buffer_put =
gv11b_fb_read_mmu_fault_buffer_put;
g->ops.fb.write_mmu_fault_buffer_get =
fb_gv11b_write_mmu_fault_buffer_get;
g->ops.fb.is_fault_buf_enabled = gv11b_fb_is_fault_buf_enabled;
g->ops.fb.fault_buf_set_state_hw = gv11b_fb_fault_buf_set_state_hw;
g->ops.fb.write_mmu_fault_buffer_size =
gv11b_fb_write_mmu_fault_buffer_size;
g->ops.fb.read_mmu_fault_status = gv11b_fb_read_mmu_fault_status;
g->ops.fb.fault_buf_configure_hw = gv11b_fb_fault_buf_configure_hw;
g->ops.fb.write_mmu_fault_buffer_lo_hi =
gv11b_fb_write_mmu_fault_buffer_lo_hi;
g->ops.fb.read_mmu_fault_addr_lo_hi =
gv11b_fb_read_mmu_fault_addr_lo_hi;
g->ops.fb.read_mmu_fault_inst_lo_hi =
gv11b_fb_read_mmu_fault_inst_lo_hi;
g->ops.fb.read_mmu_fault_info = gv11b_fb_read_mmu_fault_info;
g->ops.fb.write_mmu_fault_status = gv11b_fb_write_mmu_fault_status;
/* Other HALs that are needed */
g->ops.channel.count = hal_channel_count;
g->ops.ce.mthd_buffer_fault_in_bar2_fault = hal_bar2_fault_nop;
g->ops.bus.bar2_bind = hal_bar2_bind_nop;
g->ops.fifo.mmu_fault_id_to_pbdma_id =
hal_fifo_mmu_fault_id_to_pbdma_id;
return UNIT_SUCCESS;
}
int fb_mmu_fault_gv11b_buffer_test(struct unit_module *m, struct gk20a *g,
void *args)
{
u32 get_idx;
u32 val;
u32 lo, hi;
if (g->ops.fb.is_fault_buf_enabled(g, 0)) {
unit_return_fail(m, "fault buffer not disabled as expected\n");
}
/* Standard case */
gv11b_fb_fault_buffer_get_ptr_update(g, 0, 0);
/* Overflow situation */
nvgpu_writel(g, fb_mmu_fault_buffer_get_r(0),
fb_mmu_fault_buffer_get_overflow_m());
gv11b_fb_fault_buffer_get_ptr_update(g, 0, 0);
gv11b_fb_fault_buffer_size_val(g, 0);
if (!gv11b_fb_is_fault_buffer_empty(g, 0, &get_idx)) {
unit_return_fail(m, "fault buffer not empty as expected\n");
}
/* Fault buffer hw setup */
g->ops.fb.fault_buf_configure_hw(g, 0);
/* Enable fault buffer */
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_ENABLED);
/* Enabling again shouldn't cause an issue */
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_ENABLED);
/* Disable */
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_DISABLED);
/* Try to disable again, but cause a timeout as fault status is set */
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_ENABLED);
nvgpu_writel(g, fb_mmu_fault_status_r(),
fb_mmu_fault_status_busy_true_f());
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_DISABLED);
if (g->ops.fb.is_fault_buf_enabled(g, 0)) {
unit_return_fail(m, "fault buffer not disabled as expected\n");
}
nvgpu_writel(g, fb_mmu_fault_addr_lo_r(), TEST_VALUE_1);
nvgpu_writel(g, fb_mmu_fault_addr_hi_r(), TEST_VALUE_2);
g->ops.fb.read_mmu_fault_addr_lo_hi(g, &lo, &hi);
if ((lo != TEST_VALUE_1) || (hi != TEST_VALUE_2)) {
unit_return_fail(m, "Invalid MMU fault address\n");
}
nvgpu_writel(g, fb_mmu_fault_inst_lo_r(), TEST_VALUE_1);
nvgpu_writel(g, fb_mmu_fault_inst_hi_r(), TEST_VALUE_2);
g->ops.fb.read_mmu_fault_inst_lo_hi(g, &lo, &hi);
if ((lo != TEST_VALUE_1) || (hi != TEST_VALUE_2)) {
unit_return_fail(m, "Invalid MMU fault inst\n");
}
val = g->ops.fb.read_mmu_fault_info(g);
if (val != nvgpu_readl(g, fb_mmu_fault_info_r())) {
unit_return_fail(m, "invalid fb_mmu_fault_info_r value\n");
}
g->ops.fb.write_mmu_fault_status(g, FAULT_STATUS_TEST_VAL);
if (nvgpu_readl(g, fb_mmu_fault_status_r()) != FAULT_STATUS_TEST_VAL) {
unit_return_fail(m, "invalid fb_mmu_fault_status_r value\n");
}
return UNIT_SUCCESS;
}
int fb_mmu_fault_gv11b_snap_reg(struct unit_module *m, struct gk20a *g,
void *args)
{
struct mmu_fault_info mmufault;
/* Not a valid fault, chid should just be zero'ed out by memset */
gv11b_mm_copy_from_fault_snap_reg(g, 0, &mmufault);
if (mmufault.chid != 0) {
unit_return_fail(m, "chid updated for invalid fault\n");
}
/* Valid fault */
gv11b_mm_copy_from_fault_snap_reg(g, fb_mmu_fault_status_valid_set_f(),
&mmufault);
if (mmufault.chid != NVGPU_INVALID_CHANNEL_ID) {
unit_return_fail(m, "chid NOT updated for valid fault\n");
}
return UNIT_SUCCESS;
}
static bool helper_is_intr_cleared(struct gk20a *g)
{
return (nvgpu_readl(g, fb_mmu_fault_status_r()) ==
fb_mmu_fault_status_valid_clear_f());
}
int fb_mmu_fault_gv11b_handle_fault(struct unit_module *m, struct gk20a *g,
void *args)
{
u32 niso_intr;
/* Set interrupt source as "other" and handle it */
niso_intr = fb_niso_intr_mmu_other_fault_notify_m();
nvgpu_writel(g, fb_mmu_fault_status_r(), 0);
gv11b_fb_handle_mmu_fault(g, niso_intr);
if (!helper_is_intr_cleared(g)) {
unit_return_fail(m, "unhandled interrupt (1)\n");
}
/* Enable fault buffer */
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_ENABLED);
/* Handle again for branch coverage */
gv11b_fb_handle_mmu_fault(g, niso_intr);
/* Set a valid dropped status and handle again */
nvgpu_writel(g, fb_mmu_fault_status_r(),
fb_mmu_fault_status_dropped_bar1_phys_set_f());
gv11b_fb_handle_mmu_fault(g, niso_intr);
if (!helper_is_intr_cleared(g)) {
unit_return_fail(m, "unhandled interrupt (2)\n");
}
/* Now set interrupt source as a non-replayable fault and handle it */
niso_intr = fb_niso_intr_mmu_nonreplayable_fault_notify_m();
nvgpu_writel(g, fb_mmu_fault_status_r(), 0);
gv11b_fb_handle_mmu_fault(g, niso_intr);
if (!helper_is_intr_cleared(g)) {
unit_return_fail(m, "unhandled interrupt (3)\n");
}
/* Now set source as non-replayable and overflow then handle it */
niso_intr = fb_niso_intr_mmu_nonreplayable_fault_notify_m() |
fb_niso_intr_mmu_nonreplayable_fault_overflow_m();
nvgpu_writel(g, fb_mmu_fault_status_r(), 0);
gv11b_fb_handle_mmu_fault(g, niso_intr);
if (!helper_is_intr_cleared(g)) {
unit_return_fail(m, "unhandled interrupt (4)\n");
}
/* Same case but ensure fault status register is also set properly */
nvgpu_writel(g, fb_mmu_fault_status_r(),
fb_mmu_fault_status_non_replayable_overflow_m());
nvgpu_writel(g, fb_mmu_fault_status_r(), 0);
gv11b_fb_handle_mmu_fault(g, niso_intr);
if (!helper_is_intr_cleared(g)) {
unit_return_fail(m, "unhandled interrupt (5)\n");
}
/* Case where getptr is reported as corrupted */
nvgpu_writel(g, fb_mmu_fault_status_r(),
fb_mmu_fault_status_non_replayable_overflow_m() |
fb_mmu_fault_status_non_replayable_getptr_corrupted_m());
nvgpu_writel(g, fb_mmu_fault_status_r(), 0);
gv11b_fb_handle_mmu_fault(g, niso_intr);
if (!helper_is_intr_cleared(g)) {
unit_return_fail(m, "unhandled interrupt (6)\n");
}
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_DISABLED);
return UNIT_SUCCESS;
}
int fb_mmu_fault_gv11b_handle_bar2_fault(struct unit_module *m, struct gk20a *g,
void *args)
{
struct mmu_fault_info mmufault;
struct nvgpu_channel refch;
u32 fault_status = 0;
(void) memset(&mmufault, 0, sizeof(mmufault));
(void) memset(&refch, 0, sizeof(refch));
gv11b_fb_handle_bar2_fault(g, &mmufault, fault_status);
/* Set the minimum mmufault struct to handle the fault */
/* First cover some error cases */
gv11b_fb_mmu_fault_info_dump(g, NULL);
gv11b_fb_mmu_fault_info_dump(g, &mmufault);
/* Now set it up properly */
mmufault.valid = true;
mmufault.refch = &refch;
gv11b_fb_mmu_fault_info_dump(g, &mmufault);
fault_status = fb_mmu_fault_status_non_replayable_error_m();
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_ENABLED);
gv11b_fb_handle_bar2_fault(g, &mmufault, fault_status);
/* Case where fault buffer is not enabled */
g->ops.fb.fault_buf_set_state_hw(g, 0, NVGPU_MMU_FAULT_BUF_DISABLED);
gv11b_fb_handle_bar2_fault(g, &mmufault, fault_status);
return UNIT_SUCCESS;
}