diff --git a/arch/nvgpu-hal-new.yaml b/arch/nvgpu-hal-new.yaml index 1bd84d950..f9d23aa02 100644 --- a/arch/nvgpu-hal-new.yaml +++ b/arch/nvgpu-hal-new.yaml @@ -776,3 +776,9 @@ xve: sources: [ include/nvgpu/xve.h, hal/xve/xve_gp106.c, hal/xve/xve_gp106.h ] + +tpc: + safe: no + owner: Divya S + sources: [ hal/tpc/tpc_gv11b.c, + hal/tpc/tpc_gv11b.h ] diff --git a/drivers/gpu/nvgpu/Makefile b/drivers/gpu/nvgpu/Makefile index d05488983..e21653359 100644 --- a/drivers/gpu/nvgpu/Makefile +++ b/drivers/gpu/nvgpu/Makefile @@ -310,6 +310,7 @@ nvgpu-y += \ hal/bios/bios_tu104.o \ hal/top/top_gp106.o \ hal/top/top_gv100.o \ + hal/tpc/tpc_gv11b.o \ hal/xve/xve_gp106.o diff --git a/drivers/gpu/nvgpu/Makefile.sources b/drivers/gpu/nvgpu/Makefile.sources index e49ad26fb..cc9a27df5 100644 --- a/drivers/gpu/nvgpu/Makefile.sources +++ b/drivers/gpu/nvgpu/Makefile.sources @@ -149,6 +149,7 @@ srcs += common/utils/assert.c \ hal/fifo/runlist_fifo_gv11b.c \ hal/fifo/runlist_ram_gk20a.c \ hal/fifo/userd_gk20a.c \ + hal/tpc/tpc_gv11b.c \ hal/sync/syncpt_cmdbuf_gv11b.c # Source files below are functionaly safe (FuSa) and must always be included. diff --git a/drivers/gpu/nvgpu/common/init/nvgpu_init.c b/drivers/gpu/nvgpu/common/init/nvgpu_init.c index 478ddd0e9..06e654317 100644 --- a/drivers/gpu/nvgpu/common/init/nvgpu_init.c +++ b/drivers/gpu/nvgpu/common/init/nvgpu_init.c @@ -166,6 +166,7 @@ int nvgpu_prepare_poweroff(struct gk20a *g) int nvgpu_finalize_poweron(struct gk20a *g) { int err = 0; + u32 fuse_status; #if defined(CONFIG_TEGRA_GK20A_NVHOST) u64 nr_pages; #endif @@ -344,14 +345,20 @@ int nvgpu_finalize_poweron(struct gk20a *g) g->ops.mc.intr_enable(g); /* - * Overwrite can_tpc_powergate to false if the chip is ES fused and - * already optimized with some TPCs already floorswept - * via fuse. We will not support TPC-PG in those cases. + * Power gate the chip as per the TPC PG mask + * and the fuse_status register. + * If TPC PG mask is invalid halt the GPU poweron. */ + g->can_tpc_powergate = false; + fuse_status = g->ops.fuse.fuse_status_opt_tpc_gpc(g, 0); - if (g->ops.fuse.fuse_status_opt_tpc_gpc(g, 0) != 0x0U) { - g->can_tpc_powergate = false; - g->tpc_pg_mask = 0x0; + if (g->ops.tpc.tpc_powergate) { + err = g->ops.tpc.tpc_powergate(g, fuse_status); + } + + if (err) { + nvgpu_err(g, "failed to power ON GPU"); + goto done; } nvgpu_mutex_acquire(&g->tpc_pg_lock); diff --git a/drivers/gpu/nvgpu/hal/init/hal_gm20b.c b/drivers/gpu/nvgpu/hal/init/hal_gm20b.c index eb419708d..141af8306 100644 --- a/drivers/gpu/nvgpu/hal/init/hal_gm20b.c +++ b/drivers/gpu/nvgpu/hal/init/hal_gm20b.c @@ -1047,6 +1047,9 @@ static const struct gpu_ops gm20b_ops = { .get_max_lts_per_ltc = gm20b_top_get_max_lts_per_ltc, .get_num_ltcs = gm20b_top_get_num_ltcs, }, + .tpc = { + .tpc_powergate = NULL, + }, .chip_init_gpu_characteristics = nvgpu_init_gpu_characteristics, .get_litter_value = gm20b_get_litter_value, }; @@ -1121,6 +1124,8 @@ int gm20b_init_hal(struct gk20a *g) gops->fuse = gm20b_ops.fuse; + gops->tpc = gm20b_ops.tpc; + gops->top = gm20b_ops.top; /* Lone functions */ diff --git a/drivers/gpu/nvgpu/hal/init/hal_gp10b.c b/drivers/gpu/nvgpu/hal/init/hal_gp10b.c index 9fc737e9b..c87ecb8c3 100644 --- a/drivers/gpu/nvgpu/hal/init/hal_gp10b.c +++ b/drivers/gpu/nvgpu/hal/init/hal_gp10b.c @@ -1142,6 +1142,9 @@ static const struct gpu_ops gp10b_ops = { .get_max_lts_per_ltc = gm20b_top_get_max_lts_per_ltc, .get_num_ltcs = gm20b_top_get_num_ltcs, }, + .tpc = { + .tpc_powergate = NULL, + }, .chip_init_gpu_characteristics = gp10b_init_gpu_characteristics, .get_litter_value = gp10b_get_litter_value, }; @@ -1203,6 +1206,7 @@ int gp10b_init_hal(struct gk20a *g) gops->priv_ring = gp10b_ops.priv_ring; gops->fuse = gp10b_ops.fuse; + gops->tpc = gp10b_ops.tpc; gops->top = gp10b_ops.top; /* Lone Functions */ diff --git a/drivers/gpu/nvgpu/hal/init/hal_gv11b.c b/drivers/gpu/nvgpu/hal/init/hal_gv11b.c index 74169aba3..3613614d5 100644 --- a/drivers/gpu/nvgpu/hal/init/hal_gv11b.c +++ b/drivers/gpu/nvgpu/hal/init/hal_gv11b.c @@ -147,10 +147,12 @@ #include "common/pmu/pg/pg_sw_gp106.h" #include "common/pmu/pg/pg_sw_gv11b.h" #endif +#include "common/clk_arb/clk_arb_gp10b.h" + #include "hal/fifo/channel_gk20a.h" #include "hal/fifo/channel_gm20b.h" #include "hal/fifo/channel_gv11b.h" -#include "common/clk_arb/clk_arb_gp10b.h" +#include "hal/tpc/tpc_gv11b.h" #include "hal_gv11b.h" #include "hal_gv11b_litter.h" @@ -1341,6 +1343,9 @@ static const struct gpu_ops gv11b_ops = { .get_num_ltcs = gm20b_top_get_num_ltcs, .get_num_lce = gv11b_top_get_num_lce, }, + .tpc = { + .tpc_powergate = gv11b_tpc_powergate, + }, .chip_init_gpu_characteristics = gv11b_init_gpu_characteristics, .get_litter_value = gv11b_get_litter_value, }; @@ -1393,6 +1398,7 @@ int gv11b_init_hal(struct gk20a *g) gops->falcon = gv11b_ops.falcon; gops->priv_ring = gv11b_ops.priv_ring; gops->fuse = gv11b_ops.fuse; + gops->tpc = gv11b_ops.tpc; #ifdef CONFIG_NVGPU_CLK_ARB gops->clk_arb = gv11b_ops.clk_arb; #endif diff --git a/drivers/gpu/nvgpu/hal/tpc/tpc_gv11b.c b/drivers/gpu/nvgpu/hal/tpc/tpc_gv11b.c new file mode 100644 index 000000000..975d2f766 --- /dev/null +++ b/drivers/gpu/nvgpu/hal/tpc/tpc_gv11b.c @@ -0,0 +1,71 @@ +/* + * GV11B TPC + * + * 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 +#include "tpc_gv11b.h" + +int gv11b_tpc_powergate(struct gk20a *g, u32 fuse_status) +{ + int err = 0; + + if (fuse_status == 0x0) { + g->can_tpc_powergate = true; + + } else { + /* if hardware has already floorswept any TPC + * (fuse_status != 0x0) and if TPC PG mask + * sent from userspace is 0x0 GPU will be powered on + * with the default fuse_status setting. It cannot + * un-floorsweep any TPC + * thus, set g->tpc_pg_mask to fuse_status value + */ + if (g->tpc_pg_mask == 0x0) { + g->can_tpc_powergate = true; + g->tpc_pg_mask = fuse_status; + + } else if (fuse_status == g->tpc_pg_mask) { + g->can_tpc_powergate = true; + + } else if ((fuse_status & g->tpc_pg_mask) == + fuse_status) { + g->can_tpc_powergate = true; + + } else { + /* If userspace sends a TPC PG mask such that + * it tries to un-floorsweep any TPC which is + * already powergated from hardware, then + * such mask is invalid. + * In this case set tpc pg mask to 0x0 + * Return -EINVAL here and halt GPU poweron. + */ + nvgpu_err(g, "Invalid TPC_PG mask: 0x%x", + g->tpc_pg_mask); + g->can_tpc_powergate = false; + g->tpc_pg_mask = 0x0; + err = -EINVAL; + } + } + + return err; +} + diff --git a/drivers/gpu/nvgpu/hal/tpc/tpc_gv11b.h b/drivers/gpu/nvgpu/hal/tpc/tpc_gv11b.h new file mode 100644 index 000000000..15b04ae2c --- /dev/null +++ b/drivers/gpu/nvgpu/hal/tpc/tpc_gv11b.h @@ -0,0 +1,33 @@ +/* + * GV11B TPC + * + * 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 NVGPU_TPC_GV11B_H +#define NVGPU_TPC_GV11B_H + +struct gk20a; + +int gv11b_tpc_powergate(struct gk20a *g, u32 fuse_status); + +#endif /* NVGPU_TPC_GV11B_H */ + diff --git a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h index fcc56da71..e1e7be653 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h @@ -214,7 +214,7 @@ struct railgate_stats { #define nvgpu_get_litter_value(g, v) ((g)->ops.get_litter_value((g), v)) -#define MAX_TPC_PG_CONFIGS 3 +#define MAX_TPC_PG_CONFIGS 9 struct nvgpu_gpfifo_userdata { struct nvgpu_gpfifo_entry __user *entries; @@ -1911,6 +1911,9 @@ struct gpu_ops { void (*falcon_setup_boot_config)(struct gk20a *g); int (*gsp_reset)(struct gk20a *g); } gsp; + struct { + int (*tpc_powergate)(struct gk20a *g, u32 fuse_status); + } tpc; void (*semaphore_wakeup)(struct gk20a *g, bool post_events); }; diff --git a/drivers/gpu/nvgpu/os/linux/module.c b/drivers/gpu/nvgpu/os/linux/module.c index 5b84e71e1..94c79a2ff 100644 --- a/drivers/gpu/nvgpu/os/linux/module.c +++ b/drivers/gpu/nvgpu/os/linux/module.c @@ -1415,7 +1415,8 @@ static int nvgpu_read_fuse_overrides(struct gk20a *g) break; case GV11B_FUSE_OPT_TPC_DISABLE: if (platform->set_tpc_pg_mask != NULL) - platform->set_tpc_pg_mask(dev_from_gk20a(g), value); + platform->set_tpc_pg_mask(dev_from_gk20a(g), + value); break; default: nvgpu_err(g, "ignore unknown fuse override %08x", fuse); diff --git a/drivers/gpu/nvgpu/os/linux/platform_gk20a.h b/drivers/gpu/nvgpu/os/linux/platform_gk20a.h index c887e9716..5d041d0a4 100644 --- a/drivers/gpu/nvgpu/os/linux/platform_gk20a.h +++ b/drivers/gpu/nvgpu/os/linux/platform_gk20a.h @@ -218,8 +218,8 @@ struct gk20a_platform { /* Pre callback is called before frequency change */ void (*prescale)(struct device *dev); - /* Set TPC_PG during probe */ - void (*set_tpc_pg_mask)(struct device *dev, u32 tpc_mask); + /* Set TPC_PG_MASK during probe */ + void (*set_tpc_pg_mask)(struct device *dev, u32 tpc_pg_mask); /* Devfreq governor name. If scaling is enabled, we request * this governor to be used in scaling */ diff --git a/drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c b/drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c index ab11265b3..fd6e6ad37 100644 --- a/drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c +++ b/drivers/gpu/nvgpu/os/linux/platform_gv11b_tegra.c @@ -208,25 +208,27 @@ static int gv11b_tegra_suspend(struct device *dev) return 0; } -static bool is_tpc_mask_valid(struct gk20a_platform *platform, u32 tpc_mask) +static bool is_tpc_mask_valid(struct gk20a_platform *platform, u32 tpc_pg_mask) { u32 i; bool valid = false; for (i = 0; i < MAX_TPC_PG_CONFIGS; i++) { - if (tpc_mask == platform->valid_tpc_mask[i]) + if (tpc_pg_mask == platform->valid_tpc_mask[i]) { valid = true; + break; + } } return valid; } -static void gv11b_tegra_set_tpc_pg_mask(struct device *dev, u32 tpc_mask) +static void gv11b_tegra_set_tpc_pg_mask(struct device *dev, u32 tpc_pg_mask) { struct gk20a_platform *platform = gk20a_get_platform(dev); struct gk20a *g = get_gk20a(dev); - if (is_tpc_mask_valid(platform, tpc_mask)) { - g->tpc_pg_mask = tpc_mask; + if (is_tpc_mask_valid(platform, tpc_pg_mask)) { + g->tpc_pg_mask = tpc_pg_mask; } } @@ -247,9 +249,15 @@ struct gk20a_platform gv11b_tegra_platform = { .can_tpc_powergate = true, .valid_tpc_mask[0] = 0x0, .valid_tpc_mask[1] = 0x1, - .valid_tpc_mask[2] = 0x5, + .valid_tpc_mask[2] = 0x2, + .valid_tpc_mask[3] = 0x4, + .valid_tpc_mask[4] = 0x8, + .valid_tpc_mask[5] = 0x5, + .valid_tpc_mask[6] = 0x6, + .valid_tpc_mask[7] = 0x9, + .valid_tpc_mask[8] = 0xa, - .set_tpc_pg_mask = gv11b_tegra_set_tpc_pg_mask, + .set_tpc_pg_mask = gv11b_tegra_set_tpc_pg_mask, .can_slcg = true, .can_blcg = true, diff --git a/drivers/gpu/nvgpu/os/linux/sysfs.c b/drivers/gpu/nvgpu/os/linux/sysfs.c index 2b07b9958..868990ec0 100644 --- a/drivers/gpu/nvgpu/os/linux/sysfs.c +++ b/drivers/gpu/nvgpu/os/linux/sysfs.c @@ -818,8 +818,10 @@ static bool is_tpc_mask_valid(struct gk20a *g, u32 tpc_mask) bool valid = false; for (i = 0; i < MAX_TPC_PG_CONFIGS; i++) { - if (tpc_mask == g->valid_tpc_mask[i]) + if (tpc_mask == g->valid_tpc_mask[i]) { valid = true; + break; + } } return valid; } @@ -834,11 +836,6 @@ static ssize_t tpc_pg_mask_store(struct device *dev, nvgpu_mutex_acquire(&g->tpc_pg_lock); - if (!g->can_tpc_powergate) { - nvgpu_info(g, "TPC-PG not enabled for the platform"); - goto exit; - } - if (kstrtoul(buf, 10, &val) < 0) { nvgpu_err(g, "invalid value"); nvgpu_mutex_release(&g->tpc_pg_lock); @@ -855,7 +852,9 @@ static ssize_t tpc_pg_mask_store(struct device *dev, nvgpu_mutex_release(&g->tpc_pg_lock); return -ENODEV; } - + /* checking that the value from userspace is within + * the possible valid TPC configurations. + */ if (is_tpc_mask_valid(g, (u32)val)) { g->tpc_pg_mask = val; } else {