static void vgpu_gr_free_channel_gr_ctx(struct channel_gk20a *c) { struct gk20a_platform *platform = gk20a_get_platform(c->g->dev); struct channel_ctx_gk20a *ch_ctx = &c->ch_ctx; struct vm_gk20a *ch_vm = c->vm; gk20a_dbg_fn(""); if (ch_ctx->gr_ctx && ch_ctx->gr_ctx->mem.gpu_va) { struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_gr_ctx_params *p = &msg.params.gr_ctx; int err; msg.cmd = TEGRA_VGPU_CMD_CHANNEL_FREE_GR_CTX; msg.handle = platform->virt_handle; p->handle = c->virt_ctx; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); WARN_ON(err || msg.ret); gk20a_vm_free_va(ch_vm, ch_ctx->gr_ctx->mem.gpu_va, ch_ctx->gr_ctx->mem.size, 0); ch_ctx->gr_ctx->mem.gpu_va = 0; kfree(ch_ctx->gr_ctx); } }
static void vgpu_gr_detect_sm_arch(struct gk20a *g) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); u32 v = 0, raw_version, version = 0; gk20a_dbg_fn(""); if (vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_GPC0_TPC0_SM_ARCH, &v)) gk20a_err(dev_from_gk20a(g), "failed to retrieve SM arch"); raw_version = gr_gpc0_tpc0_sm_arch_spa_version_v(v); if (raw_version == gr_gpc0_tpc0_sm_arch_spa_version_smkepler_lp_v()) version = 0x320; /* SM 3.2 */ else gk20a_err(dev_from_gk20a(g), "Unknown SM version 0x%x", raw_version); /* on Kepler, SM version == SPA version */ g->gpu_characteristics.sm_arch_spa_version = version; g->gpu_characteristics.sm_arch_sm_version = version; g->gpu_characteristics.sm_arch_warp_count = gr_gpc0_tpc0_sm_arch_warp_count_v(v); }
static void vgpu_gr_unmap_global_ctx_buffers(struct channel_gk20a *c) { struct gk20a_platform *platform = gk20a_get_platform(c->g->dev); struct vm_gk20a *ch_vm = c->vm; u64 *g_bfr_va = c->ch_ctx.global_ctx_buffer_va; u64 *g_bfr_size = c->ch_ctx.global_ctx_buffer_size; u32 i; gk20a_dbg_fn(""); if (c->ch_ctx.global_ctx_buffer_mapped) { struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_gr_ctx_params *p = &msg.params.gr_ctx; int err; msg.cmd = TEGRA_VGPU_CMD_CHANNEL_UNMAP_GR_GLOBAL_CTX; msg.handle = platform->virt_handle; p->handle = c->virt_ctx; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); WARN_ON(err || msg.ret); } for (i = 0; i < NR_GLOBAL_CTX_BUF_VA; i++) { if (g_bfr_va[i]) { gk20a_vm_free_va(ch_vm, g_bfr_va[i], g_bfr_size[i], 0); g_bfr_va[i] = 0; g_bfr_size[i] = 0; } } c->ch_ctx.global_ctx_buffer_mapped = false; }
static int vgpu_gr_add_zbc(struct gk20a *g, struct gr_gk20a *gr, struct zbc_entry *zbc_val) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); struct tegra_vgpu_cmd_msg msg = {0}; struct tegra_vgpu_zbc_set_table_params *p = &msg.params.zbc_set_table; int err; gk20a_dbg_fn(""); msg.cmd = TEGRA_VGPU_CMD_ZBC_SET_TABLE; msg.handle = platform->virt_handle; p->type = zbc_val->type; p->format = zbc_val->format; switch (p->type) { case GK20A_ZBC_TYPE_COLOR: memcpy(p->color_ds, zbc_val->color_ds, sizeof(p->color_ds)); memcpy(p->color_l2, zbc_val->color_l2, sizeof(p->color_l2)); break; case GK20A_ZBC_TYPE_DEPTH: p->depth = zbc_val->depth; break; default: return -EINVAL; } err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); return (err || msg.ret) ? -ENOMEM : 0; }
static int vgpu_gr_alloc_channel_patch_ctx(struct gk20a *g, struct channel_gk20a *c) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); struct patch_desc *patch_ctx = &c->ch_ctx.patch_ctx; struct vm_gk20a *ch_vm = c->vm; struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_gr_ctx_params *p = &msg.params.gr_ctx; int err; gk20a_dbg_fn(""); patch_ctx->mem.size = 128 * sizeof(u32); patch_ctx->mem.gpu_va = gk20a_vm_alloc_va(ch_vm, patch_ctx->mem.size, 0); if (!patch_ctx->mem.gpu_va) return -ENOMEM; msg.cmd = TEGRA_VGPU_CMD_CHANNEL_ALLOC_GR_PATCH_CTX; msg.handle = platform->virt_handle; p->handle = c->virt_ctx; p->patch_ctx_va = patch_ctx->mem.gpu_va; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); if (err || msg.ret) { gk20a_vm_free_va(ch_vm, patch_ctx->mem.gpu_va, patch_ctx->mem.size, 0); err = -ENOMEM; } return err; }
static int vgpu_gr_get_zcull_info(struct gk20a *g, struct gr_gk20a *gr, struct gr_zcull_info *zcull_params) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_zcull_info_params *p = &msg.params.zcull_info; int err; gk20a_dbg_fn(""); msg.cmd = TEGRA_VGPU_CMD_GET_ZCULL_INFO; msg.handle = platform->virt_handle; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); if (err || msg.ret) return -ENOMEM; zcull_params->width_align_pixels = p->width_align_pixels; zcull_params->height_align_pixels = p->height_align_pixels; zcull_params->pixel_squares_by_aliquots = p->pixel_squares_by_aliquots; zcull_params->aliquot_total = p->aliquot_total; zcull_params->region_byte_multiplier = p->region_byte_multiplier; zcull_params->region_header_size = p->region_header_size; zcull_params->subregion_header_size = p->subregion_header_size; zcull_params->subregion_width_align_pixels = p->subregion_width_align_pixels; zcull_params->subregion_height_align_pixels = p->subregion_height_align_pixels; zcull_params->subregion_count = p->subregion_count; return 0; }
static int gk20a_generic_probe(struct platform_device *dev) { struct gk20a_platform *platform = gk20a_get_platform(dev); /* TODO: Initialize clocks and power */ (void)platform; return 0; }
void gk20a_debug_dump(struct platform_device *pdev) { struct gk20a_platform *platform = gk20a_get_platform(pdev); struct gk20a_debug_output o = { .fn = gk20a_debug_write_printk }; if (platform->dump_platform_dependencies) platform->dump_platform_dependencies(pdev); gk20a_debug_show_dump(pdev, &o); }
static int vgpu_determine_L2_size_bytes(struct gk20a *g) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); u32 cache_size = 0; gk20a_dbg_fn(""); if (vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_L2_SIZE, &cache_size)) dev_err(dev_from_gk20a(g), "unable to get L2 size"); return cache_size; }
static u32 vgpu_gr_get_max_fbps_count(struct gk20a *g) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); u32 max_fbps_count = 0; gk20a_dbg_fn(""); if (vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_NUM_FBPS, &max_fbps_count)) gk20a_err(dev_from_gk20a(g), "failed to retrieve num fbps"); return max_fbps_count; }
static u32 vgpu_gr_get_fbp_en_mask(struct gk20a *g) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); u32 fbp_en_mask = 0; gk20a_dbg_fn(""); if (vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_FBP_EN_MASK, &fbp_en_mask)) gk20a_err(dev_from_gk20a(g), "failed to retrieve fbp en mask"); return fbp_en_mask; }
static int vgpu_gr_alloc_channel_gr_ctx(struct gk20a *g, struct channel_gk20a *c) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_gr_ctx_params *p = &msg.params.gr_ctx; struct gr_gk20a *gr = &g->gr; struct gr_ctx_desc *gr_ctx; struct vm_gk20a *ch_vm = c->vm; int err; gk20a_dbg_fn(""); if (gr->ctx_vars.buffer_size == 0) return 0; /* alloc channel gr ctx buffer */ gr->ctx_vars.buffer_size = gr->ctx_vars.golden_image_size; gr->ctx_vars.buffer_total_size = gr->ctx_vars.golden_image_size; gr_ctx = kzalloc(sizeof(*gr_ctx), GFP_KERNEL); if (!gr_ctx) return -ENOMEM; gr_ctx->mem.size = gr->ctx_vars.buffer_total_size; gr_ctx->mem.gpu_va = gk20a_vm_alloc_va(ch_vm, gr_ctx->mem.size, 0); if (!gr_ctx->mem.gpu_va) { kfree(gr_ctx); return -ENOMEM; } msg.cmd = TEGRA_VGPU_CMD_CHANNEL_ALLOC_GR_CTX; msg.handle = platform->virt_handle; p->handle = c->virt_ctx; p->gr_ctx_va = gr_ctx->mem.gpu_va; p->class_num = c->obj_class; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); if (err || msg.ret) { kfree(gr_ctx); gk20a_vm_free_va(ch_vm, gr_ctx->mem.gpu_va, gr_ctx->mem.size, 0); err = -ENOMEM; } else c->ch_ctx.gr_ctx = gr_ctx; return err; }
static int vgpu_gr_commit_inst(struct channel_gk20a *c, u64 gpu_va) { struct gk20a_platform *platform = gk20a_get_platform(c->g->dev); struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_gr_ctx_params *p = &msg.params.gr_ctx; int err; gk20a_dbg_fn(""); msg.cmd = TEGRA_VGPU_CMD_CHANNEL_COMMIT_GR_CTX; msg.handle = platform->virt_handle; p->handle = c->virt_ctx; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); return (err || msg.ret) ? -1 : 0; }
/* load saved fresh copy of gloden image into channel gr_ctx */ static int vgpu_gr_load_golden_ctx_image(struct gk20a *g, struct channel_gk20a *c) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_gr_ctx_params *p = &msg.params.gr_ctx; int err; gk20a_dbg_fn(""); msg.cmd = TEGRA_VGPU_CMD_CHANNEL_LOAD_GR_GOLDEN_CTX; msg.handle = platform->virt_handle; p->handle = c->virt_ctx; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); return (err || msg.ret) ? -1 : 0; }
static int vgpu_ltc_init_comptags(struct gk20a *g, struct gr_gk20a *gr) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); u32 max_comptag_lines = 0; int err; gk20a_dbg_fn(""); vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_COMPTAG_LINES, &max_comptag_lines); if (max_comptag_lines < 2) return -ENXIO; err = gk20a_comptag_allocator_init(&gr->comp_tags, max_comptag_lines); if (err) return err; return 0; }
static int vgpu_gr_query_zbc(struct gk20a *g, struct gr_gk20a *gr, struct zbc_query_params *query_params) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); struct tegra_vgpu_cmd_msg msg = {0}; struct tegra_vgpu_zbc_query_table_params *p = &msg.params.zbc_query_table; int err; gk20a_dbg_fn(""); msg.cmd = TEGRA_VGPU_CMD_ZBC_QUERY_TABLE; msg.handle = platform->virt_handle; p->type = query_params->type; p->index_size = query_params->index_size; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); if (err || msg.ret) return -ENOMEM; switch (query_params->type) { case GK20A_ZBC_TYPE_COLOR: memcpy(query_params->color_ds, p->color_ds, sizeof(query_params->color_ds)); memcpy(query_params->color_l2, p->color_l2, sizeof(query_params->color_l2)); break; case GK20A_ZBC_TYPE_DEPTH: query_params->depth = p->depth; break; case GK20A_ZBC_TYPE_INVALID: query_params->index_size = p->index_size; break; default: return -EINVAL; } query_params->ref_cnt = p->ref_cnt; query_params->format = p->format; return 0; }
static int vgpu_gr_init_ctx_state(struct gk20a *g, struct gr_gk20a *gr) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); gk20a_dbg_fn(""); vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_GOLDEN_CTX_SIZE, &g->gr.ctx_vars.golden_image_size); vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_ZCULL_CTX_SIZE, &g->gr.ctx_vars.zcull_ctxsw_image_size); if (!g->gr.ctx_vars.golden_image_size || !g->gr.ctx_vars.zcull_ctxsw_image_size) return -ENXIO; gr->ctx_vars.buffer_size = g->gr.ctx_vars.golden_image_size; g->gr.ctx_vars.priv_access_map_size = 512 * 1024; return 0; }
static int vgpu_gr_bind_ctxsw_zcull(struct gk20a *g, struct gr_gk20a *gr, struct channel_gk20a *c, u64 zcull_va, u32 mode) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_zcull_bind_params *p = &msg.params.zcull_bind; int err; gk20a_dbg_fn(""); msg.cmd = TEGRA_VGPU_CMD_CHANNEL_BIND_ZCULL; msg.handle = platform->virt_handle; p->handle = c->virt_ctx; p->zcull_va = zcull_va; p->mode = mode; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); return (err || msg.ret) ? -ENOMEM : 0; }
static int vgpu_gr_init_gr_config(struct gk20a *g, struct gr_gk20a *gr) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); u32 gpc_index; gk20a_dbg_fn(""); if (vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_GPC_COUNT, &gr->gpc_count)) return -ENOMEM; if (vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_MAX_TPC_PER_GPC_COUNT, &gr->max_tpc_per_gpc_count)) return -ENOMEM; if (vgpu_get_attribute(platform->virt_handle, TEGRA_VGPU_ATTRIB_MAX_TPC_COUNT, &gr->max_tpc_count)) return -ENOMEM; gr->gpc_tpc_mask = kzalloc(gr->gpc_count * sizeof(u32), GFP_KERNEL); if (!gr->gpc_tpc_mask) { gk20a_err(dev_from_gk20a(g), "%s: out of memory\n", __func__); return -ENOMEM; } for (gpc_index = 0; gpc_index < gr->gpc_count; gpc_index++) { if (g->ops.gr.get_gpc_tpc_mask) gr->gpc_tpc_mask[gpc_index] = g->ops.gr.get_gpc_tpc_mask(g, gpc_index); } g->ops.gr.bundle_cb_defaults(g); g->ops.gr.cb_size_default(g); g->ops.gr.calc_global_ctx_buffer_size(g); return 0; }
static void gk20a_debug_show_dump(struct platform_device *pdev, struct gk20a_debug_output *o) { struct gk20a_platform *platform = gk20a_get_platform(pdev); struct gk20a *g = platform->g; struct fifo_gk20a *f = &g->fifo; u32 chid; int i, err; err = gk20a_busy(g->dev); if (err) { gk20a_debug_output(o, "failed to power on gpu: %d\n", err); return; } for (i = 0; i < fifo_pbdma_status__size_1_v(); i++) { u32 status = gk20a_readl(g, fifo_pbdma_status_r(i)); u32 chan_status = fifo_pbdma_status_chan_status_v(status); gk20a_debug_output(o, "%s pbdma %d: ", g->dev->name, i); gk20a_debug_output(o, "id: %d (%s), next_id: %d (%s) status: %s\n", fifo_pbdma_status_id_v(status), fifo_pbdma_status_id_type_v(status) ? "tsg" : "channel", fifo_pbdma_status_next_id_v(status), fifo_pbdma_status_next_id_type_v(status) ? "tsg" : "channel", chan_status_str[chan_status]); gk20a_debug_output(o, "PUT: %016llx GET: %016llx " "FETCH: %08x HEADER: %08x\n", (u64)gk20a_readl(g, pbdma_put_r(i)) + ((u64)gk20a_readl(g, pbdma_put_hi_r(i)) << 32ULL), (u64)gk20a_readl(g, pbdma_get_r(i)) + ((u64)gk20a_readl(g, pbdma_get_hi_r(i)) << 32ULL), gk20a_readl(g, pbdma_gp_fetch_r(i)), gk20a_readl(g, pbdma_pb_header_r(i))); } gk20a_debug_output(o, "\n"); for (i = 0; i < fifo_engine_status__size_1_v(); i++) { u32 status = gk20a_readl(g, fifo_engine_status_r(i)); u32 ctx_status = fifo_engine_status_ctx_status_v(status); gk20a_debug_output(o, "%s eng %d: ", g->dev->name, i); gk20a_debug_output(o, "id: %d (%s), next_id: %d (%s), ctx: %s ", fifo_engine_status_id_v(status), fifo_engine_status_id_type_v(status) ? "tsg" : "channel", fifo_engine_status_next_id_v(status), fifo_engine_status_next_id_type_v(status) ? "tsg" : "channel", ctx_status_str[ctx_status]); if (fifo_engine_status_faulted_v(status)) gk20a_debug_output(o, "faulted "); if (fifo_engine_status_engine_v(status)) gk20a_debug_output(o, "busy "); gk20a_debug_output(o, "\n"); } gk20a_debug_output(o, "\n"); for (chid = 0; chid < f->num_channels; chid++) { if (f->channel[chid].in_use) { struct channel_gk20a *gpu_ch = &f->channel[chid]; gk20a_debug_show_channel(g, o, gpu_ch); } } gk20a_idle(g->dev); }
static int vgpu_gr_map_global_ctx_buffers(struct gk20a *g, struct channel_gk20a *c) { struct gk20a_platform *platform = gk20a_get_platform(g->dev); struct tegra_vgpu_cmd_msg msg; struct tegra_vgpu_gr_ctx_params *p = &msg.params.gr_ctx; struct vm_gk20a *ch_vm = c->vm; u64 *g_bfr_va = c->ch_ctx.global_ctx_buffer_va; u64 *g_bfr_size = c->ch_ctx.global_ctx_buffer_size; struct gr_gk20a *gr = &g->gr; u64 gpu_va; u32 i; int err; gk20a_dbg_fn(""); /* FIXME: add VPR support */ /* Circular Buffer */ gpu_va = gk20a_vm_alloc_va(ch_vm, gr->global_ctx_buffer[CIRCULAR].mem.size, 0); if (!gpu_va) goto clean_up; g_bfr_va[CIRCULAR_VA] = gpu_va; g_bfr_size[CIRCULAR_VA] = gr->global_ctx_buffer[CIRCULAR].mem.size; /* Attribute Buffer */ gpu_va = gk20a_vm_alloc_va(ch_vm, gr->global_ctx_buffer[ATTRIBUTE].mem.size, 0); if (!gpu_va) goto clean_up; g_bfr_va[ATTRIBUTE_VA] = gpu_va; g_bfr_size[ATTRIBUTE_VA] = gr->global_ctx_buffer[ATTRIBUTE].mem.size; /* Page Pool */ gpu_va = gk20a_vm_alloc_va(ch_vm, gr->global_ctx_buffer[PAGEPOOL].mem.size, 0); if (!gpu_va) goto clean_up; g_bfr_va[PAGEPOOL_VA] = gpu_va; g_bfr_size[PAGEPOOL_VA] = gr->global_ctx_buffer[PAGEPOOL].mem.size; /* Priv register Access Map */ gpu_va = gk20a_vm_alloc_va(ch_vm, gr->global_ctx_buffer[PRIV_ACCESS_MAP].mem.size, 0); if (!gpu_va) goto clean_up; g_bfr_va[PRIV_ACCESS_MAP_VA] = gpu_va; g_bfr_size[PRIV_ACCESS_MAP_VA] = gr->global_ctx_buffer[PRIV_ACCESS_MAP].mem.size; msg.cmd = TEGRA_VGPU_CMD_CHANNEL_MAP_GR_GLOBAL_CTX; msg.handle = platform->virt_handle; p->handle = c->virt_ctx; p->cb_va = g_bfr_va[CIRCULAR_VA]; p->attr_va = g_bfr_va[ATTRIBUTE_VA]; p->page_pool_va = g_bfr_va[PAGEPOOL_VA]; p->priv_access_map_va = g_bfr_va[PRIV_ACCESS_MAP_VA]; err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); if (err || msg.ret) goto clean_up; c->ch_ctx.global_ctx_buffer_mapped = true; return 0; clean_up: for (i = 0; i < NR_GLOBAL_CTX_BUF_VA; i++) { if (g_bfr_va[i]) { gk20a_vm_free_va(ch_vm, g_bfr_va[i], g_bfr_size[i], 0); g_bfr_va[i] = 0; } } return -ENOMEM; }