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