mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 09:12:24 +03:00
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:
committed by
Alex Waterman
parent
ce6fc269a1
commit
92d5c53c59
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -78,7 +78,8 @@ UNITS := \
|
||||
$(UNIT_SRC)/mm/nvgpu_mem \
|
||||
$(UNIT_SRC)/mm/vm \
|
||||
$(UNIT_SRC)/netlist \
|
||||
$(UNIT_SRC)/fbp \
|
||||
$(UNIT_SRC)/fb \
|
||||
$(UNIT_SRC)/fbp \
|
||||
$(UNIT_SRC)/fifo \
|
||||
$(UNIT_SRC)/fifo/fifo/gk20a \
|
||||
$(UNIT_SRC)/fifo/fifo/gv11b \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
27
userspace/units/fb/Makefile
Normal file
27
userspace/units/fb/Makefile
Normal 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
|
||||
23
userspace/units/fb/Makefile.interface.tmk
Normal file
23
userspace/units/fb/Makefile.interface.tmk
Normal 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:
|
||||
25
userspace/units/fb/Makefile.tmk
Normal file
25
userspace/units/fb/Makefile.tmk
Normal 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:
|
||||
158
userspace/units/fb/fb_fusa.c
Normal file
158
userspace/units/fb/fb_fusa.c
Normal 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);
|
||||
389
userspace/units/fb/fb_fusa.h
Normal file
389
userspace/units/fb/fb_fusa.h
Normal 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 */
|
||||
184
userspace/units/fb/fb_gm20b_fusa.c
Normal file
184
userspace/units/fb/fb_gm20b_fusa.c
Normal 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;
|
||||
}
|
||||
112
userspace/units/fb/fb_gv11b_fusa.c
Normal file
112
userspace/units/fb/fb_gv11b_fusa.c
Normal 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;
|
||||
}
|
||||
211
userspace/units/fb/fb_intr_gv11b_fusa.c
Normal file
211
userspace/units/fb/fb_intr_gv11b_fusa.c
Normal 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;
|
||||
}
|
||||
301
userspace/units/fb/fb_mmu_fault_gv11b_fusa.c
Normal file
301
userspace/units/fb/fb_mmu_fault_gv11b_fusa.c
Normal 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;
|
||||
}
|
||||
Reference in New Issue
Block a user