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 <tkudav@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1938046
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
tkudav
2018-10-29 16:11:15 +05:30
committed by mobile promotions
parent 03dcb8006e
commit 1cdcc54a53
11 changed files with 130 additions and 15 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 = {

View File

@@ -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 */

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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];

View File

@@ -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 = {

View File

@@ -29,6 +29,7 @@
#include <nvgpu/io.h>
#include <nvgpu/timers.h>
#include <nvgpu/gk20a.h>
#include <nvgpu/bios.h>
#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 */

View File

@@ -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