Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Linux/drivers/gpu/drm/radeon/   (Open Source Betriebssystem Version 6.17.9©)  Datei vom 24.10.2025 mit Größe 106 kB image not shown  

Quelle  evergreen_cs.c   Sprache: C

 
/*
 * Copyright 2010 Advanced Micro Devices, Inc.
 * Copyright 2008 Red Hat Inc.
 * Copyright 2009 Jerome Glisse.
 *
 * 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 COPYRIGHT HOLDER(S) OR AUTHOR(S) 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.
 *
 * Authors: Dave Airlie
 *          Alex Deucher
 *          Jerome Glisse
 */

#include "radeon.h"
#include "radeon_asic.h"
#include "r600.h"
#include "evergreend.h"
#include "evergreen_reg_safe.h"
#include "cayman_reg_safe.h"

#ifndef MIN
#define MAX(a, b)                   (((a) > (b)) ? (a) : (b))
#define MIN(a, b)                   (((a) < (b)) ? (a) : (b))
#endif

#define REG_SAFE_BM_SIZE ARRAY_SIZE(evergreen_reg_safe_bm)

struct evergreen_cs_track {
 u32   group_size;
 u32   nbanks;
 u32   npipes;
 u32   row_size;
 /* value we track */
 u32   nsamples;  /* unused */
 struct radeon_bo *cb_color_bo[12];
 u32   cb_color_bo_offset[12];
 struct radeon_bo *cb_color_fmask_bo[8]; /* unused */
 struct radeon_bo *cb_color_cmask_bo[8]; /* unused */
 u32   cb_color_info[12];
 u32   cb_color_view[12];
 u32   cb_color_pitch[12];
 u32   cb_color_slice[12];
 u32   cb_color_slice_idx[12];
 u32   cb_color_attrib[12];
 u32   cb_color_cmask_slice[8];/* unused */
 u32   cb_color_fmask_slice[8];/* unused */
 u32   cb_target_mask;
 u32   cb_shader_mask; /* unused */
 u32   vgt_strmout_config;
 u32   vgt_strmout_buffer_config;
 struct radeon_bo *vgt_strmout_bo[4];
 u32   vgt_strmout_bo_offset[4];
 u32   vgt_strmout_size[4];
 u32   db_depth_control;
 u32   db_depth_view;
 u32   db_depth_slice;
 u32   db_depth_size;
 u32   db_z_info;
 u32   db_z_read_offset;
 u32   db_z_write_offset;
 struct radeon_bo *db_z_read_bo;
 struct radeon_bo *db_z_write_bo;
 u32   db_s_info;
 u32   db_s_read_offset;
 u32   db_s_write_offset;
 struct radeon_bo *db_s_read_bo;
 struct radeon_bo *db_s_write_bo;
 bool   sx_misc_kill_all_prims;
 bool   cb_dirty;
 bool   db_dirty;
 bool   streamout_dirty;
 u32   htile_offset;
 u32   htile_surface;
 struct radeon_bo *htile_bo;
 unsigned long  indirect_draw_buffer_size;
 const unsigned  *reg_safe_bm;
};

static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
{
 if (tiling_flags & RADEON_TILING_MACRO)
  return ARRAY_2D_TILED_THIN1;
 else if (tiling_flags & RADEON_TILING_MICRO)
  return ARRAY_1D_TILED_THIN1;
 else
  return ARRAY_LINEAR_GENERAL;
}

static u32 evergreen_cs_get_num_banks(u32 nbanks)
{
 switch (nbanks) {
 case 2:
  return ADDR_SURF_2_BANK;
 case 4:
  return ADDR_SURF_4_BANK;
 case 8:
 default:
  return ADDR_SURF_8_BANK;
 case 16:
  return ADDR_SURF_16_BANK;
 }
}

static void evergreen_cs_track_init(struct evergreen_cs_track *track)
{
 int i;

 for (i = 0; i < 8; i++) {
  track->cb_color_fmask_bo[i] = NULL;
  track->cb_color_cmask_bo[i] = NULL;
  track->cb_color_cmask_slice[i] = 0;
  track->cb_color_fmask_slice[i] = 0;
 }

 for (i = 0; i < 12; i++) {
  track->cb_color_bo[i] = NULL;
  track->cb_color_bo_offset[i] = 0xFFFFFFFF;
  track->cb_color_info[i] = 0;
  track->cb_color_view[i] = 0xFFFFFFFF;
  track->cb_color_pitch[i] = 0;
  track->cb_color_slice[i] = 0xfffffff;
  track->cb_color_slice_idx[i] = 0;
 }
 track->cb_target_mask = 0xFFFFFFFF;
 track->cb_shader_mask = 0xFFFFFFFF;
 track->cb_dirty = true;

 track->db_depth_slice = 0xffffffff;
 track->db_depth_view = 0xFFFFC000;
 track->db_depth_size = 0xFFFFFFFF;
 track->db_depth_control = 0xFFFFFFFF;
 track->db_z_info = 0xFFFFFFFF;
 track->db_z_read_offset = 0xFFFFFFFF;
 track->db_z_write_offset = 0xFFFFFFFF;
 track->db_z_read_bo = NULL;
 track->db_z_write_bo = NULL;
 track->db_s_info = 0xFFFFFFFF;
 track->db_s_read_offset = 0xFFFFFFFF;
 track->db_s_write_offset = 0xFFFFFFFF;
 track->db_s_read_bo = NULL;
 track->db_s_write_bo = NULL;
 track->db_dirty = true;
 track->htile_bo = NULL;
 track->htile_offset = 0xFFFFFFFF;
 track->htile_surface = 0;

 for (i = 0; i < 4; i++) {
  track->vgt_strmout_size[i] = 0;
  track->vgt_strmout_bo[i] = NULL;
  track->vgt_strmout_bo_offset[i] = 0xFFFFFFFF;
 }
 track->streamout_dirty = true;
 track->sx_misc_kill_all_prims = false;
}

struct eg_surface {
 /* value gathered from cs */
 unsigned nbx;
 unsigned nby;
 unsigned format;
 unsigned mode;
 unsigned nbanks;
 unsigned bankw;
 unsigned bankh;
 unsigned tsplit;
 unsigned mtilea;
 unsigned nsamples;
 /* output value */
 unsigned bpe;
 unsigned layer_size;
 unsigned palign;
 unsigned halign;
 unsigned long base_align;
};

static int evergreen_surface_check_linear(struct radeon_cs_parser *p,
       struct eg_surface *surf,
       const char *prefix)
{
 surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples;
 surf->base_align = surf->bpe;
 surf->palign = 1;
 surf->halign = 1;
 return 0;
}

static int evergreen_surface_check_linear_aligned(struct radeon_cs_parser *p,
        struct eg_surface *surf,
        const char *prefix)
{
 struct evergreen_cs_track *track = p->track;
 unsigned palign;

 palign = MAX(64, track->group_size / surf->bpe);
 surf->layer_size = surf->nbx * surf->nby * surf->bpe * surf->nsamples;
 surf->base_align = track->group_size;
 surf->palign = palign;
 surf->halign = 1;
 if ((surf->nbx & (palign - 1)) && !(palign == 64 && surf->nbx == 32)) {
  if (prefix) {
   dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n",
     __func__, __LINE__, prefix, surf->nbx, palign);
  }
  return -EINVAL;
 }
 return 0;
}

static int evergreen_surface_check_1d(struct radeon_cs_parser *p,
          struct eg_surface *surf,
          const char *prefix)
{
 struct evergreen_cs_track *track = p->track;
 unsigned palign;

 palign = track->group_size / (8 * surf->bpe * surf->nsamples);
 palign = MAX(8, palign);
 surf->layer_size = surf->nbx * surf->nby * surf->bpe;
 surf->base_align = track->group_size;
 surf->palign = palign;
 surf->halign = 8;
 if ((surf->nbx & (palign - 1))) {
  if (prefix) {
   dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d (%d %d %d)\n",
     __func__, __LINE__, prefix, surf->nbx, palign,
     track->group_size, surf->bpe, surf->nsamples);
  }
  return -EINVAL;
 }
 if ((surf->nby & (8 - 1))) {
  if (prefix) {
   dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with 8\n",
     __func__, __LINE__, prefix, surf->nby);
  }
  return -EINVAL;
 }
 return 0;
}

static int evergreen_surface_check_2d(struct radeon_cs_parser *p,
          struct eg_surface *surf,
          const char *prefix)
{
 struct evergreen_cs_track *track = p->track;
 unsigned palign, halign, tileb, slice_pt;
 unsigned mtile_pr, mtile_ps, mtileb;

 tileb = 64 * surf->bpe * surf->nsamples;
 slice_pt = 1;
 if (tileb > surf->tsplit) {
  slice_pt = tileb / surf->tsplit;
 }
 tileb = tileb / slice_pt;
 /* macro tile width & height */
 palign = (8 * surf->bankw * track->npipes) * surf->mtilea;
 halign = (8 * surf->bankh * surf->nbanks) / surf->mtilea;
 mtileb = (palign / 8) * (halign / 8) * tileb;
 mtile_pr = surf->nbx / palign;
 mtile_ps = (mtile_pr * surf->nby) / halign;
 surf->layer_size = mtile_ps * mtileb * slice_pt;
 surf->base_align = (palign / 8) * (halign / 8) * tileb;
 surf->palign = palign;
 surf->halign = halign;

 if ((surf->nbx & (palign - 1))) {
  if (prefix) {
   dev_warn(p->dev, "%s:%d %s pitch %d invalid must be aligned with %d\n",
     __func__, __LINE__, prefix, surf->nbx, palign);
  }
  return -EINVAL;
 }
 if ((surf->nby & (halign - 1))) {
  if (prefix) {
   dev_warn(p->dev, "%s:%d %s height %d invalid must be aligned with %d\n",
     __func__, __LINE__, prefix, surf->nby, halign);
  }
  return -EINVAL;
 }

 return 0;
}

static int evergreen_surface_check(struct radeon_cs_parser *p,
       struct eg_surface *surf,
       const char *prefix)
{
 /* some common value computed here */
 surf->bpe = r600_fmt_get_blocksize(surf->format);

 switch (surf->mode) {
 case ARRAY_LINEAR_GENERAL:
  return evergreen_surface_check_linear(p, surf, prefix);
 case ARRAY_LINEAR_ALIGNED:
  return evergreen_surface_check_linear_aligned(p, surf, prefix);
 case ARRAY_1D_TILED_THIN1:
  return evergreen_surface_check_1d(p, surf, prefix);
 case ARRAY_2D_TILED_THIN1:
  return evergreen_surface_check_2d(p, surf, prefix);
 default:
  dev_warn(p->dev, "%s:%d %s invalid array mode %d\n",
    __func__, __LINE__, prefix, surf->mode);
  return -EINVAL;
 }
 return -EINVAL;
}

static int evergreen_surface_value_conv_check(struct radeon_cs_parser *p,
           struct eg_surface *surf,
           const char *prefix)
{
 switch (surf->mode) {
 case ARRAY_2D_TILED_THIN1:
  break;
 case ARRAY_LINEAR_GENERAL:
 case ARRAY_LINEAR_ALIGNED:
 case ARRAY_1D_TILED_THIN1:
  return 0;
 default:
  dev_warn(p->dev, "%s:%d %s invalid array mode %d\n",
    __func__, __LINE__, prefix, surf->mode);
  return -EINVAL;
 }

 switch (surf->nbanks) {
 case 0: surf->nbanks = 2; break;
 case 1: surf->nbanks = 4; break;
 case 2: surf->nbanks = 8; break;
 case 3: surf->nbanks = 16; break;
 default:
  dev_warn(p->dev, "%s:%d %s invalid number of banks %d\n",
    __func__, __LINE__, prefix, surf->nbanks);
  return -EINVAL;
 }
 switch (surf->bankw) {
 case 0: surf->bankw = 1; break;
 case 1: surf->bankw = 2; break;
 case 2: surf->bankw = 4; break;
 case 3: surf->bankw = 8; break;
 default:
  dev_warn(p->dev, "%s:%d %s invalid bankw %d\n",
    __func__, __LINE__, prefix, surf->bankw);
  return -EINVAL;
 }
 switch (surf->bankh) {
 case 0: surf->bankh = 1; break;
 case 1: surf->bankh = 2; break;
 case 2: surf->bankh = 4; break;
 case 3: surf->bankh = 8; break;
 default:
  dev_warn(p->dev, "%s:%d %s invalid bankh %d\n",
    __func__, __LINE__, prefix, surf->bankh);
  return -EINVAL;
 }
 switch (surf->mtilea) {
 case 0: surf->mtilea = 1; break;
 case 1: surf->mtilea = 2; break;
 case 2: surf->mtilea = 4; break;
 case 3: surf->mtilea = 8; break;
 default:
  dev_warn(p->dev, "%s:%d %s invalid macro tile aspect %d\n",
    __func__, __LINE__, prefix, surf->mtilea);
  return -EINVAL;
 }
 switch (surf->tsplit) {
 case 0: surf->tsplit = 64; break;
 case 1: surf->tsplit = 128; break;
 case 2: surf->tsplit = 256; break;
 case 3: surf->tsplit = 512; break;
 case 4: surf->tsplit = 1024; break;
 case 5: surf->tsplit = 2048; break;
 case 6: surf->tsplit = 4096; break;
 default:
  dev_warn(p->dev, "%s:%d %s invalid tile split %d\n",
    __func__, __LINE__, prefix, surf->tsplit);
  return -EINVAL;
 }
 return 0;
}

static int evergreen_cs_track_validate_cb(struct radeon_cs_parser *p, unsigned id)
{
 struct evergreen_cs_track *track = p->track;
 struct eg_surface surf;
 unsigned pitch, slice, mslice;
 u64 offset;
 int r;

 mslice = G_028C6C_SLICE_MAX(track->cb_color_view[id]) + 1;
 pitch = track->cb_color_pitch[id];
 slice = track->cb_color_slice[id];
 surf.nbx = (pitch + 1) * 8;
 surf.nby = ((slice + 1) * 64) / surf.nbx;
 surf.mode = G_028C70_ARRAY_MODE(track->cb_color_info[id]);
 surf.format = G_028C70_FORMAT(track->cb_color_info[id]);
 surf.tsplit = G_028C74_TILE_SPLIT(track->cb_color_attrib[id]);
 surf.nbanks = G_028C74_NUM_BANKS(track->cb_color_attrib[id]);
 surf.bankw = G_028C74_BANK_WIDTH(track->cb_color_attrib[id]);
 surf.bankh = G_028C74_BANK_HEIGHT(track->cb_color_attrib[id]);
 surf.mtilea = G_028C74_MACRO_TILE_ASPECT(track->cb_color_attrib[id]);
 surf.nsamples = 1;

 if (!r600_fmt_is_valid_color(surf.format)) {
  dev_warn(p->dev, "%s:%d cb invalid format %d for %d (0x%08x)\n",
    __func__, __LINE__, surf.format,
   id, track->cb_color_info[id]);
  return -EINVAL;
 }

 r = evergreen_surface_value_conv_check(p, &surf, "cb");
 if (r) {
  return r;
 }

 r = evergreen_surface_check(p, &surf, "cb");
 if (r) {
  dev_warn(p->dev, "%s:%d cb[%d] invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
    __func__, __LINE__, id, track->cb_color_pitch[id],
    track->cb_color_slice[id], track->cb_color_attrib[id],
    track->cb_color_info[id]);
  return r;
 }

 offset = (u64)track->cb_color_bo_offset[id] << 8;
 if (offset & (surf.base_align - 1)) {
  dev_warn(p->dev, "%s:%d cb[%d] bo base %llu not aligned with %ld\n",
    __func__, __LINE__, id, offset, surf.base_align);
  return -EINVAL;
 }

 offset += (u64)surf.layer_size * mslice;
 if (offset > radeon_bo_size(track->cb_color_bo[id])) {
  /* old ddx are broken they allocate bo with w*h*bpp but
   * program slice with ALIGN(h, 8), catch this and patch
   * command stream.
   */
  if (!surf.mode) {
   uint32_t *ib = p->ib.ptr;
   u64 tmp, nby, bsize, size, min = 0;

   /* find the height the ddx wants */
   if (surf.nby > 8) {
    min = surf.nby - 8;
   }
   bsize = radeon_bo_size(track->cb_color_bo[id]);
   tmp = (u64)track->cb_color_bo_offset[id] << 8;
   for (nby = surf.nby; nby > min; nby--) {
    size = nby * surf.nbx * surf.bpe * surf.nsamples;
    if ((tmp + size * mslice) <= bsize) {
     break;
    }
   }
   if (nby > min) {
    surf.nby = nby;
    slice = ((nby * surf.nbx) / 64) - 1;
    if (!evergreen_surface_check(p, &surf, "cb")) {
     /* check if this one works */
     tmp += (u64)surf.layer_size * mslice;
     if (tmp <= bsize) {
      ib[track->cb_color_slice_idx[id]] = slice;
      goto old_ddx_ok;
     }
    }
   }
  }
  dev_warn(p->dev, "%s:%d cb[%d] bo too small (layer size %d, "
    "offset %llu, max layer %d, bo size %ld, slice %d)\n",
    __func__, __LINE__, id, surf.layer_size,
   (u64)track->cb_color_bo_offset[id] << 8, mslice,
   radeon_bo_size(track->cb_color_bo[id]), slice);
  dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n",
    __func__, __LINE__, surf.nbx, surf.nby,
   surf.mode, surf.bpe, surf.nsamples,
   surf.bankw, surf.bankh,
   surf.tsplit, surf.mtilea);
  return -EINVAL;
 }
old_ddx_ok:

 return 0;
}

static int evergreen_cs_track_validate_htile(struct radeon_cs_parser *p,
      unsigned nbx, unsigned nby)
{
 struct evergreen_cs_track *track = p->track;
 unsigned long size;

 if (track->htile_bo == NULL) {
  dev_warn(p->dev, "%s:%d htile enabled without htile surface 0x%08x\n",
    __func__, __LINE__, track->db_z_info);
  return -EINVAL;
 }

 if (G_028ABC_LINEAR(track->htile_surface)) {
  /* pitch must be 16 htiles aligned == 16 * 8 pixel aligned */
  nbx = round_up(nbx, 16 * 8);
  /* height is npipes htiles aligned == npipes * 8 pixel aligned */
  nby = round_up(nby, track->npipes * 8);
 } else {
  /* always assume 8x8 htile */
  /* align is htile align * 8, htile align vary according to
   * number of pipe and tile width and nby
   */
  switch (track->npipes) {
  case 8:
   /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
   nbx = round_up(nbx, 64 * 8);
   nby = round_up(nby, 64 * 8);
   break;
  case 4:
   /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
   nbx = round_up(nbx, 64 * 8);
   nby = round_up(nby, 32 * 8);
   break;
  case 2:
   /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
   nbx = round_up(nbx, 32 * 8);
   nby = round_up(nby, 32 * 8);
   break;
  case 1:
   /* HTILE_WIDTH = 8 & HTILE_HEIGHT = 8*/
   nbx = round_up(nbx, 32 * 8);
   nby = round_up(nby, 16 * 8);
   break;
  default:
   dev_warn(p->dev, "%s:%d invalid num pipes %d\n",
     __func__, __LINE__, track->npipes);
   return -EINVAL;
  }
 }
 /* compute number of htile */
 nbx = nbx >> 3;
 nby = nby >> 3;
 /* size must be aligned on npipes * 2K boundary */
 size = roundup(nbx * nby * 4, track->npipes * (2 << 10));
 size += track->htile_offset;

 if (size > radeon_bo_size(track->htile_bo)) {
  dev_warn(p->dev, "%s:%d htile surface too small %ld for %ld (%d %d)\n",
    __func__, __LINE__, radeon_bo_size(track->htile_bo),
    size, nbx, nby);
  return -EINVAL;
 }
 return 0;
}

static int evergreen_cs_track_validate_stencil(struct radeon_cs_parser *p)
{
 struct evergreen_cs_track *track = p->track;
 struct eg_surface surf;
 unsigned pitch, slice, mslice;
 u64 offset;
 int r;

 mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1;
 pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size);
 slice = track->db_depth_slice;
 surf.nbx = (pitch + 1) * 8;
 surf.nby = ((slice + 1) * 64) / surf.nbx;
 surf.mode = G_028040_ARRAY_MODE(track->db_z_info);
 surf.format = G_028044_FORMAT(track->db_s_info);
 surf.tsplit = G_028044_TILE_SPLIT(track->db_s_info);
 surf.nbanks = G_028040_NUM_BANKS(track->db_z_info);
 surf.bankw = G_028040_BANK_WIDTH(track->db_z_info);
 surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info);
 surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info);
 surf.nsamples = 1;

 if (surf.format != 1) {
  dev_warn(p->dev, "%s:%d stencil invalid format %d\n",
    __func__, __LINE__, surf.format);
  return -EINVAL;
 }
 /* replace by color format so we can use same code */
 surf.format = V_028C70_COLOR_8;

 r = evergreen_surface_value_conv_check(p, &surf, "stencil");
 if (r) {
  return r;
 }

 r = evergreen_surface_check(p, &surf, NULL);
 if (r) {
  /* old userspace doesn't compute proper depth/stencil alignment
   * check that alignment against a bigger byte per elements and
   * only report if that alignment is wrong too.
   */
  surf.format = V_028C70_COLOR_8_8_8_8;
  r = evergreen_surface_check(p, &surf, "stencil");
  if (r) {
   dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
     __func__, __LINE__, track->db_depth_size,
     track->db_depth_slice, track->db_s_info, track->db_z_info);
  }
  return r;
 }

 offset = (u64)track->db_s_read_offset << 8;
 if (offset & (surf.base_align - 1)) {
  dev_warn(p->dev, "%s:%d stencil read bo base %llu not aligned with %ld\n",
    __func__, __LINE__, offset, surf.base_align);
  return -EINVAL;
 }
 offset += (u64)surf.layer_size * mslice;
 if (offset > radeon_bo_size(track->db_s_read_bo)) {
  dev_warn(p->dev, "%s:%d stencil read bo too small (layer size %d, "
    "offset %llu, max layer %d, bo size %ld)\n",
    __func__, __LINE__, surf.layer_size,
   (u64)track->db_s_read_offset << 8, mslice,
   radeon_bo_size(track->db_s_read_bo));
  dev_warn(p->dev, "%s:%d stencil invalid (0x%08x 0x%08x 0x%08x 0x%08x)\n",
    __func__, __LINE__, track->db_depth_size,
    track->db_depth_slice, track->db_s_info, track->db_z_info);
  return -EINVAL;
 }

 offset = (u64)track->db_s_write_offset << 8;
 if (offset & (surf.base_align - 1)) {
  dev_warn(p->dev, "%s:%d stencil write bo base %llu not aligned with %ld\n",
    __func__, __LINE__, offset, surf.base_align);
  return -EINVAL;
 }
 offset += (u64)surf.layer_size * mslice;
 if (offset > radeon_bo_size(track->db_s_write_bo)) {
  dev_warn(p->dev, "%s:%d stencil write bo too small (layer size %d, "
    "offset %llu, max layer %d, bo size %ld)\n",
    __func__, __LINE__, surf.layer_size,
   (u64)track->db_s_write_offset << 8, mslice,
   radeon_bo_size(track->db_s_write_bo));
  return -EINVAL;
 }

 /* hyperz */
 if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
  r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
  if (r) {
   return r;
  }
 }

 return 0;
}

static int evergreen_cs_track_validate_depth(struct radeon_cs_parser *p)
{
 struct evergreen_cs_track *track = p->track;
 struct eg_surface surf;
 unsigned pitch, slice, mslice;
 u64 offset;
 int r;

 mslice = G_028008_SLICE_MAX(track->db_depth_view) + 1;
 pitch = G_028058_PITCH_TILE_MAX(track->db_depth_size);
 slice = track->db_depth_slice;
 surf.nbx = (pitch + 1) * 8;
 surf.nby = ((slice + 1) * 64) / surf.nbx;
 surf.mode = G_028040_ARRAY_MODE(track->db_z_info);
 surf.format = G_028040_FORMAT(track->db_z_info);
 surf.tsplit = G_028040_TILE_SPLIT(track->db_z_info);
 surf.nbanks = G_028040_NUM_BANKS(track->db_z_info);
 surf.bankw = G_028040_BANK_WIDTH(track->db_z_info);
 surf.bankh = G_028040_BANK_HEIGHT(track->db_z_info);
 surf.mtilea = G_028040_MACRO_TILE_ASPECT(track->db_z_info);
 surf.nsamples = 1;

 switch (surf.format) {
 case V_028040_Z_16:
  surf.format = V_028C70_COLOR_16;
  break;
 case V_028040_Z_24:
 case V_028040_Z_32_FLOAT:
  surf.format = V_028C70_COLOR_8_8_8_8;
  break;
 default:
  dev_warn(p->dev, "%s:%d depth invalid format %d\n",
    __func__, __LINE__, surf.format);
  return -EINVAL;
 }

 r = evergreen_surface_value_conv_check(p, &surf, "depth");
 if (r) {
  dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n",
    __func__, __LINE__, track->db_depth_size,
    track->db_depth_slice, track->db_z_info);
  return r;
 }

 r = evergreen_surface_check(p, &surf, "depth");
 if (r) {
  dev_warn(p->dev, "%s:%d depth invalid (0x%08x 0x%08x 0x%08x)\n",
    __func__, __LINE__, track->db_depth_size,
    track->db_depth_slice, track->db_z_info);
  return r;
 }

 offset = (u64)track->db_z_read_offset << 8;
 if (offset & (surf.base_align - 1)) {
  dev_warn(p->dev, "%s:%d stencil read bo base %llu not aligned with %ld\n",
    __func__, __LINE__, offset, surf.base_align);
  return -EINVAL;
 }
 offset += (u64)surf.layer_size * mslice;
 if (offset > radeon_bo_size(track->db_z_read_bo)) {
  dev_warn(p->dev, "%s:%d depth read bo too small (layer size %d, "
    "offset %llu, max layer %d, bo size %ld)\n",
    __func__, __LINE__, surf.layer_size,
   (u64)track->db_z_read_offset << 8, mslice,
   radeon_bo_size(track->db_z_read_bo));
  return -EINVAL;
 }

 offset = (u64)track->db_z_write_offset << 8;
 if (offset & (surf.base_align - 1)) {
  dev_warn(p->dev, "%s:%d stencil write bo base %llu not aligned with %ld\n",
    __func__, __LINE__, offset, surf.base_align);
  return -EINVAL;
 }
 offset += (u64)surf.layer_size * mslice;
 if (offset > radeon_bo_size(track->db_z_write_bo)) {
  dev_warn(p->dev, "%s:%d depth write bo too small (layer size %d, "
    "offset %llu, max layer %d, bo size %ld)\n",
    __func__, __LINE__, surf.layer_size,
   (u64)track->db_z_write_offset << 8, mslice,
   radeon_bo_size(track->db_z_write_bo));
  return -EINVAL;
 }

 /* hyperz */
 if (G_028040_TILE_SURFACE_ENABLE(track->db_z_info)) {
  r = evergreen_cs_track_validate_htile(p, surf.nbx, surf.nby);
  if (r) {
   return r;
  }
 }

 return 0;
}

static int evergreen_cs_track_validate_texture(struct radeon_cs_parser *p,
            struct radeon_bo *texture,
            struct radeon_bo *mipmap,
            unsigned idx)
{
 struct eg_surface surf;
 unsigned long toffset, moffset;
 unsigned dim, llevel, mslice, width, height, depth, i;
 u32 texdw[8];
 int r;

 texdw[0] = radeon_get_ib_value(p, idx + 0);
 texdw[1] = radeon_get_ib_value(p, idx + 1);
 texdw[2] = radeon_get_ib_value(p, idx + 2);
 texdw[3] = radeon_get_ib_value(p, idx + 3);
 texdw[4] = radeon_get_ib_value(p, idx + 4);
 texdw[5] = radeon_get_ib_value(p, idx + 5);
 texdw[6] = radeon_get_ib_value(p, idx + 6);
 texdw[7] = radeon_get_ib_value(p, idx + 7);
 dim = G_030000_DIM(texdw[0]);
 llevel = G_030014_LAST_LEVEL(texdw[5]);
 mslice = G_030014_LAST_ARRAY(texdw[5]) + 1;
 width = G_030000_TEX_WIDTH(texdw[0]) + 1;
 height =  G_030004_TEX_HEIGHT(texdw[1]) + 1;
 depth = G_030004_TEX_DEPTH(texdw[1]) + 1;
 surf.format = G_03001C_DATA_FORMAT(texdw[7]);
 surf.nbx = (G_030000_PITCH(texdw[0]) + 1) * 8;
 surf.nbx = r600_fmt_get_nblocksx(surf.format, surf.nbx);
 surf.nby = r600_fmt_get_nblocksy(surf.format, height);
 surf.mode = G_030004_ARRAY_MODE(texdw[1]);
 surf.tsplit = G_030018_TILE_SPLIT(texdw[6]);
 surf.nbanks = G_03001C_NUM_BANKS(texdw[7]);
 surf.bankw = G_03001C_BANK_WIDTH(texdw[7]);
 surf.bankh = G_03001C_BANK_HEIGHT(texdw[7]);
 surf.mtilea = G_03001C_MACRO_TILE_ASPECT(texdw[7]);
 surf.nsamples = 1;
 toffset = texdw[2] << 8;
 moffset = texdw[3] << 8;

 if (!r600_fmt_is_valid_texture(surf.format, p->family)) {
  dev_warn(p->dev, "%s:%d texture invalid format %d\n",
    __func__, __LINE__, surf.format);
  return -EINVAL;
 }
 switch (dim) {
 case V_030000_SQ_TEX_DIM_1D:
 case V_030000_SQ_TEX_DIM_2D:
 case V_030000_SQ_TEX_DIM_CUBEMAP:
 case V_030000_SQ_TEX_DIM_1D_ARRAY:
 case V_030000_SQ_TEX_DIM_2D_ARRAY:
  depth = 1;
  break;
 case V_030000_SQ_TEX_DIM_2D_MSAA:
 case V_030000_SQ_TEX_DIM_2D_ARRAY_MSAA:
  surf.nsamples = 1 << llevel;
  llevel = 0;
  depth = 1;
  break;
 case V_030000_SQ_TEX_DIM_3D:
  break;
 default:
  dev_warn(p->dev, "%s:%d texture invalid dimension %d\n",
    __func__, __LINE__, dim);
  return -EINVAL;
 }

 r = evergreen_surface_value_conv_check(p, &surf, "texture");
 if (r) {
  return r;
 }

 /* align height */
 evergreen_surface_check(p, &surf, NULL);
 surf.nby = ALIGN(surf.nby, surf.halign);

 r = evergreen_surface_check(p, &surf, "texture");
 if (r) {
  dev_warn(p->dev, "%s:%d texture invalid 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n",
    __func__, __LINE__, texdw[0], texdw[1], texdw[4],
    texdw[5], texdw[6], texdw[7]);
  return r;
 }

 /* check texture size */
 if (toffset & (surf.base_align - 1)) {
  dev_warn(p->dev, "%s:%d texture bo base %ld not aligned with %ld\n",
    __func__, __LINE__, toffset, surf.base_align);
  return -EINVAL;
 }
 if (surf.nsamples <= 1 && moffset & (surf.base_align - 1)) {
  dev_warn(p->dev, "%s:%d mipmap bo base %ld not aligned with %ld\n",
    __func__, __LINE__, moffset, surf.base_align);
  return -EINVAL;
 }
 if (dim == SQ_TEX_DIM_3D) {
  toffset += surf.layer_size * depth;
 } else {
  toffset += surf.layer_size * mslice;
 }
 if (toffset > radeon_bo_size(texture)) {
  dev_warn(p->dev, "%s:%d texture bo too small (layer size %d, "
    "offset %ld, max layer %d, depth %d, bo size %ld) (%d %d)\n",
    __func__, __LINE__, surf.layer_size,
   (unsigned long)texdw[2] << 8, mslice,
   depth, radeon_bo_size(texture),
   surf.nbx, surf.nby);
  return -EINVAL;
 }

 if (!mipmap) {
  if (llevel) {
   dev_warn(p->dev, "%s:%i got NULL MIP_ADDRESS relocation\n",
     __func__, __LINE__);
   return -EINVAL;
  } else {
   return 0; /* everything's ok */
  }
 }

 /* check mipmap size */
 for (i = 1; i <= llevel; i++) {
  unsigned w, h, d;

  w = r600_mip_minify(width, i);
  h = r600_mip_minify(height, i);
  d = r600_mip_minify(depth, i);
  surf.nbx = r600_fmt_get_nblocksx(surf.format, w);
  surf.nby = r600_fmt_get_nblocksy(surf.format, h);

  switch (surf.mode) {
  case ARRAY_2D_TILED_THIN1:
   if (surf.nbx < surf.palign || surf.nby < surf.halign) {
    surf.mode = ARRAY_1D_TILED_THIN1;
   }
   /* recompute alignment */
   evergreen_surface_check(p, &surf, NULL);
   break;
  case ARRAY_LINEAR_GENERAL:
  case ARRAY_LINEAR_ALIGNED:
  case ARRAY_1D_TILED_THIN1:
   break;
  default:
   dev_warn(p->dev, "%s:%d invalid array mode %d\n",
     __func__, __LINE__, surf.mode);
   return -EINVAL;
  }
  surf.nbx = ALIGN(surf.nbx, surf.palign);
  surf.nby = ALIGN(surf.nby, surf.halign);

  r = evergreen_surface_check(p, &surf, "mipmap");
  if (r) {
   return r;
  }

  if (dim == SQ_TEX_DIM_3D) {
   moffset += surf.layer_size * d;
  } else {
   moffset += surf.layer_size * mslice;
  }
  if (moffset > radeon_bo_size(mipmap)) {
   dev_warn(p->dev, "%s:%d mipmap [%d] bo too small (layer size %d, "
     "offset %ld, coffset %ld, max layer %d, depth %d, "
     "bo size %ld) level0 (%d %d %d)\n",
     __func__, __LINE__, i, surf.layer_size,
     (unsigned long)texdw[3] << 8, moffset, mslice,
     d, radeon_bo_size(mipmap),
     width, height, depth);
   dev_warn(p->dev, "%s:%d problematic surf: (%d %d) (%d %d %d %d %d %d %d)\n",
     __func__, __LINE__, surf.nbx, surf.nby,
    surf.mode, surf.bpe, surf.nsamples,
    surf.bankw, surf.bankh,
    surf.tsplit, surf.mtilea);
   return -EINVAL;
  }
 }

 return 0;
}

static int evergreen_cs_track_check(struct radeon_cs_parser *p)
{
 struct evergreen_cs_track *track = p->track;
 unsigned tmp, i;
 int r;
 unsigned buffer_mask = 0;

 /* check streamout */
 if (track->streamout_dirty && track->vgt_strmout_config) {
  for (i = 0; i < 4; i++) {
   if (track->vgt_strmout_config & (1 << i)) {
    buffer_mask |= (track->vgt_strmout_buffer_config >> (i * 4)) & 0xf;
   }
  }

  for (i = 0; i < 4; i++) {
   if (buffer_mask & (1 << i)) {
    if (track->vgt_strmout_bo[i]) {
     u64 offset = (u64)track->vgt_strmout_bo_offset[i] +
       (u64)track->vgt_strmout_size[i];
     if (offset > radeon_bo_size(track->vgt_strmout_bo[i])) {
      DRM_ERROR("streamout %d bo too small: 0x%llx, 0x%lx\n",
         i, offset,
         radeon_bo_size(track->vgt_strmout_bo[i]));
      return -EINVAL;
     }
    } else {
     dev_warn(p->dev, "No buffer for streamout %d\n", i);
     return -EINVAL;
    }
   }
  }
  track->streamout_dirty = false;
 }

 if (track->sx_misc_kill_all_prims)
  return 0;

 /* check that we have a cb for each enabled target
  */
 if (track->cb_dirty) {
  tmp = track->cb_target_mask;
  for (i = 0; i < 8; i++) {
   u32 format = G_028C70_FORMAT(track->cb_color_info[i]);

   if (format != V_028C70_COLOR_INVALID &&
       (tmp >> (i * 4)) & 0xF) {
    /* at least one component is enabled */
    if (track->cb_color_bo[i] == NULL) {
     dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
      __func__, __LINE__, track->cb_target_mask, track->cb_shader_mask, i);
     return -EINVAL;
    }
    /* check cb */
    r = evergreen_cs_track_validate_cb(p, i);
    if (r) {
     return r;
    }
   }
  }
  track->cb_dirty = false;
 }

 if (track->db_dirty) {
  /* Check stencil buffer */
  if (G_028044_FORMAT(track->db_s_info) != V_028044_STENCIL_INVALID &&
      G_028800_STENCIL_ENABLE(track->db_depth_control)) {
   r = evergreen_cs_track_validate_stencil(p);
   if (r)
    return r;
  }
  /* Check depth buffer */
  if (G_028040_FORMAT(track->db_z_info) != V_028040_Z_INVALID &&
      G_028800_Z_ENABLE(track->db_depth_control)) {
   r = evergreen_cs_track_validate_depth(p);
   if (r)
    return r;
  }
  track->db_dirty = false;
 }

 return 0;
}

/**
 * evergreen_cs_packet_parse_vline() - parse userspace VLINE packet
 * @p:  parser structure holding parsing context.
 *
 * This is an Evergreen(+)-specific function for parsing VLINE packets.
 * Real work is done by r600_cs_common_vline_parse function.
 * Here we just set up ASIC-specific register table and call
 * the common implementation function.
 */
static int evergreen_cs_packet_parse_vline(struct radeon_cs_parser *p)
{

 static uint32_t vline_start_end[6] = {
  EVERGREEN_VLINE_START_END + EVERGREEN_CRTC0_REGISTER_OFFSET,
  EVERGREEN_VLINE_START_END + EVERGREEN_CRTC1_REGISTER_OFFSET,
  EVERGREEN_VLINE_START_END + EVERGREEN_CRTC2_REGISTER_OFFSET,
  EVERGREEN_VLINE_START_END + EVERGREEN_CRTC3_REGISTER_OFFSET,
  EVERGREEN_VLINE_START_END + EVERGREEN_CRTC4_REGISTER_OFFSET,
  EVERGREEN_VLINE_START_END + EVERGREEN_CRTC5_REGISTER_OFFSET
 };
 static uint32_t vline_status[6] = {
  EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC0_REGISTER_OFFSET,
  EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC1_REGISTER_OFFSET,
  EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC2_REGISTER_OFFSET,
  EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC3_REGISTER_OFFSET,
  EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC4_REGISTER_OFFSET,
  EVERGREEN_VLINE_STATUS + EVERGREEN_CRTC5_REGISTER_OFFSET
 };

 return r600_cs_common_vline_parse(p, vline_start_end, vline_status);
}

static int evergreen_packet0_check(struct radeon_cs_parser *p,
       struct radeon_cs_packet *pkt,
       unsigned idx, unsigned reg)
{
 int r;

 switch (reg) {
 case EVERGREEN_VLINE_START_END:
  r = evergreen_cs_packet_parse_vline(p);
  if (r) {
   DRM_ERROR("No reloc for ib[%d]=0x%04X\n",
     idx, reg);
   return r;
  }
  break;
 default:
  pr_err("Forbidden register 0x%04X in cs at %d\n", reg, idx);
  return -EINVAL;
 }
 return 0;
}

static int evergreen_cs_parse_packet0(struct radeon_cs_parser *p,
          struct radeon_cs_packet *pkt)
{
 unsigned reg, i;
 unsigned idx;
 int r;

 idx = pkt->idx + 1;
 reg = pkt->reg;
 for (i = 0; i <= pkt->count; i++, idx++, reg += 4) {
  r = evergreen_packet0_check(p, pkt, idx, reg);
  if (r) {
   return r;
  }
 }
 return 0;
}

/**
 * evergreen_cs_handle_reg() - process registers that need special handling.
 * @p: parser structure holding parsing context
 * @reg: register we are testing
 * @idx: index into the cs buffer
 */
static int evergreen_cs_handle_reg(struct radeon_cs_parser *p, u32 reg, u32 idx)
{
 struct evergreen_cs_track *track = (struct evergreen_cs_track *)p->track;
 struct radeon_bo_list *reloc;
 u32 tmp, *ib;
 int r;

 ib = p->ib.ptr;
 switch (reg) {
 /* force following reg to 0 in an attempt to disable out buffer
  * which will need us to better understand how it works to perform
  * security check on it (Jerome)
  */
 case SQ_ESGS_RING_SIZE:
 case SQ_GSVS_RING_SIZE:
 case SQ_ESTMP_RING_SIZE:
 case SQ_GSTMP_RING_SIZE:
 case SQ_HSTMP_RING_SIZE:
 case SQ_LSTMP_RING_SIZE:
 case SQ_PSTMP_RING_SIZE:
 case SQ_VSTMP_RING_SIZE:
 case SQ_ESGS_RING_ITEMSIZE:
 case SQ_ESTMP_RING_ITEMSIZE:
 case SQ_GSTMP_RING_ITEMSIZE:
 case SQ_GSVS_RING_ITEMSIZE:
 case SQ_GS_VERT_ITEMSIZE:
 case SQ_GS_VERT_ITEMSIZE_1:
 case SQ_GS_VERT_ITEMSIZE_2:
 case SQ_GS_VERT_ITEMSIZE_3:
 case SQ_GSVS_RING_OFFSET_1:
 case SQ_GSVS_RING_OFFSET_2:
 case SQ_GSVS_RING_OFFSET_3:
 case SQ_HSTMP_RING_ITEMSIZE:
 case SQ_LSTMP_RING_ITEMSIZE:
 case SQ_PSTMP_RING_ITEMSIZE:
 case SQ_VSTMP_RING_ITEMSIZE:
 case VGT_TF_RING_SIZE:
  /* get value to populate the IB don't remove */
  /*tmp =radeon_get_ib_value(p, idx);
    ib[idx] = 0;*/
  break;
 case SQ_ESGS_RING_BASE:
 case SQ_GSVS_RING_BASE:
 case SQ_ESTMP_RING_BASE:
 case SQ_GSTMP_RING_BASE:
 case SQ_HSTMP_RING_BASE:
 case SQ_LSTMP_RING_BASE:
 case SQ_PSTMP_RING_BASE:
 case SQ_VSTMP_RING_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  break;
 case DB_DEPTH_CONTROL:
  track->db_depth_control = radeon_get_ib_value(p, idx);
  track->db_dirty = true;
  break;
 case CAYMAN_DB_EQAA:
  if (p->rdev->family < CHIP_CAYMAN) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  break;
 case CAYMAN_DB_DEPTH_INFO:
  if (p->rdev->family < CHIP_CAYMAN) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  break;
 case DB_Z_INFO:
  track->db_z_info = radeon_get_ib_value(p, idx);
  if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
   r = radeon_cs_packet_next_reloc(p, &reloc, 0);
   if (r) {
    dev_warn(p->dev, "bad SET_CONTEXT_REG "
      "0x%04X\n", reg);
    return -EINVAL;
   }
   ib[idx] &= ~Z_ARRAY_MODE(0xf);
   track->db_z_info &= ~Z_ARRAY_MODE(0xf);
   ib[idx] |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
   track->db_z_info |= Z_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
   if (reloc->tiling_flags & RADEON_TILING_MACRO) {
    unsigned bankw, bankh, mtaspect, tile_split;

    evergreen_tiling_fields(reloc->tiling_flags,
       &bankw, &bankh, &mtaspect,
       &tile_split);
    ib[idx] |= DB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
    ib[idx] |= DB_TILE_SPLIT(tile_split) |
      DB_BANK_WIDTH(bankw) |
      DB_BANK_HEIGHT(bankh) |
      DB_MACRO_TILE_ASPECT(mtaspect);
   }
  }
  track->db_dirty = true;
  break;
 case DB_STENCIL_INFO:
  track->db_s_info = radeon_get_ib_value(p, idx);
  track->db_dirty = true;
  break;
 case DB_DEPTH_VIEW:
  track->db_depth_view = radeon_get_ib_value(p, idx);
  track->db_dirty = true;
  break;
 case DB_DEPTH_SIZE:
  track->db_depth_size = radeon_get_ib_value(p, idx);
  track->db_dirty = true;
  break;
 case R_02805C_DB_DEPTH_SLICE:
  track->db_depth_slice = radeon_get_ib_value(p, idx);
  track->db_dirty = true;
  break;
 case DB_Z_READ_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  track->db_z_read_offset = radeon_get_ib_value(p, idx);
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->db_z_read_bo = reloc->robj;
  track->db_dirty = true;
  break;
 case DB_Z_WRITE_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  track->db_z_write_offset = radeon_get_ib_value(p, idx);
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->db_z_write_bo = reloc->robj;
  track->db_dirty = true;
  break;
 case DB_STENCIL_READ_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  track->db_s_read_offset = radeon_get_ib_value(p, idx);
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->db_s_read_bo = reloc->robj;
  track->db_dirty = true;
  break;
 case DB_STENCIL_WRITE_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  track->db_s_write_offset = radeon_get_ib_value(p, idx);
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->db_s_write_bo = reloc->robj;
  track->db_dirty = true;
  break;
 case VGT_STRMOUT_CONFIG:
  track->vgt_strmout_config = radeon_get_ib_value(p, idx);
  track->streamout_dirty = true;
  break;
 case VGT_STRMOUT_BUFFER_CONFIG:
  track->vgt_strmout_buffer_config = radeon_get_ib_value(p, idx);
  track->streamout_dirty = true;
  break;
 case VGT_STRMOUT_BUFFER_BASE_0:
 case VGT_STRMOUT_BUFFER_BASE_1:
 case VGT_STRMOUT_BUFFER_BASE_2:
 case VGT_STRMOUT_BUFFER_BASE_3:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  tmp = (reg - VGT_STRMOUT_BUFFER_BASE_0) / 16;
  track->vgt_strmout_bo_offset[tmp] = radeon_get_ib_value(p, idx) << 8;
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->vgt_strmout_bo[tmp] = reloc->robj;
  track->streamout_dirty = true;
  break;
 case VGT_STRMOUT_BUFFER_SIZE_0:
 case VGT_STRMOUT_BUFFER_SIZE_1:
 case VGT_STRMOUT_BUFFER_SIZE_2:
 case VGT_STRMOUT_BUFFER_SIZE_3:
  tmp = (reg - VGT_STRMOUT_BUFFER_SIZE_0) / 16;
  /* size in register is DWs, convert to bytes */
  track->vgt_strmout_size[tmp] = radeon_get_ib_value(p, idx) * 4;
  track->streamout_dirty = true;
  break;
 case CP_COHER_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "missing reloc for CP_COHER_BASE "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  break;
 case CB_TARGET_MASK:
  track->cb_target_mask = radeon_get_ib_value(p, idx);
  track->cb_dirty = true;
  break;
 case CB_SHADER_MASK:
  track->cb_shader_mask = radeon_get_ib_value(p, idx);
  track->cb_dirty = true;
  break;
 case PA_SC_AA_CONFIG:
  if (p->rdev->family >= CHIP_CAYMAN) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  tmp = radeon_get_ib_value(p, idx) & MSAA_NUM_SAMPLES_MASK;
  track->nsamples = 1 << tmp;
  break;
 case CAYMAN_PA_SC_AA_CONFIG:
  if (p->rdev->family < CHIP_CAYMAN) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  tmp = radeon_get_ib_value(p, idx) & CAYMAN_MSAA_NUM_SAMPLES_MASK;
  track->nsamples = 1 << tmp;
  break;
 case CB_COLOR0_VIEW:
 case CB_COLOR1_VIEW:
 case CB_COLOR2_VIEW:
 case CB_COLOR3_VIEW:
 case CB_COLOR4_VIEW:
 case CB_COLOR5_VIEW:
 case CB_COLOR6_VIEW:
 case CB_COLOR7_VIEW:
  tmp = (reg - CB_COLOR0_VIEW) / 0x3c;
  track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
  track->cb_dirty = true;
  break;
 case CB_COLOR8_VIEW:
 case CB_COLOR9_VIEW:
 case CB_COLOR10_VIEW:
 case CB_COLOR11_VIEW:
  tmp = ((reg - CB_COLOR8_VIEW) / 0x1c) + 8;
  track->cb_color_view[tmp] = radeon_get_ib_value(p, idx);
  track->cb_dirty = true;
  break;
 case CB_COLOR0_INFO:
 case CB_COLOR1_INFO:
 case CB_COLOR2_INFO:
 case CB_COLOR3_INFO:
 case CB_COLOR4_INFO:
 case CB_COLOR5_INFO:
 case CB_COLOR6_INFO:
 case CB_COLOR7_INFO:
  tmp = (reg - CB_COLOR0_INFO) / 0x3c;
  track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
  if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
   r = radeon_cs_packet_next_reloc(p, &reloc, 0);
   if (r) {
    dev_warn(p->dev, "bad SET_CONTEXT_REG "
      "0x%04X\n", reg);
    return -EINVAL;
   }
   ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
   track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
  }
  track->cb_dirty = true;
  break;
 case CB_COLOR8_INFO:
 case CB_COLOR9_INFO:
 case CB_COLOR10_INFO:
 case CB_COLOR11_INFO:
  tmp = ((reg - CB_COLOR8_INFO) / 0x1c) + 8;
  track->cb_color_info[tmp] = radeon_get_ib_value(p, idx);
  if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
   r = radeon_cs_packet_next_reloc(p, &reloc, 0);
   if (r) {
    dev_warn(p->dev, "bad SET_CONTEXT_REG "
      "0x%04X\n", reg);
    return -EINVAL;
   }
   ib[idx] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
   track->cb_color_info[tmp] |= CB_ARRAY_MODE(evergreen_cs_get_aray_mode(reloc->tiling_flags));
  }
  track->cb_dirty = true;
  break;
 case CB_COLOR0_PITCH:
 case CB_COLOR1_PITCH:
 case CB_COLOR2_PITCH:
 case CB_COLOR3_PITCH:
 case CB_COLOR4_PITCH:
 case CB_COLOR5_PITCH:
 case CB_COLOR6_PITCH:
 case CB_COLOR7_PITCH:
  tmp = (reg - CB_COLOR0_PITCH) / 0x3c;
  track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);
  track->cb_dirty = true;
  break;
 case CB_COLOR8_PITCH:
 case CB_COLOR9_PITCH:
 case CB_COLOR10_PITCH:
 case CB_COLOR11_PITCH:
  tmp = ((reg - CB_COLOR8_PITCH) / 0x1c) + 8;
  track->cb_color_pitch[tmp] = radeon_get_ib_value(p, idx);
  track->cb_dirty = true;
  break;
 case CB_COLOR0_SLICE:
 case CB_COLOR1_SLICE:
 case CB_COLOR2_SLICE:
 case CB_COLOR3_SLICE:
 case CB_COLOR4_SLICE:
 case CB_COLOR5_SLICE:
 case CB_COLOR6_SLICE:
 case CB_COLOR7_SLICE:
  tmp = (reg - CB_COLOR0_SLICE) / 0x3c;
  track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx);
  track->cb_color_slice_idx[tmp] = idx;
  track->cb_dirty = true;
  break;
 case CB_COLOR8_SLICE:
 case CB_COLOR9_SLICE:
 case CB_COLOR10_SLICE:
 case CB_COLOR11_SLICE:
  tmp = ((reg - CB_COLOR8_SLICE) / 0x1c) + 8;
  track->cb_color_slice[tmp] = radeon_get_ib_value(p, idx);
  track->cb_color_slice_idx[tmp] = idx;
  track->cb_dirty = true;
  break;
 case CB_COLOR0_ATTRIB:
 case CB_COLOR1_ATTRIB:
 case CB_COLOR2_ATTRIB:
 case CB_COLOR3_ATTRIB:
 case CB_COLOR4_ATTRIB:
 case CB_COLOR5_ATTRIB:
 case CB_COLOR6_ATTRIB:
 case CB_COLOR7_ATTRIB:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
   if (reloc->tiling_flags & RADEON_TILING_MACRO) {
    unsigned bankw, bankh, mtaspect, tile_split;

    evergreen_tiling_fields(reloc->tiling_flags,
       &bankw, &bankh, &mtaspect,
       &tile_split);
    ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
    ib[idx] |= CB_TILE_SPLIT(tile_split) |
        CB_BANK_WIDTH(bankw) |
        CB_BANK_HEIGHT(bankh) |
        CB_MACRO_TILE_ASPECT(mtaspect);
   }
  }
  tmp = ((reg - CB_COLOR0_ATTRIB) / 0x3c);
  track->cb_color_attrib[tmp] = ib[idx];
  track->cb_dirty = true;
  break;
 case CB_COLOR8_ATTRIB:
 case CB_COLOR9_ATTRIB:
 case CB_COLOR10_ATTRIB:
 case CB_COLOR11_ATTRIB:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  if (!(p->cs_flags & RADEON_CS_KEEP_TILING_FLAGS)) {
   if (reloc->tiling_flags & RADEON_TILING_MACRO) {
    unsigned bankw, bankh, mtaspect, tile_split;

    evergreen_tiling_fields(reloc->tiling_flags,
       &bankw, &bankh, &mtaspect,
       &tile_split);
    ib[idx] |= CB_NUM_BANKS(evergreen_cs_get_num_banks(track->nbanks));
    ib[idx] |= CB_TILE_SPLIT(tile_split) |
        CB_BANK_WIDTH(bankw) |
        CB_BANK_HEIGHT(bankh) |
        CB_MACRO_TILE_ASPECT(mtaspect);
   }
  }
  tmp = ((reg - CB_COLOR8_ATTRIB) / 0x1c) + 8;
  track->cb_color_attrib[tmp] = ib[idx];
  track->cb_dirty = true;
  break;
 case CB_COLOR0_FMASK:
 case CB_COLOR1_FMASK:
 case CB_COLOR2_FMASK:
 case CB_COLOR3_FMASK:
 case CB_COLOR4_FMASK:
 case CB_COLOR5_FMASK:
 case CB_COLOR6_FMASK:
 case CB_COLOR7_FMASK:
  tmp = (reg - CB_COLOR0_FMASK) / 0x3c;
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
   return -EINVAL;
  }
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->cb_color_fmask_bo[tmp] = reloc->robj;
  break;
 case CB_COLOR0_CMASK:
 case CB_COLOR1_CMASK:
 case CB_COLOR2_CMASK:
 case CB_COLOR3_CMASK:
 case CB_COLOR4_CMASK:
 case CB_COLOR5_CMASK:
 case CB_COLOR6_CMASK:
 case CB_COLOR7_CMASK:
  tmp = (reg - CB_COLOR0_CMASK) / 0x3c;
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_err(p->dev, "bad SET_CONTEXT_REG 0x%04X\n", reg);
   return -EINVAL;
  }
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->cb_color_cmask_bo[tmp] = reloc->robj;
  break;
 case CB_COLOR0_FMASK_SLICE:
 case CB_COLOR1_FMASK_SLICE:
 case CB_COLOR2_FMASK_SLICE:
 case CB_COLOR3_FMASK_SLICE:
 case CB_COLOR4_FMASK_SLICE:
 case CB_COLOR5_FMASK_SLICE:
 case CB_COLOR6_FMASK_SLICE:
 case CB_COLOR7_FMASK_SLICE:
  tmp = (reg - CB_COLOR0_FMASK_SLICE) / 0x3c;
  track->cb_color_fmask_slice[tmp] = radeon_get_ib_value(p, idx);
  break;
 case CB_COLOR0_CMASK_SLICE:
 case CB_COLOR1_CMASK_SLICE:
 case CB_COLOR2_CMASK_SLICE:
 case CB_COLOR3_CMASK_SLICE:
 case CB_COLOR4_CMASK_SLICE:
 case CB_COLOR5_CMASK_SLICE:
 case CB_COLOR6_CMASK_SLICE:
 case CB_COLOR7_CMASK_SLICE:
  tmp = (reg - CB_COLOR0_CMASK_SLICE) / 0x3c;
  track->cb_color_cmask_slice[tmp] = radeon_get_ib_value(p, idx);
  break;
 case CB_COLOR0_BASE:
 case CB_COLOR1_BASE:
 case CB_COLOR2_BASE:
 case CB_COLOR3_BASE:
 case CB_COLOR4_BASE:
 case CB_COLOR5_BASE:
 case CB_COLOR6_BASE:
 case CB_COLOR7_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  tmp = (reg - CB_COLOR0_BASE) / 0x3c;
  track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->cb_color_bo[tmp] = reloc->robj;
  track->cb_dirty = true;
  break;
 case CB_COLOR8_BASE:
 case CB_COLOR9_BASE:
 case CB_COLOR10_BASE:
 case CB_COLOR11_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  tmp = ((reg - CB_COLOR8_BASE) / 0x1c) + 8;
  track->cb_color_bo_offset[tmp] = radeon_get_ib_value(p, idx);
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->cb_color_bo[tmp] = reloc->robj;
  track->cb_dirty = true;
  break;
 case DB_HTILE_DATA_BASE:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  track->htile_offset = radeon_get_ib_value(p, idx);
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  track->htile_bo = reloc->robj;
  track->db_dirty = true;
  break;
 case DB_HTILE_SURFACE:
  /* 8x8 only */
  track->htile_surface = radeon_get_ib_value(p, idx);
  /* force 8x8 htile width and height */
  ib[idx] |= 3;
  track->db_dirty = true;
  break;
 case CB_IMMED0_BASE:
 case CB_IMMED1_BASE:
 case CB_IMMED2_BASE:
 case CB_IMMED3_BASE:
 case CB_IMMED4_BASE:
 case CB_IMMED5_BASE:
 case CB_IMMED6_BASE:
 case CB_IMMED7_BASE:
 case CB_IMMED8_BASE:
 case CB_IMMED9_BASE:
 case CB_IMMED10_BASE:
 case CB_IMMED11_BASE:
 case SQ_PGM_START_FS:
 case SQ_PGM_START_ES:
 case SQ_PGM_START_VS:
 case SQ_PGM_START_GS:
 case SQ_PGM_START_PS:
 case SQ_PGM_START_HS:
 case SQ_PGM_START_LS:
 case SQ_CONST_MEM_BASE:
 case SQ_ALU_CONST_CACHE_GS_0:
 case SQ_ALU_CONST_CACHE_GS_1:
 case SQ_ALU_CONST_CACHE_GS_2:
 case SQ_ALU_CONST_CACHE_GS_3:
 case SQ_ALU_CONST_CACHE_GS_4:
 case SQ_ALU_CONST_CACHE_GS_5:
 case SQ_ALU_CONST_CACHE_GS_6:
 case SQ_ALU_CONST_CACHE_GS_7:
 case SQ_ALU_CONST_CACHE_GS_8:
 case SQ_ALU_CONST_CACHE_GS_9:
 case SQ_ALU_CONST_CACHE_GS_10:
 case SQ_ALU_CONST_CACHE_GS_11:
 case SQ_ALU_CONST_CACHE_GS_12:
 case SQ_ALU_CONST_CACHE_GS_13:
 case SQ_ALU_CONST_CACHE_GS_14:
 case SQ_ALU_CONST_CACHE_GS_15:
 case SQ_ALU_CONST_CACHE_PS_0:
 case SQ_ALU_CONST_CACHE_PS_1:
 case SQ_ALU_CONST_CACHE_PS_2:
 case SQ_ALU_CONST_CACHE_PS_3:
 case SQ_ALU_CONST_CACHE_PS_4:
 case SQ_ALU_CONST_CACHE_PS_5:
 case SQ_ALU_CONST_CACHE_PS_6:
 case SQ_ALU_CONST_CACHE_PS_7:
 case SQ_ALU_CONST_CACHE_PS_8:
 case SQ_ALU_CONST_CACHE_PS_9:
 case SQ_ALU_CONST_CACHE_PS_10:
 case SQ_ALU_CONST_CACHE_PS_11:
 case SQ_ALU_CONST_CACHE_PS_12:
 case SQ_ALU_CONST_CACHE_PS_13:
 case SQ_ALU_CONST_CACHE_PS_14:
 case SQ_ALU_CONST_CACHE_PS_15:
 case SQ_ALU_CONST_CACHE_VS_0:
 case SQ_ALU_CONST_CACHE_VS_1:
 case SQ_ALU_CONST_CACHE_VS_2:
 case SQ_ALU_CONST_CACHE_VS_3:
 case SQ_ALU_CONST_CACHE_VS_4:
 case SQ_ALU_CONST_CACHE_VS_5:
 case SQ_ALU_CONST_CACHE_VS_6:
 case SQ_ALU_CONST_CACHE_VS_7:
 case SQ_ALU_CONST_CACHE_VS_8:
 case SQ_ALU_CONST_CACHE_VS_9:
 case SQ_ALU_CONST_CACHE_VS_10:
 case SQ_ALU_CONST_CACHE_VS_11:
 case SQ_ALU_CONST_CACHE_VS_12:
 case SQ_ALU_CONST_CACHE_VS_13:
 case SQ_ALU_CONST_CACHE_VS_14:
 case SQ_ALU_CONST_CACHE_VS_15:
 case SQ_ALU_CONST_CACHE_HS_0:
 case SQ_ALU_CONST_CACHE_HS_1:
 case SQ_ALU_CONST_CACHE_HS_2:
 case SQ_ALU_CONST_CACHE_HS_3:
 case SQ_ALU_CONST_CACHE_HS_4:
 case SQ_ALU_CONST_CACHE_HS_5:
 case SQ_ALU_CONST_CACHE_HS_6:
 case SQ_ALU_CONST_CACHE_HS_7:
 case SQ_ALU_CONST_CACHE_HS_8:
 case SQ_ALU_CONST_CACHE_HS_9:
 case SQ_ALU_CONST_CACHE_HS_10:
 case SQ_ALU_CONST_CACHE_HS_11:
 case SQ_ALU_CONST_CACHE_HS_12:
 case SQ_ALU_CONST_CACHE_HS_13:
 case SQ_ALU_CONST_CACHE_HS_14:
 case SQ_ALU_CONST_CACHE_HS_15:
 case SQ_ALU_CONST_CACHE_LS_0:
 case SQ_ALU_CONST_CACHE_LS_1:
 case SQ_ALU_CONST_CACHE_LS_2:
 case SQ_ALU_CONST_CACHE_LS_3:
 case SQ_ALU_CONST_CACHE_LS_4:
 case SQ_ALU_CONST_CACHE_LS_5:
 case SQ_ALU_CONST_CACHE_LS_6:
 case SQ_ALU_CONST_CACHE_LS_7:
 case SQ_ALU_CONST_CACHE_LS_8:
 case SQ_ALU_CONST_CACHE_LS_9:
 case SQ_ALU_CONST_CACHE_LS_10:
 case SQ_ALU_CONST_CACHE_LS_11:
 case SQ_ALU_CONST_CACHE_LS_12:
 case SQ_ALU_CONST_CACHE_LS_13:
 case SQ_ALU_CONST_CACHE_LS_14:
 case SQ_ALU_CONST_CACHE_LS_15:
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  break;
 case SX_MEMORY_EXPORT_BASE:
  if (p->rdev->family >= CHIP_CAYMAN) {
   dev_warn(p->dev, "bad SET_CONFIG_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONFIG_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  break;
 case CAYMAN_SX_SCATTER_EXPORT_BASE:
  if (p->rdev->family < CHIP_CAYMAN) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   dev_warn(p->dev, "bad SET_CONTEXT_REG "
     "0x%04X\n", reg);
   return -EINVAL;
  }
  ib[idx] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  break;
 case SX_MISC:
  track->sx_misc_kill_all_prims = (radeon_get_ib_value(p, idx) & 0x1) != 0;
  break;
 default:
  dev_warn(p->dev, "forbidden register 0x%08x at %d\n", reg, idx);
  return -EINVAL;
 }
 return 0;
}

/**
 * evergreen_is_safe_reg() - check if register is authorized or not
 * @p: parser structure holding parsing context
 * @reg: register we are testing
 *
 * This function will test against reg_safe_bm and return true
 * if register is safe or false otherwise.
 */
static inline bool evergreen_is_safe_reg(struct radeon_cs_parser *p, u32 reg)
{
 struct evergreen_cs_track *track = p->track;
 u32 m, i;

 i = (reg >> 7);
 if (unlikely(i >= REG_SAFE_BM_SIZE)) {
  return false;
 }
 m = 1 << ((reg >> 2) & 31);
 if (!(track->reg_safe_bm[i] & m))
  return true;

 return false;
}

static int evergreen_packet3_check(struct radeon_cs_parser *p,
       struct radeon_cs_packet *pkt)
{
 struct radeon_bo_list *reloc;
 struct evergreen_cs_track *track;
 uint32_t *ib;
 unsigned idx;
 unsigned i;
 unsigned start_reg, end_reg, reg;
 int r;
 u32 idx_value;

 track = (struct evergreen_cs_track *)p->track;
 ib = p->ib.ptr;
 idx = pkt->idx + 1;
 idx_value = radeon_get_ib_value(p, idx);

 switch (pkt->opcode) {
 case PACKET3_SET_PREDICATION:
 {
  int pred_op;
  int tmp;
  uint64_t offset;

  if (pkt->count != 1) {
   DRM_ERROR("bad SET PREDICATION\n");
   return -EINVAL;
  }

  tmp = radeon_get_ib_value(p, idx + 1);
  pred_op = (tmp >> 16) & 0x7;

  /* for the clear predicate operation */
  if (pred_op == 0)
   return 0;

  if (pred_op > 2) {
   DRM_ERROR("bad SET PREDICATION operation %d\n", pred_op);
   return -EINVAL;
  }

  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   DRM_ERROR("bad SET PREDICATION\n");
   return -EINVAL;
  }

  offset = reloc->gpu_offset +
    (idx_value & 0xfffffff0) +
    ((u64)(tmp & 0xff) << 32);

  ib[idx + 0] = offset;
  ib[idx + 1] = (tmp & 0xffffff00) | (upper_32_bits(offset) & 0xff);
 }
 break;
 case PACKET3_CONTEXT_CONTROL:
  if (pkt->count != 1) {
   DRM_ERROR("bad CONTEXT_CONTROL\n");
   return -EINVAL;
  }
  break;
 case PACKET3_INDEX_TYPE:
 case PACKET3_NUM_INSTANCES:
 case PACKET3_CLEAR_STATE:
  if (pkt->count) {
   DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n");
   return -EINVAL;
  }
  break;
 case CAYMAN_PACKET3_DEALLOC_STATE:
  if (p->rdev->family < CHIP_CAYMAN) {
   DRM_ERROR("bad PACKET3_DEALLOC_STATE\n");
   return -EINVAL;
  }
  if (pkt->count) {
   DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES/CLEAR_STATE\n");
   return -EINVAL;
  }
  break;
 case PACKET3_INDEX_BASE:
 {
  uint64_t offset;

  if (pkt->count != 1) {
   DRM_ERROR("bad INDEX_BASE\n");
   return -EINVAL;
  }
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   DRM_ERROR("bad INDEX_BASE\n");
   return -EINVAL;
  }

  offset = reloc->gpu_offset +
    idx_value +
    ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);

  ib[idx+0] = offset;
  ib[idx+1] = upper_32_bits(offset) & 0xff;

  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
   return r;
  }
  break;
 }
 case PACKET3_INDEX_BUFFER_SIZE:
 {
  if (pkt->count != 0) {
   DRM_ERROR("bad INDEX_BUFFER_SIZE\n");
   return -EINVAL;
  }
  break;
 }
 case PACKET3_DRAW_INDEX:
 {
  uint64_t offset;
  if (pkt->count != 3) {
   DRM_ERROR("bad DRAW_INDEX\n");
   return -EINVAL;
  }
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   DRM_ERROR("bad DRAW_INDEX\n");
   return -EINVAL;
  }

  offset = reloc->gpu_offset +
    idx_value +
    ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);

  ib[idx+0] = offset;
  ib[idx+1] = upper_32_bits(offset) & 0xff;

  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
   return r;
  }
  break;
 }
 case PACKET3_DRAW_INDEX_2:
 {
  uint64_t offset;

  if (pkt->count != 4) {
   DRM_ERROR("bad DRAW_INDEX_2\n");
   return -EINVAL;
  }
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   DRM_ERROR("bad DRAW_INDEX_2\n");
   return -EINVAL;
  }

  offset = reloc->gpu_offset +
    radeon_get_ib_value(p, idx+1) +
    ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);

  ib[idx+1] = offset;
  ib[idx+2] = upper_32_bits(offset) & 0xff;

  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
   return r;
  }
  break;
 }
 case PACKET3_DRAW_INDEX_AUTO:
  if (pkt->count != 1) {
   DRM_ERROR("bad DRAW_INDEX_AUTO\n");
   return -EINVAL;
  }
  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
   return r;
  }
  break;
 case PACKET3_DRAW_INDEX_MULTI_AUTO:
  if (pkt->count != 2) {
   DRM_ERROR("bad DRAW_INDEX_MULTI_AUTO\n");
   return -EINVAL;
  }
  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
   return r;
  }
  break;
 case PACKET3_DRAW_INDEX_IMMD:
  if (pkt->count < 2) {
   DRM_ERROR("bad DRAW_INDEX_IMMD\n");
   return -EINVAL;
  }
  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
   return r;
  }
  break;
 case PACKET3_DRAW_INDEX_OFFSET:
  if (pkt->count != 2) {
   DRM_ERROR("bad DRAW_INDEX_OFFSET\n");
   return -EINVAL;
  }
  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
   return r;
  }
  break;
 case PACKET3_DRAW_INDEX_OFFSET_2:
  if (pkt->count != 3) {
   DRM_ERROR("bad DRAW_INDEX_OFFSET_2\n");
   return -EINVAL;
  }
  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
   return r;
  }
  break;
 case PACKET3_SET_BASE:
 {
  /*
  DW 1 HEADER Header of the packet. Shader_Type in bit 1 of the Header will correspond to the shader type of the Load, see Type-3 Packet.
     2 BASE_INDEX Bits [3:0] BASE_INDEX - Base Index specifies which base address is specified in the last two DWs.
       0001: DX11 Draw_Index_Indirect Patch Table Base: Base address for Draw_Index_Indirect data.
     3 ADDRESS_LO Bits [31:3] - Lower bits of QWORD-Aligned Address. Bits [2:0] - Reserved
     4 ADDRESS_HI Bits [31:8] - Reserved. Bits [7:0] - Upper bits of Address [47:32]
  */
  if (pkt->count != 2) {
   DRM_ERROR("bad SET_BASE\n");
   return -EINVAL;
  }

  /* currently only supporting setting indirect draw buffer base address */
  if (idx_value != 1) {
   DRM_ERROR("bad SET_BASE\n");
   return -EINVAL;
  }

  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   DRM_ERROR("bad SET_BASE\n");
   return -EINVAL;
  }

  track->indirect_draw_buffer_size = radeon_bo_size(reloc->robj);

  ib[idx+1] = reloc->gpu_offset;
  ib[idx+2] = upper_32_bits(reloc->gpu_offset) & 0xff;

  break;
 }
 case PACKET3_DRAW_INDIRECT:
 case PACKET3_DRAW_INDEX_INDIRECT:
 {
  u64 size = pkt->opcode == PACKET3_DRAW_INDIRECT ? 16 : 20;

  /*
  DW 1 HEADER
     2 DATA_OFFSET Bits [31:0] + byte aligned offset where the required data structure starts. Bits 1:0 are zero
     3 DRAW_INITIATOR Draw Initiator Register. Written to the VGT_DRAW_INITIATOR register for the assigned context
  */
  if (pkt->count != 1) {
   DRM_ERROR("bad DRAW_INDIRECT\n");
   return -EINVAL;
  }

  if (idx_value + size > track->indirect_draw_buffer_size) {
   dev_warn(p->dev, "DRAW_INDIRECT buffer too small %u + %llu > %lu\n",
    idx_value, size, track->indirect_draw_buffer_size);
   return -EINVAL;
  }

  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
   return r;
  }
  break;
 }
 case PACKET3_DISPATCH_DIRECT:
  if (pkt->count != 3) {
   DRM_ERROR("bad DISPATCH_DIRECT\n");
   return -EINVAL;
  }
  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream %d\n", __func__, __LINE__, idx);
   return r;
  }
  break;
 case PACKET3_DISPATCH_INDIRECT:
  if (pkt->count != 1) {
   DRM_ERROR("bad DISPATCH_INDIRECT\n");
   return -EINVAL;
  }
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   DRM_ERROR("bad DISPATCH_INDIRECT\n");
   return -EINVAL;
  }
  ib[idx+0] = idx_value + (u32)(reloc->gpu_offset & 0xffffffff);
  r = evergreen_cs_track_check(p);
  if (r) {
   dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
   return r;
  }
  break;
 case PACKET3_WAIT_REG_MEM:
  if (pkt->count != 5) {
   DRM_ERROR("bad WAIT_REG_MEM\n");
   return -EINVAL;
  }
  /* bit 4 is reg (0) or mem (1) */
  if (idx_value & 0x10) {
   uint64_t offset;

   r = radeon_cs_packet_next_reloc(p, &reloc, 0);
   if (r) {
    DRM_ERROR("bad WAIT_REG_MEM\n");
    return -EINVAL;
   }

   offset = reloc->gpu_offset +
     (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
     ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);

   ib[idx+1] = (ib[idx+1] & 0x3) | (offset & 0xfffffffc);
   ib[idx+2] = upper_32_bits(offset) & 0xff;
  } else if (idx_value & 0x100) {
   DRM_ERROR("cannot use PFP on REG wait\n");
   return -EINVAL;
  }
  break;
 case PACKET3_CP_DMA:
 {
  u32 command, size, info;
  u64 offset, tmp;
  if (pkt->count != 4) {
   DRM_ERROR("bad CP DMA\n");
   return -EINVAL;
  }
  command = radeon_get_ib_value(p, idx+4);
  size = command & 0x1fffff;
  info = radeon_get_ib_value(p, idx+1);
  if ((((info & 0x60000000) >> 29) != 0) || /* src = GDS or DATA */
      (((info & 0x00300000) >> 20) != 0) || /* dst = GDS */
      ((((info & 0x00300000) >> 20) == 0) &&
       (command & PACKET3_CP_DMA_CMD_DAS)) || /* dst = register */
      ((((info & 0x60000000) >> 29) == 0) &&
       (command & PACKET3_CP_DMA_CMD_SAS))) { /* src = register */
   /* non mem to mem copies requires dw aligned count */
   if (size % 4) {
    DRM_ERROR("CP DMA command requires dw count alignment\n");
    return -EINVAL;
   }
  }
  if (command & PACKET3_CP_DMA_CMD_SAS) {
   /* src address space is register */
   /* GDS is ok */
   if (((info & 0x60000000) >> 29) != 1) {
    DRM_ERROR("CP DMA SAS not supported\n");
    return -EINVAL;
   }
  } else {
   if (command & PACKET3_CP_DMA_CMD_SAIC) {
    DRM_ERROR("CP DMA SAIC only supported for registers\n");
    return -EINVAL;
   }
   /* src address space is memory */
   if (((info & 0x60000000) >> 29) == 0) {
    r = radeon_cs_packet_next_reloc(p, &reloc, 0);
    if (r) {
     DRM_ERROR("bad CP DMA SRC\n");
     return -EINVAL;
    }

    tmp = radeon_get_ib_value(p, idx) +
     ((u64)(radeon_get_ib_value(p, idx+1) & 0xff) << 32);

    offset = reloc->gpu_offset + tmp;

    if ((tmp + size) > radeon_bo_size(reloc->robj)) {
     dev_warn(p->dev, "CP DMA src buffer too small (%llu %lu)\n",
       tmp + size, radeon_bo_size(reloc->robj));
     return -EINVAL;
    }

    ib[idx] = offset;
    ib[idx+1] = (ib[idx+1] & 0xffffff00) | (upper_32_bits(offset) & 0xff);
   } else if (((info & 0x60000000) >> 29) != 2) {
    DRM_ERROR("bad CP DMA SRC_SEL\n");
    return -EINVAL;
   }
  }
  if (command & PACKET3_CP_DMA_CMD_DAS) {
   /* dst address space is register */
   /* GDS is ok */
   if (((info & 0x00300000) >> 20) != 1) {
    DRM_ERROR("CP DMA DAS not supported\n");
    return -EINVAL;
   }
  } else {
   /* dst address space is memory */
   if (command & PACKET3_CP_DMA_CMD_DAIC) {
    DRM_ERROR("CP DMA DAIC only supported for registers\n");
    return -EINVAL;
   }
   if (((info & 0x00300000) >> 20) == 0) {
    r = radeon_cs_packet_next_reloc(p, &reloc, 0);
    if (r) {
     DRM_ERROR("bad CP DMA DST\n");
     return -EINVAL;
    }

    tmp = radeon_get_ib_value(p, idx+2) +
     ((u64)(radeon_get_ib_value(p, idx+3) & 0xff) << 32);

    offset = reloc->gpu_offset + tmp;

    if ((tmp + size) > radeon_bo_size(reloc->robj)) {
     dev_warn(p->dev, "CP DMA dst buffer too small (%llu %lu)\n",
       tmp + size, radeon_bo_size(reloc->robj));
     return -EINVAL;
    }

    ib[idx+2] = offset;
    ib[idx+3] = upper_32_bits(offset) & 0xff;
   } else {
    DRM_ERROR("bad CP DMA DST_SEL\n");
    return -EINVAL;
   }
  }
  break;
 }
 case PACKET3_PFP_SYNC_ME:
  if (pkt->count) {
   DRM_ERROR("bad PFP_SYNC_ME\n");
   return -EINVAL;
  }
  break;
 case PACKET3_SURFACE_SYNC:
  if (pkt->count != 3) {
   DRM_ERROR("bad SURFACE_SYNC\n");
   return -EINVAL;
  }
  /* 0xffffffff/0x0 is flush all cache flag */
  if (radeon_get_ib_value(p, idx + 1) != 0xffffffff ||
      radeon_get_ib_value(p, idx + 2) != 0) {
   r = radeon_cs_packet_next_reloc(p, &reloc, 0);
   if (r) {
    DRM_ERROR("bad SURFACE_SYNC\n");
    return -EINVAL;
   }
   ib[idx+2] += (u32)((reloc->gpu_offset >> 8) & 0xffffffff);
  }
  break;
 case PACKET3_EVENT_WRITE:
  if (pkt->count != 2 && pkt->count != 0) {
   DRM_ERROR("bad EVENT_WRITE\n");
   return -EINVAL;
  }
  if (pkt->count) {
   uint64_t offset;

   r = radeon_cs_packet_next_reloc(p, &reloc, 0);
   if (r) {
    DRM_ERROR("bad EVENT_WRITE\n");
    return -EINVAL;
   }
   offset = reloc->gpu_offset +
     (radeon_get_ib_value(p, idx+1) & 0xfffffff8) +
     ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);

   ib[idx+1] = offset & 0xfffffff8;
   ib[idx+2] = upper_32_bits(offset) & 0xff;
  }
  break;
 case PACKET3_EVENT_WRITE_EOP:
 {
  uint64_t offset;

  if (pkt->count != 4) {
   DRM_ERROR("bad EVENT_WRITE_EOP\n");
   return -EINVAL;
  }
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   DRM_ERROR("bad EVENT_WRITE_EOP\n");
   return -EINVAL;
  }

  offset = reloc->gpu_offset +
    (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
    ((u64)(radeon_get_ib_value(p, idx+2) & 0xff) << 32);

  ib[idx+1] = offset & 0xfffffffc;
  ib[idx+2] = (ib[idx+2] & 0xffffff00) | (upper_32_bits(offset) & 0xff);
  break;
 }
 case PACKET3_EVENT_WRITE_EOS:
 {
  uint64_t offset;

  if (pkt->count != 3) {
   DRM_ERROR("bad EVENT_WRITE_EOS\n");
   return -EINVAL;
  }
  r = radeon_cs_packet_next_reloc(p, &reloc, 0);
  if (r) {
   DRM_ERROR("bad EVENT_WRITE_EOS\n");
   return -EINVAL;
  }

  offset = reloc->gpu_offset +
    (radeon_get_ib_value(p, idx+1) & 0xfffffffc) +
--> --------------------

--> maximum size reached

--> --------------------

¤ Dauer der Verarbeitung: 0.20 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.