mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-24 10:34:43 +03:00
Remove ltc_common.c and integrate the included functions into device specific ltc_gXXXX.c files. Merge non-device reg definition dependent ltc functions into ltc_gk20a.c/h. Prior to this patch, ltc_common.c was being directly included into the device specific ltc source files as a workaround to allow different devices to share the same code but still include in different hw reg definitions. Given that this approach was not adopted for other systems, this code has been separated out for readability and consistency. Jira NVGPU-74 Change-Id: I4eea301927418532cc150b029535f165928cab89 Signed-off-by: Sunny He <suhe@nvidia.com> Reviewed-on: https://git-master/r/1507502 GVS: Gerrit_Virtual_Submit Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
381 lines
10 KiB
C
381 lines
10 KiB
C
/*
|
|
* GK20A L2
|
|
*
|
|
* Copyright (c) 2011-2017, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify it
|
|
* under the terms and conditions of the GNU General Public License,
|
|
* version 2, as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
|
* more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <trace/events/gk20a.h>
|
|
#include <nvgpu/timers.h>
|
|
#include <nvgpu/log.h>
|
|
#include <nvgpu/bug.h>
|
|
#include <nvgpu/enabled.h>
|
|
#include <nvgpu/dma.h>
|
|
|
|
#include "gk20a.h"
|
|
#include "gr_gk20a.h"
|
|
#include "ltc_gk20a.h"
|
|
|
|
#include <nvgpu/hw/gk20a/hw_ltc_gk20a.h>
|
|
|
|
|
|
/* Non HW reg dependent stuff: */
|
|
|
|
int gk20a_ltc_alloc_phys_cbc(struct gk20a *g, size_t compbit_backing_size)
|
|
{
|
|
struct gr_gk20a *gr = &g->gr;
|
|
|
|
return nvgpu_dma_alloc_flags_sys(g, NVGPU_DMA_FORCE_CONTIGUOUS,
|
|
compbit_backing_size,
|
|
&gr->compbit_store.mem);
|
|
}
|
|
|
|
int gk20a_ltc_alloc_virt_cbc(struct gk20a *g, size_t compbit_backing_size)
|
|
{
|
|
struct gr_gk20a *gr = &g->gr;
|
|
|
|
return nvgpu_dma_alloc_flags_sys(g, NVGPU_DMA_NO_KERNEL_MAPPING,
|
|
compbit_backing_size,
|
|
&gr->compbit_store.mem);
|
|
}
|
|
|
|
/* HW reg dependent stuff: */
|
|
static int gk20a_ltc_init_comptags(struct gk20a *g, struct gr_gk20a *gr)
|
|
{
|
|
/* max memory size (MB) to cover */
|
|
u32 max_size = gr->max_comptag_mem;
|
|
/* one tag line covers 128KB */
|
|
u32 max_comptag_lines = max_size << 3;
|
|
|
|
u32 hw_max_comptag_lines =
|
|
ltc_ltcs_ltss_cbc_ctrl3_clear_upper_bound_init_v();
|
|
|
|
u32 cbc_param =
|
|
gk20a_readl(g, ltc_ltcs_ltss_cbc_param_r());
|
|
u32 comptags_per_cacheline =
|
|
ltc_ltcs_ltss_cbc_param_comptags_per_cache_line_v(cbc_param);
|
|
u32 slices_per_fbp =
|
|
ltc_ltcs_ltss_cbc_param_slices_per_fbp_v(cbc_param);
|
|
u32 cacheline_size =
|
|
512 << ltc_ltcs_ltss_cbc_param_cache_line_size_v(cbc_param);
|
|
|
|
u32 compbit_backing_size;
|
|
|
|
int err;
|
|
|
|
gk20a_dbg_fn("");
|
|
|
|
if (max_comptag_lines == 0)
|
|
return 0;
|
|
|
|
if (max_comptag_lines > hw_max_comptag_lines)
|
|
max_comptag_lines = hw_max_comptag_lines;
|
|
|
|
/* no hybird fb */
|
|
compbit_backing_size =
|
|
DIV_ROUND_UP(max_comptag_lines, comptags_per_cacheline) *
|
|
cacheline_size * slices_per_fbp * gr->num_fbps;
|
|
|
|
/* aligned to 2KB * num_fbps */
|
|
compbit_backing_size +=
|
|
gr->num_fbps << ltc_ltcs_ltss_cbc_base_alignment_shift_v();
|
|
|
|
/* must be a multiple of 64KB */
|
|
compbit_backing_size = roundup(compbit_backing_size, 64*1024);
|
|
|
|
max_comptag_lines =
|
|
(compbit_backing_size * comptags_per_cacheline) /
|
|
cacheline_size * slices_per_fbp * gr->num_fbps;
|
|
|
|
if (max_comptag_lines > hw_max_comptag_lines)
|
|
max_comptag_lines = hw_max_comptag_lines;
|
|
|
|
gk20a_dbg_info("compbit backing store size : %d",
|
|
compbit_backing_size);
|
|
gk20a_dbg_info("max comptag lines : %d",
|
|
max_comptag_lines);
|
|
|
|
if (nvgpu_is_enabled(g, NVGPU_IS_FMODEL))
|
|
err = gk20a_ltc_alloc_phys_cbc(g, compbit_backing_size);
|
|
else
|
|
err = gk20a_ltc_alloc_virt_cbc(g, compbit_backing_size);
|
|
|
|
if (err)
|
|
return err;
|
|
|
|
err = gk20a_comptag_allocator_init(&gr->comp_tags, max_comptag_lines);
|
|
if (err)
|
|
return err;
|
|
|
|
gr->comptags_per_cacheline = comptags_per_cacheline;
|
|
gr->slices_per_ltc = slices_per_fbp / g->ltc_count;
|
|
gr->cacheline_size = cacheline_size;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int gk20a_ltc_cbc_ctrl(struct gk20a *g, enum gk20a_cbc_op op,
|
|
u32 min, u32 max)
|
|
{
|
|
int err = 0;
|
|
struct gr_gk20a *gr = &g->gr;
|
|
u32 fbp, slice, ctrl1, val, hw_op = 0;
|
|
u32 slices_per_fbp =
|
|
ltc_ltcs_ltss_cbc_param_slices_per_fbp_v(
|
|
gk20a_readl(g, ltc_ltcs_ltss_cbc_param_r()));
|
|
u32 ltc_stride = nvgpu_get_litter_value(g, GPU_LIT_LTC_STRIDE);
|
|
u32 lts_stride = nvgpu_get_litter_value(g, GPU_LIT_LTS_STRIDE);
|
|
|
|
gk20a_dbg_fn("");
|
|
|
|
trace_gk20a_ltc_cbc_ctrl_start(g->name, op, min, max);
|
|
|
|
if (gr->compbit_store.mem.size == 0)
|
|
return 0;
|
|
|
|
nvgpu_mutex_acquire(&g->mm.l2_op_lock);
|
|
|
|
if (op == gk20a_cbc_op_clear) {
|
|
gk20a_writel(g, ltc_ltcs_ltss_cbc_ctrl2_r(),
|
|
ltc_ltcs_ltss_cbc_ctrl2_clear_lower_bound_f(min));
|
|
gk20a_writel(g, ltc_ltcs_ltss_cbc_ctrl3_r(),
|
|
ltc_ltcs_ltss_cbc_ctrl3_clear_upper_bound_f(max));
|
|
hw_op = ltc_ltcs_ltss_cbc_ctrl1_clear_active_f();
|
|
} else if (op == gk20a_cbc_op_clean) {
|
|
hw_op = ltc_ltcs_ltss_cbc_ctrl1_clean_active_f();
|
|
} else if (op == gk20a_cbc_op_invalidate) {
|
|
hw_op = ltc_ltcs_ltss_cbc_ctrl1_invalidate_active_f();
|
|
} else {
|
|
BUG_ON(1);
|
|
}
|
|
|
|
gk20a_writel(g, ltc_ltcs_ltss_cbc_ctrl1_r(),
|
|
gk20a_readl(g, ltc_ltcs_ltss_cbc_ctrl1_r()) | hw_op);
|
|
|
|
for (fbp = 0; fbp < gr->num_fbps; fbp++) {
|
|
struct nvgpu_timeout timeout;
|
|
|
|
nvgpu_timeout_init(g, &timeout, 200, NVGPU_TIMER_RETRY_TIMER);
|
|
for (slice = 0; slice < slices_per_fbp; slice++) {
|
|
|
|
|
|
ctrl1 = ltc_ltc0_lts0_cbc_ctrl1_r() +
|
|
fbp * ltc_stride +
|
|
slice * lts_stride;
|
|
|
|
do {
|
|
val = gk20a_readl(g, ctrl1);
|
|
if (!(val & hw_op))
|
|
break;
|
|
nvgpu_udelay(5);
|
|
|
|
} while (!nvgpu_timeout_expired(&timeout));
|
|
|
|
if (nvgpu_timeout_peek_expired(&timeout)) {
|
|
nvgpu_err(g, "comp tag clear timeout");
|
|
err = -EBUSY;
|
|
goto out;
|
|
}
|
|
}
|
|
}
|
|
out:
|
|
trace_gk20a_ltc_cbc_ctrl_done(g->name);
|
|
nvgpu_mutex_release(&g->mm.l2_op_lock);
|
|
return err;
|
|
}
|
|
|
|
|
|
static void gk20a_ltc_init_fs_state(struct gk20a *g)
|
|
{
|
|
gk20a_dbg_info("initialize gk20a L2");
|
|
|
|
g->max_ltc_count = g->ltc_count = 1;
|
|
}
|
|
|
|
static void gk20a_ltc_isr(struct gk20a *g)
|
|
{
|
|
u32 intr;
|
|
|
|
intr = gk20a_readl(g, ltc_ltc0_ltss_intr_r());
|
|
nvgpu_err(g, "ltc: %08x", intr);
|
|
gk20a_writel(g, ltc_ltc0_ltss_intr_r(), intr);
|
|
}
|
|
|
|
static int gk20a_determine_L2_size_bytes(struct gk20a *g)
|
|
{
|
|
u32 lts_per_ltc;
|
|
u32 ways;
|
|
u32 sets;
|
|
u32 bytes_per_line;
|
|
u32 active_ltcs;
|
|
u32 cache_size;
|
|
|
|
u32 tmp;
|
|
u32 active_sets_value;
|
|
|
|
tmp = gk20a_readl(g, ltc_ltc0_lts0_tstg_cfg1_r());
|
|
ways = hweight32(ltc_ltc0_lts0_tstg_cfg1_active_ways_v(tmp));
|
|
|
|
active_sets_value = ltc_ltc0_lts0_tstg_cfg1_active_sets_v(tmp);
|
|
if (active_sets_value == ltc_ltc0_lts0_tstg_cfg1_active_sets_all_v()) {
|
|
sets = 64;
|
|
} else if (active_sets_value ==
|
|
ltc_ltc0_lts0_tstg_cfg1_active_sets_half_v()) {
|
|
sets = 32;
|
|
} else if (active_sets_value ==
|
|
ltc_ltc0_lts0_tstg_cfg1_active_sets_quarter_v()) {
|
|
sets = 16;
|
|
} else {
|
|
nvgpu_err(g,
|
|
"Unknown constant %u for active sets",
|
|
(unsigned)active_sets_value);
|
|
sets = 0;
|
|
}
|
|
|
|
active_ltcs = g->gr.num_fbps;
|
|
|
|
/* chip-specific values */
|
|
lts_per_ltc = 1;
|
|
bytes_per_line = 128;
|
|
cache_size = active_ltcs * lts_per_ltc * ways * sets * bytes_per_line;
|
|
|
|
return cache_size;
|
|
}
|
|
|
|
/*
|
|
* Sets the ZBC color for the passed index.
|
|
*/
|
|
static void gk20a_ltc_set_zbc_color_entry(struct gk20a *g,
|
|
struct zbc_entry *color_val,
|
|
u32 index)
|
|
{
|
|
u32 i;
|
|
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));
|
|
|
|
for (i = 0;
|
|
i < ltc_ltcs_ltss_dstg_zbc_color_clear_value__size_1_v(); i++) {
|
|
gk20a_writel(g, ltc_ltcs_ltss_dstg_zbc_color_clear_value_r(i),
|
|
color_val->color_l2[i]);
|
|
}
|
|
gk20a_readl(g, ltc_ltcs_ltss_dstg_zbc_index_r());
|
|
}
|
|
|
|
/*
|
|
* Sets the ZBC depth for the passed index.
|
|
*/
|
|
static void gk20a_ltc_set_zbc_depth_entry(struct gk20a *g,
|
|
struct zbc_entry *depth_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_depth_clear_value_r(),
|
|
depth_val->depth);
|
|
|
|
gk20a_readl(g, ltc_ltcs_ltss_dstg_zbc_index_r());
|
|
}
|
|
|
|
static void gk20a_ltc_init_cbc(struct gk20a *g, struct gr_gk20a *gr)
|
|
{
|
|
u32 max_size = gr->max_comptag_mem;
|
|
u32 max_comptag_lines = max_size << 3;
|
|
|
|
u32 compbit_base_post_divide;
|
|
u64 compbit_base_post_multiply64;
|
|
u64 compbit_store_iova;
|
|
u64 compbit_base_post_divide64;
|
|
|
|
if (nvgpu_is_enabled(g, NVGPU_IS_FMODEL))
|
|
compbit_store_iova = gk20a_mem_phys(&gr->compbit_store.mem);
|
|
else
|
|
compbit_store_iova = g->ops.mm.get_iova_addr(g,
|
|
gr->compbit_store.mem.priv.sgt->sgl, 0);
|
|
|
|
compbit_base_post_divide64 = compbit_store_iova >>
|
|
ltc_ltcs_ltss_cbc_base_alignment_shift_v();
|
|
|
|
do_div(compbit_base_post_divide64, g->ltc_count);
|
|
compbit_base_post_divide = u64_lo32(compbit_base_post_divide64);
|
|
|
|
compbit_base_post_multiply64 = ((u64)compbit_base_post_divide *
|
|
g->ltc_count) << ltc_ltcs_ltss_cbc_base_alignment_shift_v();
|
|
|
|
if (compbit_base_post_multiply64 < compbit_store_iova)
|
|
compbit_base_post_divide++;
|
|
|
|
/* Bug 1477079 indicates sw adjustment on the posted divided base. */
|
|
if (g->ops.ltc.cbc_fix_config)
|
|
compbit_base_post_divide =
|
|
g->ops.ltc.cbc_fix_config(g, compbit_base_post_divide);
|
|
|
|
gk20a_writel(g, ltc_ltcs_ltss_cbc_base_r(),
|
|
compbit_base_post_divide);
|
|
|
|
gk20a_dbg(gpu_dbg_info | gpu_dbg_map_v | gpu_dbg_pte,
|
|
"compbit base.pa: 0x%x,%08x cbc_base:0x%08x\n",
|
|
(u32)(compbit_store_iova >> 32),
|
|
(u32)(compbit_store_iova & 0xffffffff),
|
|
compbit_base_post_divide);
|
|
|
|
gr->compbit_store.base_hw = compbit_base_post_divide;
|
|
|
|
g->ops.ltc.cbc_ctrl(g, gk20a_cbc_op_invalidate,
|
|
0, max_comptag_lines - 1);
|
|
|
|
}
|
|
|
|
#ifdef CONFIG_DEBUG_FS
|
|
static void gk20a_ltc_sync_debugfs(struct gk20a *g)
|
|
{
|
|
u32 reg_f = ltc_ltcs_ltss_tstg_set_mgmt_2_l2_bypass_mode_enabled_f();
|
|
|
|
nvgpu_spinlock_acquire(&g->debugfs_lock);
|
|
if (g->mm.ltc_enabled != g->mm.ltc_enabled_debug) {
|
|
u32 reg = gk20a_readl(g, ltc_ltcs_ltss_tstg_set_mgmt_2_r());
|
|
|
|
if (g->mm.ltc_enabled_debug)
|
|
/* bypass disabled (normal caching ops)*/
|
|
reg &= ~reg_f;
|
|
else
|
|
/* bypass enabled (no caching) */
|
|
reg |= reg_f;
|
|
|
|
gk20a_writel(g, ltc_ltcs_ltss_tstg_set_mgmt_2_r(), reg);
|
|
g->mm.ltc_enabled = g->mm.ltc_enabled_debug;
|
|
}
|
|
nvgpu_spinlock_release(&g->debugfs_lock);
|
|
}
|
|
#endif
|
|
|
|
void gk20a_init_ltc(struct gpu_ops *gops)
|
|
{
|
|
gops->ltc.determine_L2_size_bytes = gk20a_determine_L2_size_bytes;
|
|
gops->ltc.init_comptags = gk20a_ltc_init_comptags;
|
|
gops->ltc.cbc_ctrl = gk20a_ltc_cbc_ctrl;
|
|
gops->ltc.set_zbc_color_entry = gk20a_ltc_set_zbc_color_entry;
|
|
gops->ltc.set_zbc_depth_entry = gk20a_ltc_set_zbc_depth_entry;
|
|
gops->ltc.init_cbc = gk20a_ltc_init_cbc;
|
|
#ifdef CONFIG_DEBUG_FS
|
|
gops->ltc.sync_debugfs = gk20a_ltc_sync_debugfs;
|
|
#endif
|
|
gops->ltc.init_fs_state = gk20a_ltc_init_fs_state;
|
|
gops->ltc.isr = gk20a_ltc_isr;
|
|
}
|