gpu: nvgpu: Fix CWD floorsweep programming

Program CWD TPC and SM registers correctly. The old code did not work
when there are more than 4 TPCs.

Refactor init_fs_mask to reduce code duplication.

Change-Id: Id93c1f8df24f1b7ee60314c3204e288b91951a88
Signed-off-by: Terje Bergstrom <tbergstrom@nvidia.com>
Reviewed-on: http://git-master/r/1143697
GVS: Gerrit_Virtual_Submit
Reviewed-by: Konsta Holtta <kholtta@nvidia.com>
This commit is contained in:
Terje Bergstrom
2016-05-06 15:13:54 -07:00
parent 3a1321ddcd
commit 211edaefb7
6 changed files with 164 additions and 121 deletions

View File

@@ -260,6 +260,10 @@ struct gpu_ops {
int (*get_preemption_mode_flags)(struct gk20a *g,
struct nvgpu_preemption_modes_rec *preemption_modes_rec);
int (*fuse_override)(struct gk20a *g);
int (*load_smid_config)(struct gk20a *g);
void (*program_sm_id_numbering)(struct gk20a *g,
u32 gpc, u32 tpc, u32 smid);
void (*program_active_tpc_counts)(struct gk20a *g, u32 gpc);
} gr;
const char *name;
struct {

View File

@@ -1286,54 +1286,82 @@ static u32 gr_gk20a_get_gpc_tpc_mask(struct gk20a *g, u32 gpc_index)
return 0x1;
}
static int gr_gk20a_ctx_state_floorsweep(struct gk20a *g)
static void gr_gk20a_program_active_tpc_counts(struct gk20a *g, u32 gpc_index)
{
u32 gpc_stride = nvgpu_get_litter_value(g, GPU_LIT_GPC_STRIDE);
u32 gpc_offset = gpc_stride * gpc_index;
struct gr_gk20a *gr = &g->gr;
gk20a_writel(g, gr_gpc0_gpm_pd_active_tpcs_r() + gpc_offset,
gr_gpc0_gpm_pd_active_tpcs_num_f(gr->gpc_tpc_count[gpc_index]));
gk20a_writel(g, gr_gpc0_gpm_sd_active_tpcs_r() + gpc_offset,
gr_gpc0_gpm_sd_active_tpcs_num_f(gr->gpc_tpc_count[gpc_index]));
}
static void gr_gk20a_init_sm_id_table(struct gk20a *g)
{
u32 gpc, tpc;
u32 sm_id = 0;
for (tpc = 0; tpc < g->gr.max_tpc_per_gpc_count; tpc++) {
for (gpc = 0; gpc < g->gr.gpc_count; gpc++) {
if (tpc < g->gr.gpc_tpc_count[gpc]) {
g->gr.sm_to_cluster[sm_id].tpc_index = tpc;
g->gr.sm_to_cluster[sm_id].gpc_index = gpc;
sm_id++;
}
}
}
g->gr.no_of_sm = sm_id;
}
static void gr_gk20a_program_sm_id_numbering(struct gk20a *g,
u32 gpc, u32 tpc, u32 sm_id)
{
u32 gpc_stride = nvgpu_get_litter_value(g, GPU_LIT_GPC_STRIDE);
u32 tpc_in_gpc_stride = nvgpu_get_litter_value(g, GPU_LIT_TPC_IN_GPC_STRIDE);
u32 gpc_offset = gpc_stride * gpc;
u32 tpc_offset = tpc_in_gpc_stride * tpc;
gk20a_writel(g, gr_gpc0_tpc0_sm_cfg_r() + gpc_offset + tpc_offset,
gr_gpc0_tpc0_sm_cfg_sm_id_f(sm_id));
gk20a_writel(g, gr_gpc0_tpc0_l1c_cfg_smid_r() + gpc_offset + tpc_offset,
gr_gpc0_tpc0_l1c_cfg_smid_value_f(sm_id));
gk20a_writel(g, gr_gpc0_gpm_pd_sm_id_r(tpc) + gpc_offset,
gr_gpc0_gpm_pd_sm_id_id_f(sm_id));
gk20a_writel(g, gr_gpc0_tpc0_pe_cfg_smid_r() + gpc_offset + tpc_offset,
gr_gpc0_tpc0_pe_cfg_smid_value_f(sm_id));
}
int gr_gk20a_init_fs_state(struct gk20a *g)
{
struct gr_gk20a *gr = &g->gr;
u32 tpc_index, gpc_index;
u32 tpc_offset, gpc_offset;
u32 sm_id = 0, gpc_id = 0;
u32 tpc_per_gpc;
u32 gpc_stride = nvgpu_get_litter_value(g, GPU_LIT_GPC_STRIDE);
u32 tpc_in_gpc_stride = nvgpu_get_litter_value(g, GPU_LIT_TPC_IN_GPC_STRIDE);
u32 fuse_tpc_mask;
gk20a_dbg_fn("");
for (tpc_index = 0; tpc_index < gr->max_tpc_per_gpc_count; tpc_index++) {
for (gpc_index = 0; gpc_index < gr->gpc_count; gpc_index++) {
gpc_offset = gpc_stride * gpc_index;
if (tpc_index < gr->gpc_tpc_count[gpc_index]) {
tpc_offset = tpc_in_gpc_stride * tpc_index;
gr_gk20a_init_sm_id_table(g);
gk20a_writel(g, gr_gpc0_tpc0_sm_cfg_r() + gpc_offset + tpc_offset,
gr_gpc0_tpc0_sm_cfg_sm_id_f(sm_id));
gk20a_writel(g, gr_gpc0_tpc0_l1c_cfg_smid_r() + gpc_offset + tpc_offset,
gr_gpc0_tpc0_l1c_cfg_smid_value_f(sm_id));
gk20a_writel(g, gr_gpc0_gpm_pd_sm_id_r(tpc_index) + gpc_offset,
gr_gpc0_gpm_pd_sm_id_id_f(sm_id));
gk20a_writel(g, gr_gpc0_tpc0_pe_cfg_smid_r() + gpc_offset + tpc_offset,
gr_gpc0_tpc0_pe_cfg_smid_value_f(sm_id));
for (sm_id = 0; sm_id < gr->tpc_count; sm_id++) {
tpc_index = g->gr.sm_to_cluster[sm_id].tpc_index;
gpc_index = g->gr.sm_to_cluster[sm_id].gpc_index;
g->gr.sm_to_cluster[sm_id].tpc_index = tpc_index;
g->gr.sm_to_cluster[sm_id].gpc_index = gpc_index;
g->ops.gr.program_sm_id_numbering(g, gpc_index, tpc_index, sm_id);
sm_id++;
}
gk20a_writel(g, gr_gpc0_gpm_pd_active_tpcs_r() + gpc_offset,
gr_gpc0_gpm_pd_active_tpcs_num_f(gr->gpc_tpc_count[gpc_index]));
gk20a_writel(g, gr_gpc0_gpm_sd_active_tpcs_r() + gpc_offset,
gr_gpc0_gpm_sd_active_tpcs_num_f(gr->gpc_tpc_count[gpc_index]));
}
if (g->ops.gr.program_active_tpc_counts)
g->ops.gr.program_active_tpc_counts(g, gpc_index);
}
gr->no_of_sm = sm_id;
for (tpc_index = 0, gpc_id = 0;
tpc_index < gr_pd_num_tpc_per_gpc__size_1_v();
tpc_index++, gpc_id += 8) {
if (gpc_id >= gr->gpc_count)
gpc_id = 0;
continue;
tpc_per_gpc =
gr_pd_num_tpc_per_gpc_count0_f(gr->gpc_tpc_count[gpc_id + 0]) |
@@ -1365,9 +1393,19 @@ static int gr_gk20a_ctx_state_floorsweep(struct gk20a *g)
gr_pd_dist_skip_table_gpc_4n3_mask_f(gr->gpc_skip_mask[gpc_index + 3]));
}
gk20a_writel(g, gr_cwd_fs_r(),
gr_cwd_fs_num_gpcs_f(gr->gpc_count) |
gr_cwd_fs_num_tpcs_f(gr->tpc_count));
fuse_tpc_mask = g->ops.gr.get_gpc_tpc_mask(g, 0);
if (g->tpc_fs_mask_user &&
fuse_tpc_mask == (0x1 << gr->max_tpc_count) - 1) {
u32 val = g->tpc_fs_mask_user;
val &= (0x1 << gr->max_tpc_count) - 1;
gk20a_writel(g, gr_cwd_fs_r(),
gr_cwd_fs_num_gpcs_f(gr->gpc_count) |
gr_cwd_fs_num_tpcs_f(hweight32(val)));
} else {
gk20a_writel(g, gr_cwd_fs_r(),
gr_cwd_fs_num_gpcs_f(gr->gpc_count) |
gr_cwd_fs_num_tpcs_f(gr->tpc_count));
}
gk20a_writel(g, gr_bes_zrop_settings_r(),
gr_bes_zrop_settings_num_active_fbps_f(gr->num_fbps));
@@ -4413,7 +4451,9 @@ static int gk20a_init_gr_setup_hw(struct gk20a *g)
gr_gk20a_commit_global_timeslice(g, NULL, false);
/* floorsweep anything left */
g->ops.gr.init_fs_state(g);
err = g->ops.gr.init_fs_state(g);
if (err)
goto out;
err = gr_gk20a_wait_idle(g, end_jiffies, GR_IDLE_CHECK_DEFAULT);
if (err)
@@ -4466,7 +4506,7 @@ restore_fe_go_idle:
out:
gk20a_dbg_fn("done");
return 0;
return err;
}
static void gr_gk20a_load_gating_prod(struct gk20a *g)
@@ -8633,7 +8673,7 @@ void gk20a_init_gr_ops(struct gpu_ops *gops)
gops->gr.is_valid_class = gr_gk20a_is_valid_class;
gops->gr.get_sm_dsm_perf_regs = gr_gk20a_get_sm_dsm_perf_regs;
gops->gr.get_sm_dsm_perf_ctrl_regs = gr_gk20a_get_sm_dsm_perf_ctrl_regs;
gops->gr.init_fs_state = gr_gk20a_ctx_state_floorsweep;
gops->gr.init_fs_state = gr_gk20a_init_fs_state;
gops->gr.set_hww_esr_report_mask = gr_gk20a_set_hww_esr_report_mask;
gops->gr.setup_alpha_beta_tables = gr_gk20a_setup_alpha_beta_tables;
gops->gr.falcon_load_ucode = gr_gk20a_load_ctxsw_ucode_segments;
@@ -8681,4 +8721,6 @@ void gk20a_init_gr_ops(struct gpu_ops *gops)
gops->gr.clear_sm_error_state = gk20a_gr_clear_sm_error_state;
gops->gr.suspend_contexts = gr_gk20a_suspend_contexts;
gops->gr.get_preemption_mode_flags = gr_gk20a_get_preemption_mode_flags;
gops->gr.program_active_tpc_counts = gr_gk20a_program_active_tpc_counts;
gops->gr.program_sm_id_numbering = gr_gk20a_program_sm_id_numbering;
}

View File

@@ -533,6 +533,7 @@ void gr_gk20a_commit_global_pagepool(struct gk20a *g,
u64 addr, u32 size, bool patch);
void gk20a_gr_set_shader_exceptions(struct gk20a *g, u32 data);
void gr_gk20a_enable_hww_exceptions(struct gk20a *g);
int gr_gk20a_init_fs_state(struct gk20a *g);
int gr_gk20a_setup_rop_mapping(struct gk20a *g, struct gr_gk20a *gr);
int gr_gk20a_init_ctxsw_ucode(struct gk20a *g);
int gr_gk20a_load_ctxsw_ucode(struct gk20a *g);

View File

@@ -552,78 +552,70 @@ static void gr_gm20b_load_tpc_mask(struct gk20a *g)
}
}
int gr_gm20b_ctx_state_floorsweep(struct gk20a *g)
static void gr_gm20b_program_sm_id_numbering(struct gk20a *g,
u32 gpc, u32 tpc, u32 smid)
{
struct gr_gk20a *gr = &g->gr;
u32 tpc_index, gpc_index;
u32 tpc_offset, gpc_offset;
u32 sm_id = 0;
u32 tpc_per_gpc = 0;
u32 tpc_sm_id = 0, gpc_tpc_id = 0;
u32 gpc_stride = nvgpu_get_litter_value(g, GPU_LIT_GPC_STRIDE);
u32 tpc_in_gpc_stride = nvgpu_get_litter_value(g, GPU_LIT_TPC_IN_GPC_STRIDE);
u32 fuse_tpc_mask;
u32 gpc_offset = gpc_stride * gpc;
u32 tpc_offset = tpc_in_gpc_stride * tpc;
gk20a_writel(g, gr_gpc0_tpc0_sm_cfg_r() + gpc_offset + tpc_offset,
gr_gpc0_tpc0_sm_cfg_sm_id_f(smid));
gk20a_writel(g, gr_gpc0_gpm_pd_sm_id_r(tpc) + gpc_offset,
gr_gpc0_gpm_pd_sm_id_id_f(smid));
gk20a_writel(g, gr_gpc0_tpc0_pe_cfg_smid_r() + gpc_offset + tpc_offset,
gr_gpc0_tpc0_pe_cfg_smid_value_f(smid));
}
static int gr_gm20b_load_smid_config(struct gk20a *g)
{
u32 *tpc_sm_id;
u32 i, j;
u32 tpc_index, gpc_index;
tpc_sm_id = kcalloc(gr_cwd_sm_id__size_1_v(), sizeof(u32), GFP_KERNEL);
if (!tpc_sm_id)
return -ENOMEM;
/* Each NV_PGRAPH_PRI_CWD_GPC_TPC_ID can store 4 TPCs.*/
for (i = 0; i <= ((g->gr.tpc_count-1) / 4); i++) {
u32 reg = 0;
u32 bit_stride = gr_cwd_gpc_tpc_id_gpc0_s() +
gr_cwd_gpc_tpc_id_tpc0_s();
for (j = 0; j < 4; j++) {
u32 sm_id = (i / 4) + j;
u32 bits;
if (sm_id >= g->gr.tpc_count)
break;
gpc_index = g->gr.sm_to_cluster[sm_id].gpc_index;
tpc_index = g->gr.sm_to_cluster[sm_id].tpc_index;
bits = gr_cwd_gpc_tpc_id_gpc0_f(gpc_index) |
gr_cwd_gpc_tpc_id_tpc0_f(tpc_index);
reg |= bits << (j * bit_stride);
tpc_sm_id[gpc_index] |= sm_id << tpc_index * bit_stride;
}
gk20a_writel(g, gr_cwd_gpc_tpc_id_r(i), reg);
}
for (i = 0; i < gr_cwd_sm_id__size_1_v(); i++)
gk20a_writel(g, gr_cwd_sm_id_r(i), tpc_sm_id[i]);
kfree(tpc_sm_id);
return 0;
}
int gr_gm20b_init_fs_state(struct gk20a *g)
{
gk20a_dbg_fn("");
for (gpc_index = 0; gpc_index < gr->gpc_count; gpc_index++) {
gpc_offset = gpc_stride * gpc_index;
for (tpc_index = 0; tpc_index < gr->gpc_tpc_count[gpc_index];
tpc_index++) {
tpc_offset = tpc_in_gpc_stride * tpc_index;
gk20a_writel(g, gr_gpc0_tpc0_sm_cfg_r()
+ gpc_offset + tpc_offset,
gr_gpc0_tpc0_sm_cfg_sm_id_f(sm_id));
gk20a_writel(g, gr_gpc0_gpm_pd_sm_id_r(tpc_index)
+ gpc_offset,
gr_gpc0_gpm_pd_sm_id_id_f(sm_id));
gk20a_writel(g, gr_gpc0_tpc0_pe_cfg_smid_r()
+ gpc_offset + tpc_offset,
gr_gpc0_tpc0_pe_cfg_smid_value_f(sm_id));
g->gr.sm_to_cluster[sm_id].tpc_index = tpc_index;
g->gr.sm_to_cluster[sm_id].gpc_index = gpc_index;
sm_id++;
}
}
gr->no_of_sm = sm_id;
for (gpc_index = 0; gpc_index < gr->gpc_count; gpc_index++)
tpc_per_gpc |= gr->gpc_tpc_count[gpc_index]
<< (gr_pd_num_tpc_per_gpc__size_1_v() * gpc_index);
gk20a_writel(g, gr_pd_num_tpc_per_gpc_r(0), tpc_per_gpc);
gk20a_writel(g, gr_ds_num_tpc_per_gpc_r(0), tpc_per_gpc);
/* gr__setup_pd_mapping stubbed for gk20a */
gr_gk20a_setup_rop_mapping(g, gr);
for (gpc_index = 0;
gpc_index < gr_pd_dist_skip_table__size_1_v() * 4;
gpc_index += 4) {
gk20a_writel(g, gr_pd_dist_skip_table_r(gpc_index/4),
gr_pd_dist_skip_table_gpc_4n0_mask_f(gr->gpc_skip_mask[gpc_index]) |
gr_pd_dist_skip_table_gpc_4n1_mask_f(gr->gpc_skip_mask[gpc_index + 1]) |
gr_pd_dist_skip_table_gpc_4n2_mask_f(gr->gpc_skip_mask[gpc_index + 2]) |
gr_pd_dist_skip_table_gpc_4n3_mask_f(gr->gpc_skip_mask[gpc_index + 3]));
}
fuse_tpc_mask = g->ops.gr.get_gpc_tpc_mask(g, 0);
if (g->tpc_fs_mask_user &&
fuse_tpc_mask == (0x1 << gr->max_tpc_count) - 1) {
u32 val = g->tpc_fs_mask_user;
val &= (0x1 << gr->max_tpc_count) - 1;
gk20a_writel(g, gr_cwd_fs_r(),
gr_cwd_fs_num_gpcs_f(gr->gpc_count) |
gr_cwd_fs_num_tpcs_f(hweight32(val)));
} else {
gk20a_writel(g, gr_cwd_fs_r(),
gr_cwd_fs_num_gpcs_f(gr->gpc_count) |
gr_cwd_fs_num_tpcs_f(gr->tpc_count));
}
gr_gk20a_init_fs_state(g);
gr_gm20b_load_tpc_mask(g);
@@ -636,22 +628,7 @@ int gr_gm20b_ctx_state_floorsweep(struct gk20a *g)
gk20a_readl(g, gr_be0_crop_debug3_r()) |
gr_bes_crop_debug3_comp_vdc_4to2_disable_m());
for (tpc_index = 0; tpc_index < gr->tpc_count; tpc_index++) {
if (tpc_index == 0) {
gpc_tpc_id |= gr_cwd_gpc_tpc_id_tpc0_f(tpc_index);
tpc_sm_id |= gr_cwd_sm_id_tpc0_f(tpc_index);
} else if (tpc_index == 1) {
gpc_tpc_id |= gr_cwd_gpc_tpc_id_tpc1_f(tpc_index);
tpc_sm_id |= gr_cwd_sm_id_tpc1_f(tpc_index);
}
}
/* Each NV_PGRAPH_PRI_CWD_GPC_TPC_ID can store 4 TPCs.
* Since we know TPC number is less than 5. We select
* index 0 directly. */
gk20a_writel(g, gr_cwd_gpc_tpc_id_r(0), gpc_tpc_id);
gk20a_writel(g, gr_cwd_sm_id_r(0), tpc_sm_id);
g->ops.gr.load_smid_config(g);
return 0;
}
@@ -1443,7 +1420,7 @@ void gm20b_init_gr(struct gpu_ops *gops)
gops->gr.is_valid_class = gr_gm20b_is_valid_class;
gops->gr.get_sm_dsm_perf_regs = gr_gm20b_get_sm_dsm_perf_regs;
gops->gr.get_sm_dsm_perf_ctrl_regs = gr_gm20b_get_sm_dsm_perf_ctrl_regs;
gops->gr.init_fs_state = gr_gm20b_ctx_state_floorsweep;
gops->gr.init_fs_state = gr_gm20b_init_fs_state;
gops->gr.set_hww_esr_report_mask = gr_gm20b_set_hww_esr_report_mask;
gops->gr.falcon_load_ucode = gr_gm20b_load_ctxsw_ucode_segments;
if (gops->privsecurity)
@@ -1499,4 +1476,6 @@ void gm20b_init_gr(struct gpu_ops *gops)
gops->gr.suspend_contexts = gr_gk20a_suspend_contexts;
gops->gr.get_preemption_mode_flags = gr_gm20b_get_preemption_mode_flags;
gops->gr.fuse_override = gm20b_gr_fuse_override;
gops->gr.load_smid_config = gr_gm20b_load_smid_config;
gops->gr.program_sm_id_numbering = gr_gm20b_program_sm_id_numbering;
}

View File

@@ -1,7 +1,7 @@
/*
* GM20B GPC MMU
*
* Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
* Copyright (c) 2014-2016, 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,
@@ -46,5 +46,6 @@ void gm20b_init_gr(struct gpu_ops *gops);
void gr_gm20b_commit_global_attrib_cb(struct gk20a *g,
struct channel_ctx_gk20a *ch_ctx,
u64 addr, bool patch);
int gr_gm20b_ctx_state_floorsweep(struct gk20a *g);
int gr_gm20b_init_fs_state(struct gk20a *g);
#endif

View File

@@ -1962,10 +1962,22 @@ static inline u32 gr_cwd_gpc_tpc_id_r(u32 i)
{
return 0x00405b60 + i*4;
}
static inline u32 gr_cwd_gpc_tpc_id_tpc0_s(void)
{
return 4;
}
static inline u32 gr_cwd_gpc_tpc_id_tpc0_f(u32 v)
{
return (v & 0xf) << 0;
}
static inline u32 gr_cwd_gpc_tpc_id_gpc0_s(void)
{
return 4;
}
static inline u32 gr_cwd_gpc_tpc_id_gpc0_f(u32 v)
{
return (v & 0xf) << 4;
}
static inline u32 gr_cwd_gpc_tpc_id_tpc1_f(u32 v)
{
return (v & 0xf) << 8;
@@ -1974,6 +1986,10 @@ static inline u32 gr_cwd_sm_id_r(u32 i)
{
return 0x00405ba0 + i*4;
}
static inline u32 gr_cwd_sm_id__size_1_v(void)
{
return 0x00000006;
}
static inline u32 gr_cwd_sm_id_tpc0_f(u32 v)
{
return (v & 0xff) << 0;