summaryrefslogblamecommitdiffstats
path: root/drivers/gpu/nvgpu/gv11b/ltc_gv11b.c
blob: 9f9ff3371c7c38df88412d368ef43be8b1ceccf0 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


            
                                                                     
  





                                                                             
  









                                                                             

   

                            



                                        
                                       
                                        
                                       
                                                   
 


                                             
                                                     













                                                                         
                                             



                     
                                                 
 






                                                          

                                                                   
                                                                               
 













                                                                     
                                   











                                                                       
                                               
                                 
                                                     

































                                                                                                                     
                                                                                   

                                                                                                                        
                                                                                       








                                                                                                                  
                                                                                                                              
                                                         
                                                                                                                                  



























                                                                                                                
                                                                        
                                      
                                                                          






                                           
/*
 * GV11B LTC
 *
 * Copyright (c) 2016-2018, 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 "gk20a/gk20a.h"
#include "gp10b/ltc_gp10b.h"

#include "ltc_gv11b.h"

#include <nvgpu/hw/gv11b/hw_ltc_gv11b.h>
#include <nvgpu/hw/gv11b/hw_mc_gv11b.h>
#include <nvgpu/hw/gv11b/hw_top_gv11b.h>
#include <nvgpu/hw/gv11b/hw_mc_gv11b.h>
#include <nvgpu/hw/gv11b/hw_pri_ringmaster_gv11b.h>

/*
 * Sets the ZBC stencil for the passed index.
 */
void gv11b_ltc_set_zbc_stencil_entry(struct gk20a *g,
					  struct zbc_entry *stencil_val,
					  u32 index)
{
	u32 real_index = index + GK20A_STARTOF_ZBC_TABLE;

	gk20a_writel(g, ltc_ltcs_ltss_dstg_zbc_index_r(),
		     ltc_ltcs_ltss_dstg_zbc_index_address_f(real_index));

	gk20a_writel(g, ltc_ltcs_ltss_dstg_zbc_stencil_clear_value_r(),
		     stencil_val->depth);

	gk20a_readl(g, ltc_ltcs_ltss_dstg_zbc_index_r());
}

void gv11b_ltc_init_fs_state(struct gk20a *g)
{
	u32 ltc_intr;
	u32 reg;

	nvgpu_log_info(g, "initialize gv11b l2");

	g->ops.mc.reset(g, mc_enable_pfb_enabled_f() |
				mc_enable_l2_enabled_f());

	reg = gk20a_readl(g, mc_elpg_enable_r());
	reg |= mc_elpg_enable_l2_enabled_f();
	gk20a_writel(g, mc_elpg_enable_r(), reg);

	g->max_ltc_count = gk20a_readl(g, top_num_ltcs_r());
	g->ltc_count = gk20a_readl(g, pri_ringmaster_enum_ltc_r());
	nvgpu_log_info(g, "%u ltcs out of %u", g->ltc_count, g->max_ltc_count);

	/* Disable LTC interrupts */
	reg = gk20a_readl(g, ltc_ltcs_ltss_intr_r());
	reg &= ~ltc_ltcs_ltss_intr_en_evicted_cb_m();
	reg &= ~ltc_ltcs_ltss_intr_en_illegal_compstat_access_m();
	gk20a_writel(g, ltc_ltcs_ltss_intr_r(), reg);

	/* Enable ECC interrupts */
	ltc_intr = gk20a_readl(g, ltc_ltcs_ltss_intr_r());
	ltc_intr |= ltc_ltcs_ltss_intr_en_ecc_sec_error_enabled_f() |
		ltc_ltcs_ltss_intr_en_ecc_ded_error_enabled_f();
	gk20a_writel(g, ltc_ltcs_ltss_intr_r(),
				ltc_intr);
}

void gv11b_ltc_isr(struct gk20a *g)
{
	u32 mc_intr, ltc_intr3;
	unsigned int ltc, slice;
	u32 ltc_stride = nvgpu_get_litter_value(g, GPU_LIT_LTC_STRIDE);
	u32 lts_stride = nvgpu_get_litter_value(g, GPU_LIT_LTS_STRIDE);
	u32 ecc_status, ecc_addr, corrected_cnt, uncorrected_cnt;
	u32 corrected_delta, uncorrected_delta;
	u32 corrected_overflow, uncorrected_overflow;
	u32 ltc_corrected, ltc_uncorrected;

	mc_intr = gk20a_readl(g, mc_intr_ltc_r());
	for (ltc = 0; ltc < g->ltc_count; ltc++) {
		if ((mc_intr & 1U << ltc) == 0)
			continue;
		ltc_corrected = ltc_uncorrected = 0U;

		for (slice = 0; slice < g->gr.slices_per_ltc; slice++) {
			u32 offset = ltc_stride * ltc + lts_stride * slice;
			ltc_intr3 = gk20a_readl(g, ltc_ltc0_lts0_intr3_r() +
						offset);

			/* Detect and handle ECC PARITY errors */

			if (ltc_intr3 &
				(ltc_ltcs_ltss_intr3_ecc_uncorrected_m() |
				 ltc_ltcs_ltss_intr3_ecc_corrected_m())) {

				ecc_status = gk20a_readl(g,
					ltc_ltc0_lts0_l2_cache_ecc_status_r() +
					offset);
				ecc_addr = gk20a_readl(g,
					ltc_ltc0_lts0_l2_cache_ecc_address_r() +
					offset);
				corrected_cnt = gk20a_readl(g,
					ltc_ltc0_lts0_l2_cache_ecc_corrected_err_count_r() + offset);
				uncorrected_cnt = gk20a_readl(g,
					ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_r() + offset);

				corrected_delta =
					ltc_ltc0_lts0_l2_cache_ecc_corrected_err_count_total_v(corrected_cnt);
				uncorrected_delta =
					ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_total_v(uncorrected_cnt);
				corrected_overflow = ecc_status &
					ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_total_counter_overflow_m();

				uncorrected_overflow = ecc_status &
					ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_total_counter_overflow_m();

				/* clear the interrupt */
				if ((corrected_delta > 0U) || corrected_overflow) {
					gk20a_writel(g, ltc_ltc0_lts0_l2_cache_ecc_corrected_err_count_r() + offset, 0);
				}
				if ((uncorrected_delta > 0U) || uncorrected_overflow) {
					gk20a_writel(g,
						ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_r() + offset, 0);
				}

				gk20a_writel(g, ltc_ltc0_lts0_l2_cache_ecc_status_r() + offset,
					ltc_ltc0_lts0_l2_cache_ecc_status_reset_task_f());

				/* update counters per slice */
				if (corrected_overflow)
					corrected_delta += (0x1U << ltc_ltc0_lts0_l2_cache_ecc_corrected_err_count_total_s());
				if (uncorrected_overflow)
					uncorrected_delta += (0x1U << ltc_ltc0_lts0_l2_cache_ecc_uncorrected_err_count_total_s());

				ltc_corrected += corrected_delta;
				ltc_uncorrected += uncorrected_delta;
				nvgpu_log(g, gpu_dbg_intr,
					"ltc:%d lts: %d cache ecc interrupt intr: 0x%x", ltc, slice, ltc_intr3);

				if (ecc_status & ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_rstg_m())
					nvgpu_log(g, gpu_dbg_intr, "rstg ecc error corrected");
				if (ecc_status & ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_rstg_m())
					nvgpu_log(g, gpu_dbg_intr, "rstg ecc error uncorrected");
				if (ecc_status & ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_tstg_m())
					nvgpu_log(g, gpu_dbg_intr, "tstg ecc error corrected");
				if (ecc_status & ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_tstg_m())
					nvgpu_log(g, gpu_dbg_intr, "tstg ecc error uncorrected");
				if (ecc_status & ltc_ltc0_lts0_l2_cache_ecc_status_corrected_err_dstg_m())
					nvgpu_log(g, gpu_dbg_intr, "dstg ecc error corrected");
				if (ecc_status & ltc_ltc0_lts0_l2_cache_ecc_status_uncorrected_err_dstg_m())
					nvgpu_log(g, gpu_dbg_intr, "dstg ecc error uncorrected");

				if (corrected_overflow || uncorrected_overflow)
					nvgpu_info(g, "ecc counter overflow!");

				nvgpu_log(g, gpu_dbg_intr,
					"ecc error address: 0x%x", ecc_addr);

			}

		}
		g->ecc.ltc.l2_cache_corrected_err_count.counters[ltc] +=
			ltc_corrected;
		g->ecc.ltc.l2_cache_uncorrected_err_count.counters[ltc] +=
			ltc_uncorrected;

	}

	/* fallback to other interrupts  */
	gp10b_ltc_isr(g);
}