From 1cdcc54a532329203e7192076e6be41a99fab727 Mon Sep 17 00:00:00 2001 From: tkudav Date: Mon, 29 Oct 2018 16:11:15 +0530 Subject: [PATCH] gpu: nvgpu: Use nvlink speed from VBIOS Different SKUs may require different nvlink speed and hence the nvlink speed value should come from VBIOS. The initpll number corresponding to speed is present in VBIOS Low Power Nvlink table header. Parse this data from VBIOS and set corresponding nvlink speed and minion initpll DLCMD as default. We can no longer update the GV100 VBIOS with necessary nvlink speed value. Hence the hardcoding stays for GV100. The nvlink speed should match across the endpoints. So in speed_config fops, communicate the speed to nvlink core-driver for co-ordination with Tegra endpoint. Bug 2418403 Change-Id: Ib6f60951d4ca1c275968707d4cc6d738ba3a3f08 Signed-off-by: tkudav Reviewed-on: https://git-master.nvidia.com/r/1938046 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/common/nvlink.c | 23 +++++++++++++ drivers/gpu/nvgpu/common/vbios/bios.c | 43 ++++++++++++++++++++++++ drivers/gpu/nvgpu/gv100/hal_gv100.c | 1 + drivers/gpu/nvgpu/gv100/nvlink_gv100.c | 27 ++++++++------- drivers/gpu/nvgpu/gv100/nvlink_gv100.h | 1 + drivers/gpu/nvgpu/include/nvgpu/bios.h | 6 ++++ drivers/gpu/nvgpu/include/nvgpu/gk20a.h | 1 + drivers/gpu/nvgpu/include/nvgpu/nvlink.h | 10 ++++-- drivers/gpu/nvgpu/tu104/hal_tu104.c | 1 + drivers/gpu/nvgpu/tu104/nvlink_tu104.c | 31 +++++++++++++++++ drivers/gpu/nvgpu/tu104/nvlink_tu104.h | 1 + 11 files changed, 130 insertions(+), 15 deletions(-) diff --git a/drivers/gpu/nvgpu/common/nvlink.c b/drivers/gpu/nvgpu/common/nvlink.c index 714915666..d84660c4b 100644 --- a/drivers/gpu/nvgpu/common/nvlink.c +++ b/drivers/gpu/nvgpu/common/nvlink.c @@ -44,6 +44,28 @@ static u32 __nvgpu_nvlink_get_link(struct nvlink_device *ndev) return NVLINK_MAX_LINKS_SW; } +static int nvgpu_nvlink_speed_config(struct nvlink_device *ndev) +{ + struct gk20a *g = (struct gk20a *) ndev->priv; + int err; + + /* For now master topology is the only one supported */ + if (!ndev->is_master) { + nvgpu_err(g, "dGPU is not master for Nvlink speed config"); + return -EINVAL; + } + + err = g->ops.nvlink.speed_config(g); + if (err != 0) { + nvgpu_err(g, "Nvlink speed config failed.\n"); + return err; + } + ndev->speed = g->nvlink.speed; + nvgpu_log(g, gpu_dbg_nvlink, "Nvlink default speed set to %d\n", + ndev->speed); + return err; +} + static int nvgpu_nvlink_early_init(struct nvlink_device *ndev) { struct gk20a *g = (struct gk20a *) ndev->priv; @@ -413,6 +435,7 @@ static int nvgpu_nvlink_init_ops(struct gk20a *g) ndev->dev_ops.dev_reg_init = nvgpu_nvlink_reg_init; ndev->dev_ops.dev_interface_disable = nvgpu_nvlink_interface_disable; ndev->dev_ops.dev_shutdown = nvgpu_nvlink_shutdown; + ndev->dev_ops.dev_speed_config = nvgpu_nvlink_speed_config; /* Fill in the link struct */ ndev->link.device_id = ndev->device_id; diff --git a/drivers/gpu/nvgpu/common/vbios/bios.c b/drivers/gpu/nvgpu/common/vbios/bios.c index b1fbb43c7..69d7425aa 100644 --- a/drivers/gpu/nvgpu/common/vbios/bios.c +++ b/drivers/gpu/nvgpu/common/vbios/bios.c @@ -92,6 +92,18 @@ struct nvlink_config_data_hdr_v1 { u32 ac_coupling_mask; } __packed; +#define LWPR_NVLINK_TABLE_10_HDR_VER_10 0x10U +#define LPWR_NVLINK_TABLE_10_HDR_SIZE_06 6U + +struct lpwr_nvlink_table_hdr_v1 { + u8 version; + u8 hdr_size; + u8 entry_size; + u8 entry_count; + u8 default_entry_idx; + u8 line_rate_initpll_ordinal; +} __packed; + #define MEMORY_PTRS_V1 1U #define MEMORY_PTRS_V2 2U @@ -430,6 +442,37 @@ u32 nvgpu_bios_get_nvlink_config_data(struct gk20a *g) return 0; } +int nvgpu_bios_get_lpwr_nvlink_table_hdr(struct gk20a *g) +{ + struct lpwr_nvlink_table_hdr_v1 hdr; + u8 *lpwr_nvlink_tbl_hdr_ptr = NULL; + + lpwr_nvlink_tbl_hdr_ptr = (u8 *)nvgpu_bios_get_perf_table_ptrs(g, + g->bios.perf_token, + LPWR_NVLINK_TABLE); + if (lpwr_nvlink_tbl_hdr_ptr == NULL) { + nvgpu_err(g, "Invalid pointer to LPWR_NVLINK_TABLE\n"); + return -EINVAL; + } + + nvgpu_memcpy((u8 *)&hdr, lpwr_nvlink_tbl_hdr_ptr, + LPWR_NVLINK_TABLE_10_HDR_SIZE_06); + + if (hdr.version != LWPR_NVLINK_TABLE_10_HDR_VER_10) { + nvgpu_err(g, "Unsupported LPWR_NVLINK_TABLE version: 0x%x", + hdr.version); + return -EINVAL; + } + + g->nvlink.initpll_ordinal = + BIOS_GET_FIELD(hdr.line_rate_initpll_ordinal, + VBIOS_LPWR_NVLINK_TABLE_HDR_INITPLL_ORDINAL); + nvgpu_log(g, gpu_dbg_nvlink, " Nvlink initpll_ordinal: 0x%x", + g->nvlink.initpll_ordinal); + + return 0; +} + static void nvgpu_bios_parse_memory_ptrs(struct gk20a *g, int offset, u8 version) { struct memory_ptrs_v1 v1; diff --git a/drivers/gpu/nvgpu/gv100/hal_gv100.c b/drivers/gpu/nvgpu/gv100/hal_gv100.c index 138ab7737..71bfcdbfe 100644 --- a/drivers/gpu/nvgpu/gv100/hal_gv100.c +++ b/drivers/gpu/nvgpu/gv100/hal_gv100.c @@ -971,6 +971,7 @@ static const struct gpu_ops gv100_ops = { .reg_init = gv100_nvlink_reg_init, .shutdown = gv100_nvlink_shutdown, .early_init = gv100_nvlink_early_init, + .speed_config = gv100_nvlink_speed_config, }, #endif .top = { diff --git a/drivers/gpu/nvgpu/gv100/nvlink_gv100.c b/drivers/gpu/nvgpu/gv100/nvlink_gv100.c index 3dcbcbdc6..d259d97a9 100644 --- a/drivers/gpu/nvgpu/gv100/nvlink_gv100.c +++ b/drivers/gpu/nvgpu/gv100/nvlink_gv100.c @@ -767,21 +767,11 @@ static int gv100_nvlink_minion_init_uphy(struct gk20a *g, unsigned long mask, bool sync) { int err = 0; - u32 init_pll_cmd; u32 link_id, master_pll, slave_pll; u32 master_state, slave_state; unsigned long link_enable; - switch(g->nvlink.speed) { - case nvgpu_nvlink_speed_20G: - init_pll_cmd = minion_nvlink_dl_cmd_command_initpll_1_v(); - break; - default: - nvgpu_err(g, "Unsupported UPHY speed"); - return -EINVAL; - } - link_enable = __gv100_nvlink_get_link_reset_mask(g); for_each_set_bit(link_id, &mask, 32) { @@ -809,7 +799,7 @@ static int gv100_nvlink_minion_init_uphy(struct gk20a *g, unsigned long mask, /* Check if INIT PLL is done on link */ if (!(BIT(master_pll) & g->nvlink.init_pll_done)) { err = gv100_nvlink_minion_send_command(g, master_pll, - init_pll_cmd, 0, sync); + g->nvlink.initpll_cmd, 0, sync); if (err != 0) { nvgpu_err(g, " Error sending INITPLL to minion"); return err; @@ -2691,6 +2681,12 @@ int gv100_nvlink_early_init(struct gk20a *g) if (!nvgpu_is_enabled(g, NVGPU_SUPPORT_NVLINK)) return -EINVAL; + err = nvgpu_bios_get_lpwr_nvlink_table_hdr(g); + if (err != 0) { + nvgpu_err(g, "Failed to read LWPR_NVLINK_TABLE header\n"); + goto nvlink_init_exit; + } + err = nvgpu_bios_get_nvlink_config_data(g); if (err != 0) { nvgpu_err(g, "failed to read nvlink vbios data"); @@ -2751,8 +2747,6 @@ int gv100_nvlink_early_init(struct gk20a *g) goto nvlink_init_exit; } - g->nvlink.speed = nvgpu_nvlink_speed_20G; - err = __gv100_nvlink_state_load_hal(g); if (err != 0) { nvgpu_err(g, " failed Nvlink state load"); @@ -2772,4 +2766,11 @@ nvlink_init_exit: return err; } +int gv100_nvlink_speed_config(struct gk20a *g) +{ + g->nvlink.speed = nvgpu_nvlink_speed_20G; + g->nvlink.initpll_ordinal = INITPLL_1; + g->nvlink.initpll_cmd = minion_nvlink_dl_cmd_command_initpll_1_v(); + return 0; +} #endif /* CONFIG_TEGRA_NVLINK */ diff --git a/drivers/gpu/nvgpu/gv100/nvlink_gv100.h b/drivers/gpu/nvgpu/gv100/nvlink_gv100.h index 75595bca6..7150aba32 100644 --- a/drivers/gpu/nvgpu/gv100/nvlink_gv100.h +++ b/drivers/gpu/nvgpu/gv100/nvlink_gv100.h @@ -54,4 +54,5 @@ int gv100_nvlink_interface_disable(struct gk20a *g); int gv100_nvlink_reg_init(struct gk20a *g); int gv100_nvlink_shutdown(struct gk20a *g); int gv100_nvlink_early_init(struct gk20a *g); +int gv100_nvlink_speed_config(struct gk20a *g); #endif diff --git a/drivers/gpu/nvgpu/include/nvgpu/bios.h b/drivers/gpu/nvgpu/include/nvgpu/bios.h index bcc15a715..a389d808f 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/bios.h +++ b/drivers/gpu/nvgpu/include/nvgpu/bios.h @@ -58,6 +58,7 @@ enum { LOWPOWER_TABLE, LOWPOWER_GR_TABLE = 32, LOWPOWER_MS_TABLE = 33, + LPWR_NVLINK_TABLE = 39, }; enum { @@ -1144,6 +1145,10 @@ struct nvgpu_bios_lpwr_gr_table_1x_entry { #define NV_VBIOS_LPWR_GR_FEATURE_MASK_GR_RPPG_MASK GENMASK(4, 4) #define NV_VBIOS_LPWR_GR_FEATURE_MASK_GR_RPPG_SHIFT 4 + +#define VBIOS_LPWR_NVLINK_TABLE_HDR_INITPLL_ORDINAL_MASK 0x07U +#define VBIOS_LPWR_NVLINK_TABLE_HDR_INITPLL_ORDINAL_SHIFT 0x00U + int nvgpu_bios_parse_rom(struct gk20a *g); u8 nvgpu_bios_read_u8(struct gk20a *g, u32 offset); s8 nvgpu_bios_read_s8(struct gk20a *g, u32 offset); @@ -1153,4 +1158,5 @@ void *nvgpu_bios_get_perf_table_ptrs(struct gk20a *g, struct bit_token *ptoken, u8 table_id); int nvgpu_bios_execute_script(struct gk20a *g, u32 offset); u32 nvgpu_bios_get_nvlink_config_data(struct gk20a *g); +int nvgpu_bios_get_lpwr_nvlink_table_hdr(struct gk20a *g); #endif diff --git a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h index 40a98d3fc..90008f790 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/gk20a.h +++ b/drivers/gpu/nvgpu/include/nvgpu/gk20a.h @@ -1352,6 +1352,7 @@ struct gpu_ops { int (*reg_init)(struct gk20a *g); int (*shutdown)(struct gk20a *g); int (*early_init)(struct gk20a *g); + int (*speed_config)(struct gk20a *g); } nvlink; struct { u32 (*get_nvhsclk_ctrl_e_clk_nvl)(struct gk20a *g); diff --git a/drivers/gpu/nvgpu/include/nvgpu/nvlink.h b/drivers/gpu/nvgpu/include/nvgpu/nvlink.h index a74111cdb..6d9dfa783 100644 --- a/drivers/gpu/nvgpu/include/nvgpu/nvlink.h +++ b/drivers/gpu/nvgpu/include/nvgpu/nvlink.h @@ -36,6 +36,9 @@ #define NV_NVLINK_REG_POLL_TIMEOUT_MS 3000 #define NV_NVLINK_TIMEOUT_DELAY_US 5 +#define INITPLL_1 U8(1) +#define INITPLL_7 U8(7) + #define MINION_REG_RD32(g, off) gk20a_readl(g, g->nvlink.minion_base + (off)) #define MINION_REG_WR32(g, off, v) gk20a_writel(g, g->nvlink.minion_base + (off), (v)) #define IOCTRL_REG_RD32(g, off) gk20a_readl(g, g->nvlink.ioctrl_base + (off)) @@ -153,9 +156,10 @@ struct nvgpu_nvlink_link { #define NVLINK_MAX_LINKS_SW 6 + enum nvgpu_nvlink_speed { - nvgpu_nvlink_speed_25G, - nvgpu_nvlink_speed_20G, + nvgpu_nvlink_speed_16G = 16, + nvgpu_nvlink_speed_20G = 20, nvgpu_nvlink_speed__last, }; @@ -208,6 +212,7 @@ struct nvgpu_nvlink_dev { u32 link_refclk_mask; u8 train_at_boot; u32 ac_coupling_mask; + u8 initpll_ordinal; u32 connected_links; u32 initialized_links; @@ -215,6 +220,7 @@ struct nvgpu_nvlink_dev { u32 init_pll_done; enum nvgpu_nvlink_speed speed; + u32 initpll_cmd; /* tlc cached errors */ u32 tlc_rx_err_status_0[NVLINK_MAX_LINKS_SW]; diff --git a/drivers/gpu/nvgpu/tu104/hal_tu104.c b/drivers/gpu/nvgpu/tu104/hal_tu104.c index a72d57c89..c1c12f150 100644 --- a/drivers/gpu/nvgpu/tu104/hal_tu104.c +++ b/drivers/gpu/nvgpu/tu104/hal_tu104.c @@ -989,6 +989,7 @@ static const struct gpu_ops tu104_ops = { .reg_init = gv100_nvlink_reg_init, .shutdown = gv100_nvlink_shutdown, .early_init = gv100_nvlink_early_init, + .speed_config = tu104_nvlink_speed_config, }, #endif .acr = { diff --git a/drivers/gpu/nvgpu/tu104/nvlink_tu104.c b/drivers/gpu/nvgpu/tu104/nvlink_tu104.c index aeef59a59..8bd248701 100644 --- a/drivers/gpu/nvgpu/tu104/nvlink_tu104.c +++ b/drivers/gpu/nvgpu/tu104/nvlink_tu104.c @@ -29,6 +29,7 @@ #include #include #include +#include #include "gv100/nvlink_gv100.h" #include "nvlink_tu104.h" @@ -254,4 +255,34 @@ void tu104_nvlink_get_connected_link_mask(u32 *link_mask) *link_mask = TU104_CONNECTED_LINK_MASK; } +int tu104_nvlink_speed_config(struct gk20a *g) +{ + int ret = 0; + + ret = nvgpu_bios_get_lpwr_nvlink_table_hdr(g); + if (ret != 0) { + nvgpu_err(g, "Failed to read LWPR_NVLINK_TABLE header\n"); + return ret; + } + + switch (g->nvlink.initpll_ordinal) { + case INITPLL_1: + g->nvlink.speed = nvgpu_nvlink_speed_20G; + g->nvlink.initpll_cmd = + minion_nvlink_dl_cmd_command_initpll_1_v(); + break; + case INITPLL_7: + g->nvlink.speed = nvgpu_nvlink_speed_16G; + g->nvlink.initpll_cmd = + minion_nvlink_dl_cmd_command_initpll_7_v(); + break; + default: + nvgpu_err(g, "Nvlink initpll %d from VBIOS not supported.", + g->nvlink.initpll_ordinal); + ret = -EINVAL; + break; + } + + return ret; +} #endif /* CONFIG_TEGRA_NVLINK */ diff --git a/drivers/gpu/nvgpu/tu104/nvlink_tu104.h b/drivers/gpu/nvgpu/tu104/nvlink_tu104.h index 99010010a..7f1a8626c 100644 --- a/drivers/gpu/nvgpu/tu104/nvlink_tu104.h +++ b/drivers/gpu/nvgpu/tu104/nvlink_tu104.h @@ -35,4 +35,5 @@ u32 tu104_nvlink_link_get_rx_sublink_state(struct gk20a *g, u32 link_id); int tu104_nvlink_minion_data_ready_en(struct gk20a *g, unsigned long mask, bool sync); void tu104_nvlink_get_connected_link_mask(u32 *link_mask); +int tu104_nvlink_speed_config(struct gk20a *g); #endif