From f8f6b298848ed05ad83ce107ff8a4fff0b37dd2d Mon Sep 17 00:00:00 2001 From: Deepak Nibade Date: Wed, 1 Oct 2014 21:23:49 +0530 Subject: gpu: nvgpu: support config of TPC FUSE dynamically Follow steps below to config active TPC number: echo 1 > /sys/devices/platform/host1x/gpu.0/force_idle echo 0x1/0x2/0x3 > /sys/devices/platform/host1x/gpu.0/tpc_fs_mask echo 0 > /sys/devices/platform/host1x/gpu.0/force_idle where, 0x1 : disable TPC1 0x2 : disable TPC0 0x3 : both TPCs active Also, add API set_gpc_tpc_mask to update the TPCs and call this API after update to sysfs "tpc_fs_mask" Once fuses are updated for new TPC settings, we need to reconfigure GR and golden_image. Hence disable gr->sw_ready and golden_image_initialized flags. Also, initialize gr->tpc_count = 0 each time in gr_gk20a_init_gr_config(), otherwise it goes on adding tpc count Bug 1513685 Change-Id: Ib50bafef08664262f8426ac0d6cbad74b32c5909 Signed-off-by: Kevin Huang Signed-off-by: Deepak Nibade Reviewed-on: http://git-master/r/552606 Reviewed-by: Sachin Nikam --- drivers/gpu/nvgpu/gk20a/gk20a.h | 1 + drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c | 18 +++++++++++++++++- drivers/gpu/nvgpu/gk20a/gr_gk20a.c | 1 + drivers/gpu/nvgpu/gm20b/gr_gm20b.c | 23 +++++++++++++++++++++++ drivers/gpu/nvgpu/gm20b/gr_gm20b.h | 11 +++++++++++ 5 files changed, 53 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 3f070a58..49038a0f 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h @@ -125,6 +125,7 @@ struct gpu_ops { u32 reg_offset); int (*load_ctxsw_ucode)(struct gk20a *g); u32 (*get_gpc_tpc_mask)(struct gk20a *g, u32 gpc_index); + void (*set_gpc_tpc_mask)(struct gk20a *g, u32 gpc_index); void (*free_channel_ctx)(struct channel_gk20a *c); int (*alloc_obj_ctx)(struct channel_gk20a *c, struct nvgpu_alloc_obj_ctx_args *args); diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c index 1f32ac6d..42720307 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a_sysfs.c @@ -607,9 +607,18 @@ static ssize_t tpc_fs_mask_store(struct device *device, if (kstrtoul(buf, 10, &val) < 0) return -EINVAL; - if (val) + if (val && val != g->gr.gpc_tpc_mask[0] && g->ops.gr.set_gpc_tpc_mask) { g->gr.gpc_tpc_mask[0] = val; + g->ops.gr.set_gpc_tpc_mask(g, 0); + + kfree(g->gr.ctx_vars.local_golden_image); + g->gr.ctx_vars.local_golden_image = NULL; + g->gr.ctx_vars.golden_image_initialized = false; + g->gr.ctx_vars.golden_image_size = 0; + g->gr.sw_ready = false; + } + return count; } @@ -621,6 +630,11 @@ static ssize_t tpc_fs_mask_read(struct device *device, struct gr_gk20a *gr = &g->gr; u32 gpc_index; u32 tpc_fs_mask = 0; + int err = 0; + + err = gk20a_busy(g->dev); + if (err) + return err; for (gpc_index = 0; gpc_index < gr->gpc_count; gpc_index++) { if (g->ops.gr.get_gpc_tpc_mask) @@ -629,6 +643,8 @@ static ssize_t tpc_fs_mask_read(struct device *device, (gr->max_tpc_per_gpc_count * gpc_index); } + gk20a_idle(g->dev); + return sprintf(buf, "0x%x\n", tpc_fs_mask); } diff --git a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c index da257cd4..3cf5845c 100644 --- a/drivers/gpu/nvgpu/gk20a/gr_gk20a.c +++ b/drivers/gpu/nvgpu/gk20a/gr_gk20a.c @@ -3084,6 +3084,7 @@ static int gr_gk20a_init_gr_config(struct gk20a *g, struct gr_gk20a *gr) goto clean_up; gr->ppc_count = 0; + gr->tpc_count = 0; for (gpc_index = 0; gpc_index < gr->gpc_count; gpc_index++) { tmp = gk20a_readl(g, gr_gpc0_fs_gpc_r()); diff --git a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c index 8f056181..a6b54ea5 100644 --- a/drivers/gpu/nvgpu/gm20b/gr_gm20b.c +++ b/drivers/gpu/nvgpu/gm20b/gr_gm20b.c @@ -15,6 +15,8 @@ #include #include /* for mdelay */ +#include +#include #include "gk20a/gk20a.h" #include "gk20a/gr_gk20a.h" @@ -492,6 +494,26 @@ static u32 gr_gm20b_get_gpc_tpc_mask(struct gk20a *g, u32 gpc_index) return (~val) & ((0x1 << gr->max_tpc_per_gpc_count) - 1); } +static void gr_gm20b_set_gpc_tpc_mask(struct gk20a *g, u32 gpc_index) +{ + tegra_clk_writel(CLK_RST_CONTROLLER_MISC_CLK_ENB_0_ALL_VISIBLE, + CLK_RST_CONTROLLER_MISC_CLK_ENB_0); + + tegra_fuse_writel(0x1, FUSE_FUSEBYPASS_0); + tegra_fuse_writel(0x0, FUSE_WRITE_ACCESS_SW_0); + + if (g->gr.gpc_tpc_mask[gpc_index] == 0x1) { + tegra_fuse_writel(0x0, FUSE_OPT_GPU_TPC0_DISABLE_0); + tegra_fuse_writel(0x1, FUSE_OPT_GPU_TPC1_DISABLE_0); + } else if (g->gr.gpc_tpc_mask[gpc_index] == 0x2) { + tegra_fuse_writel(0x1, FUSE_OPT_GPU_TPC0_DISABLE_0); + tegra_fuse_writel(0x0, FUSE_OPT_GPU_TPC1_DISABLE_0); + } else { + tegra_fuse_writel(0x0, FUSE_OPT_GPU_TPC0_DISABLE_0); + tegra_fuse_writel(0x0, FUSE_OPT_GPU_TPC1_DISABLE_0); + } +} + static int gr_gm20b_ctx_state_floorsweep(struct gk20a *g) { struct gr_gk20a *gr = &g->gr; @@ -785,6 +807,7 @@ void gm20b_init_gr(struct gpu_ops *gops) gops->gr.load_ctxsw_ucode = gr_gm20b_load_ctxsw_ucode; else gops->gr.load_ctxsw_ucode = gr_gk20a_load_ctxsw_ucode; + gops->gr.set_gpc_tpc_mask = gr_gm20b_set_gpc_tpc_mask; gops->gr.get_gpc_tpc_mask = gr_gm20b_get_gpc_tpc_mask; gops->gr.free_channel_ctx = gk20a_free_channel_ctx; gops->gr.alloc_obj_ctx = gk20a_alloc_obj_ctx; diff --git a/drivers/gpu/nvgpu/gm20b/gr_gm20b.h b/drivers/gpu/nvgpu/gm20b/gr_gm20b.h index 470e5bae..fd109eec 100644 --- a/drivers/gpu/nvgpu/gm20b/gr_gm20b.h +++ b/drivers/gpu/nvgpu/gm20b/gr_gm20b.h @@ -25,6 +25,17 @@ enum { MAXWELL_CHANNEL_GPFIFO_A= 0xB06F, }; +#define tegra_clk_writel(value, offset) \ + writel(value, IO_ADDRESS(0x60006000 + offset)) + +#define CLK_RST_CONTROLLER_MISC_CLK_ENB_0 0x48 +#define CLK_RST_CONTROLLER_MISC_CLK_ENB_0_ALL_VISIBLE BIT(28) + +#define FUSE_FUSEBYPASS_0 0x24 +#define FUSE_WRITE_ACCESS_SW_0 0x30 +#define FUSE_OPT_GPU_TPC0_DISABLE_0 0x30C +#define FUSE_OPT_GPU_TPC1_DISABLE_0 0x33C + #define NVB197_SET_ALPHA_CIRCULAR_BUFFER_SIZE 0x02dc #define NVB197_SET_CIRCULAR_BUFFER_SIZE 0x1280 #define NVB197_SET_SHADER_EXCEPTIONS 0x1528 -- cgit v1.2.2