summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoroga <oga@openbsd.org>2011-05-30 21:50:46 +0000
committeroga <oga@openbsd.org>2011-05-30 21:50:46 +0000
commit3d3e7161e2b12f2e1ccd3430b7dbf6bb4f9aa3bd (patch)
treefc3e7a8fa1cf3a9deea885bb6366a32788cbd740
parentfor (some; stuff; here) (diff)
downloadwireguard-openbsd-3d3e7161e2b12f2e1ccd3430b7dbf6bb4f9aa3bd.tar.xz
wireguard-openbsd-3d3e7161e2b12f2e1ccd3430b7dbf6bb4f9aa3bd.zip
Add RADEON_CS ioctl support for r600 and r700.
This is a faked up version of the gem command submission method for r600 required for OpenGL support on these chipsets. Currently support is not perfect. since these chips have a rather funky ringbuffer based interrupt method which this code does not yet support so interrupt based polling methods must be turned off in mesa. I've not found a good way which to do that per-driver, so until I work that out I the following .drirc (or /etc/drirc) chunk (provided by Brynet after I was too slack to provide it myself) will be needed: <driconf> <device screen="0" driver="r600"> <application name="all"> <option name="fthrottle_mode" value="0"/> <option name="vblank_mode" value="0"/> </application> </device> </driconf> Tested by many on tech@. While it provided more problems, this diff made espie@ stop nagging me when he finally found out it existed.
-rw-r--r--sys/dev/pci/drm/files.drm3
-rw-r--r--sys/dev/pci/drm/r600_blit.c95
-rw-r--r--sys/dev/pci/drm/radeon_cp.c21
-rw-r--r--sys/dev/pci/drm/radeon_cs.c856
-rw-r--r--sys/dev/pci/drm/radeon_drv.c12
-rw-r--r--sys/dev/pci/drm/radeon_drv.h54
-rw-r--r--sys/dev/pci/drm/radeon_irq.c2
7 files changed, 995 insertions, 48 deletions
diff --git a/sys/dev/pci/drm/files.drm b/sys/dev/pci/drm/files.drm
index f2624e45b6d..c2d10f9c027 100644
--- a/sys/dev/pci/drm/files.drm
+++ b/sys/dev/pci/drm/files.drm
@@ -1,5 +1,5 @@
# $NetBSD: files.drm,v 1.2 2007/03/28 11:29:37 jmcneill Exp $
-# $OpenBSD: files.drm,v 1.20 2010/05/25 17:15:49 oga Exp $
+# $OpenBSD: files.drm,v 1.21 2011/05/30 21:50:46 oga Exp $
# direct rendering modules
define drmbase {}
@@ -26,6 +26,7 @@ file dev/pci/drm/r300_cmdbuf.c radeondrm
file dev/pci/drm/r600_blit.c radeondrm
file dev/pci/drm/r600_blit_shaders.c radeondrm
file dev/pci/drm/radeon_cp.c radeondrm
+file dev/pci/drm/radeon_cs.c radeondrm
file dev/pci/drm/radeon_drv.c radeondrm
file dev/pci/drm/radeon_irq.c radeondrm
file dev/pci/drm/radeon_mem.c radeondrm
diff --git a/sys/dev/pci/drm/r600_blit.c b/sys/dev/pci/drm/r600_blit.c
index fba9720ea59..2cd782c756a 100644
--- a/sys/dev/pci/drm/r600_blit.c
+++ b/sys/dev/pci/drm/r600_blit.c
@@ -128,7 +128,7 @@ set_shaders(struct drm_device *dev)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
u64 gpu_addr;
- int shader_size, i;
+ int i;
u32 *vs, *ps;
uint32_t sq_pgm_resources;
DRM_DEBUG("\n");
@@ -137,12 +137,10 @@ set_shaders(struct drm_device *dev)
vs = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset);
ps = (u32 *) ((char *)dev->agp_buffer_map->handle + dev_priv->blit_vb->offset + 256);
- shader_size = r6xx_vs_size;
- for (i = 0; i < shader_size; i++)
- vs[i] = r6xx_vs[i];
- shader_size = r6xx_ps_size;
- for (i = 0; i < shader_size; i++)
- ps[i] = r6xx_ps[i];
+ for (i = 0; i < r6xx_vs_size; i++)
+ vs[i] = cpu_to_le32(r6xx_vs[i]);
+ for (i = 0; i < r6xx_ps_size; i++)
+ ps[i] = cpu_to_le32(r6xx_ps[i]);
dev_priv->blit_vb->used = 512;
@@ -194,6 +192,9 @@ set_vtx_resource(drm_radeon_private_t *dev_priv, u64 gpu_addr)
DRM_DEBUG("\n");
sq_vtx_constant_word2 = (((gpu_addr >> 32) & 0xff) | (16 << 8));
+#ifdef __BIG_ENDIAN
+ sq_vtx_constant_word2 |= (2 << 30);
+#endif
BEGIN_RING(9);
OUT_RING(CP_PACKET3(R600_IT_SET_RESOURCE, 7));
@@ -290,7 +291,11 @@ draw_auto(drm_radeon_private_t *dev_priv)
OUT_RING(DI_PT_RECTLIST);
OUT_RING(CP_PACKET3(R600_IT_INDEX_TYPE, 0));
+#ifdef __BIG_ENDIAN
+ OUT_RING((2 << 2) | DI_INDEX_SIZE_16_BIT);
+#else
OUT_RING(DI_INDEX_SIZE_16_BIT);
+#endif
OUT_RING(CP_PACKET3(R600_IT_NUM_INSTANCES, 0));
OUT_RING(1);
@@ -306,7 +311,7 @@ draw_auto(drm_radeon_private_t *dev_priv)
static inline void
set_default_state(drm_radeon_private_t *dev_priv)
{
- int default_state_dw, i;
+ int i;
u32 sq_config, sq_gpr_resource_mgmt_1, sq_gpr_resource_mgmt_2;
u32 sq_thread_resource_mgmt, sq_stack_resource_mgmt_1, sq_stack_resource_mgmt_2;
int num_ps_gprs, num_vs_gprs, num_temp_gprs, num_gs_gprs, num_es_gprs;
@@ -458,14 +463,12 @@ set_default_state(drm_radeon_private_t *dev_priv)
R600_NUM_ES_STACK_ENTRIES(num_es_stack_entries));
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) {
- default_state_dw = r7xx_default_size * 4;
- BEGIN_RING(default_state_dw + 10);
- for (i = 0; i < default_state_dw; i++)
+ BEGIN_RING(r7xx_default_size + 10);
+ for (i = 0; i < r7xx_default_size; i++)
OUT_RING(r7xx_default_state[i]);
} else {
- default_state_dw = r6xx_default_size * 4;
- BEGIN_RING(default_state_dw + 10);
- for (i = 0; i < default_state_dw; i++)
+ BEGIN_RING(r6xx_default_size + 10);
+ for (i = 0; i < r6xx_default_size; i++)
OUT_RING(r6xx_default_state[i]);
}
OUT_RING(CP_PACKET3(R600_IT_EVENT_WRITE, 0));
@@ -538,9 +541,12 @@ int
r600_prepare_blit_copy(struct drm_device *dev, struct drm_file *file_priv)
{
drm_radeon_private_t *dev_priv = dev->dev_private;
+ int ret;
DRM_DEBUG("\n");
- r600_nomm_get_vb(dev);
+ ret = r600_nomm_get_vb(dev);
+ if (ret)
+ return ret;
dev_priv->blit_vb->file_priv = file_priv;
@@ -736,7 +742,7 @@ r600_blit_copy(struct drm_device *dev,
/* dst */
set_render_target(dev_priv, COLOR_8_8_8_8,
- dst_x + cur_size, h,
+ (dst_x + cur_size) / 4, h,
dst_gpu_addr);
/* scissors */
@@ -773,12 +779,10 @@ r600_blit_swap(struct drm_device *dev,
{
drm_radeon_private_t *dev_priv = dev->dev_private;
int cb_format, tex_format;
+ int sx2, sy2, dx2, dy2;
u64 vb_addr;
u32 *vb;
- vb = (u32 *) ((char *)dev->agp_buffer_map->handle +
- dev_priv->blit_vb->offset + dev_priv->blit_vb->used);
-
if ((dev_priv->blit_vb->used + 48) > dev_priv->blit_vb->total) {
r600_nomm_put_vb(dev);
@@ -787,19 +791,13 @@ r600_blit_swap(struct drm_device *dev,
return;
set_shaders(dev);
- vb = r600_nomm_get_vb_ptr(dev);
}
+ vb = r600_nomm_get_vb_ptr(dev);
- if (cpp == 4) {
- cb_format = COLOR_8_8_8_8;
- tex_format = FMT_8_8_8_8;
- } else if (cpp == 2) {
- cb_format = COLOR_5_6_5;
- tex_format = FMT_5_6_5;
- } else {
- cb_format = COLOR_8;
- tex_format = FMT_8;
- }
+ sx2 = sx + w;
+ sy2 = sy + h;
+ dx2 = dx + w;
+ dy2 = dy + h;
vb[0] = i2f(dx);
vb[1] = i2f(dy);
@@ -807,31 +805,46 @@ r600_blit_swap(struct drm_device *dev,
vb[3] = i2f(sy);
vb[4] = i2f(dx);
- vb[5] = i2f(dy + h);
+ vb[5] = i2f(dy2);
vb[6] = i2f(sx);
- vb[7] = i2f(sy + h);
+ vb[7] = i2f(sy2);
+
+ vb[8] = i2f(dx2);
+ vb[9] = i2f(dy2);
+ vb[10] = i2f(sx2);
+ vb[11] = i2f(sy2);
- vb[8] = i2f(dx + w);
- vb[9] = i2f(dy + h);
- vb[10] = i2f(sx + w);
- vb[11] = i2f(sy + h);
+ switch(cpp) {
+ case 4:
+ cb_format = COLOR_8_8_8_8;
+ tex_format = FMT_8_8_8_8;
+ break;
+ case 2:
+ cb_format = COLOR_5_6_5;
+ tex_format = FMT_5_6_5;
+ break;
+ default:
+ cb_format = COLOR_8;
+ tex_format = FMT_8;
+ break;
+ }
/* src */
set_tex_resource(dev_priv, tex_format,
src_pitch / cpp,
- sy + h, src_pitch / cpp,
+ sy2, src_pitch / cpp,
src_gpu_addr);
cp_set_surface_sync(dev_priv,
- R600_TC_ACTION_ENA, (src_pitch * (sy + h)), src_gpu_addr);
+ R600_TC_ACTION_ENA, src_pitch * sy2, src_gpu_addr);
/* dst */
set_render_target(dev_priv, cb_format,
- dst_pitch / cpp, dy + h,
+ dst_pitch / cpp, dy2,
dst_gpu_addr);
/* scissors */
- set_scissors(dev_priv, dx, dy, dx + w, dy + h);
+ set_scissors(dev_priv, dx, dy, dx2, dy2);
/* Vertex buffer setup */
vb_addr = dev_priv->gart_buffers_offset +
@@ -844,7 +857,7 @@ r600_blit_swap(struct drm_device *dev,
cp_set_surface_sync(dev_priv,
R600_CB_ACTION_ENA | R600_CB0_DEST_BASE_ENA,
- dst_pitch * (dy + h), dst_gpu_addr);
+ dst_pitch * dy2, dst_gpu_addr);
dev_priv->blit_vb->used += 12 * 4;
}
diff --git a/sys/dev/pci/drm/radeon_cp.c b/sys/dev/pci/drm/radeon_cp.c
index 00fa0f221c7..26f46ba3247 100644
--- a/sys/dev/pci/drm/radeon_cp.c
+++ b/sys/dev/pci/drm/radeon_cp.c
@@ -112,6 +112,24 @@ int radeon_setup_pcigart_surface(drm_radeon_private_t *dev_priv);
u32
+RADEON_READ_MM(drm_radeon_private_t *dev_priv, int addr)
+{
+ u32 ret;
+
+ if (addr < 0x10000)
+ ret = bus_space_read_4(dev_priv->regs->bst,
+ dev_priv->regs->bsh, addr);
+ else {
+ bus_space_write_4(dev_priv->regs->bst, dev_priv->regs->bsh,
+ RADEON_MM_INDEX, addr);
+ ret = bus_space_read_4(dev_priv->regs->bst,
+ dev_priv->regs->bsh, RADEON_MM_DATA);
+ }
+
+ return ret;
+}
+
+u32
R500_READ_MCIND(drm_radeon_private_t *dev_priv, int addr)
{
u32 ret;
@@ -3240,6 +3258,9 @@ radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init)
radeon_do_engine_reset(dev);
radeon_test_writeback(dev_priv);
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+ r600_cs_init(dev);
+
return 0;
}
diff --git a/sys/dev/pci/drm/radeon_cs.c b/sys/dev/pci/drm/radeon_cs.c
new file mode 100644
index 00000000000..27e79697b60
--- /dev/null
+++ b/sys/dev/pci/drm/radeon_cs.c
@@ -0,0 +1,856 @@
+/*-
+ * Copyright 2008 Jerome Glisse.
+ * All Rights Reserved.
+ *
+ * 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 (including the next
+ * paragraph) 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
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS 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:
+ * Jerome Glisse <glisse@freedesktop.org>
+ */
+
+#include "drmP.h"
+#include "radeon_drm.h"
+#include "radeon_drv.h"
+
+/* regs */
+#define AVIVO_D1MODE_VLINE_START_END 0x6538
+#define AVIVO_D2MODE_VLINE_START_END 0x6d38
+#define R600_CP_COHER_BASE 0x85f8
+#define R600_DB_DEPTH_BASE 0x2800c
+#define R600_CB_COLOR0_BASE 0x28040
+#define R600_CB_COLOR1_BASE 0x28044
+#define R600_CB_COLOR2_BASE 0x28048
+#define R600_CB_COLOR3_BASE 0x2804c
+#define R600_CB_COLOR4_BASE 0x28050
+#define R600_CB_COLOR5_BASE 0x28054
+#define R600_CB_COLOR6_BASE 0x28058
+#define R600_CB_COLOR7_BASE 0x2805c
+#define R600_SQ_PGM_START_FS 0x28894
+#define R600_SQ_PGM_START_ES 0x28880
+#define R600_SQ_PGM_START_VS 0x28858
+#define R600_SQ_PGM_START_GS 0x2886c
+#define R600_SQ_PGM_START_PS 0x28840
+#define R600_VGT_DMA_BASE 0x287e8
+#define R600_VGT_DMA_BASE_HI 0x287e4
+#define R600_VGT_STRMOUT_BASE_OFFSET_0 0x28b10
+#define R600_VGT_STRMOUT_BASE_OFFSET_1 0x28b14
+#define R600_VGT_STRMOUT_BASE_OFFSET_2 0x28b18
+#define R600_VGT_STRMOUT_BASE_OFFSET_3 0x28b1c
+#define R600_VGT_STRMOUT_BASE_OFFSET_HI_0 0x28b44
+#define R600_VGT_STRMOUT_BASE_OFFSET_HI_1 0x28b48
+#define R600_VGT_STRMOUT_BASE_OFFSET_HI_2 0x28b4c
+#define R600_VGT_STRMOUT_BASE_OFFSET_HI_3 0x28b50
+#define R600_VGT_STRMOUT_BUFFER_BASE_0 0x28ad8
+#define R600_VGT_STRMOUT_BUFFER_BASE_1 0x28ae8
+#define R600_VGT_STRMOUT_BUFFER_BASE_2 0x28af8
+#define R600_VGT_STRMOUT_BUFFER_BASE_3 0x28b08
+#define R600_VGT_STRMOUT_BUFFER_OFFSET_0 0x28adc
+#define R600_VGT_STRMOUT_BUFFER_OFFSET_1 0x28aec
+#define R600_VGT_STRMOUT_BUFFER_OFFSET_2 0x28afc
+#define R600_VGT_STRMOUT_BUFFER_OFFSET_3 0x28b0c
+
+/* resource type */
+#define R600_SQ_TEX_VTX_INVALID_TEXTURE 0x0
+#define R600_SQ_TEX_VTX_INVALID_BUFFER 0x1
+#define R600_SQ_TEX_VTX_VALID_TEXTURE 0x2
+#define R600_SQ_TEX_VTX_VALID_BUFFER 0x3
+
+/* packet 3 type offsets */
+#define R600_SET_CONFIG_REG_OFFSET 0x00008000
+#define R600_SET_CONFIG_REG_END 0x0000ac00
+#define R600_SET_CONTEXT_REG_OFFSET 0x00028000
+#define R600_SET_CONTEXT_REG_END 0x00029000
+#define R600_SET_ALU_CONST_OFFSET 0x00030000
+#define R600_SET_ALU_CONST_END 0x00032000
+#define R600_SET_RESOURCE_OFFSET 0x00038000
+#define R600_SET_RESOURCE_END 0x0003c000
+#define R600_SET_SAMPLER_OFFSET 0x0003c000
+#define R600_SET_SAMPLER_END 0x0003cff0
+#define R600_SET_CTL_CONST_OFFSET 0x0003cff0
+#define R600_SET_CTL_CONST_END 0x0003e200
+#define R600_SET_LOOP_CONST_OFFSET 0x0003e200
+#define R600_SET_LOOP_CONST_END 0x0003e380
+#define R600_SET_BOOL_CONST_OFFSET 0x0003e380
+#define R600_SET_BOOL_CONST_END 0x00040000
+
+/* Packet 3 types */
+#define R600_IT_INDIRECT_BUFFER_END 0x00001700
+#define R600_IT_SET_PREDICATION 0x00002000
+#define R600_IT_REG_RMW 0x00002100
+#define R600_IT_COND_EXEC 0x00002200
+#define R600_IT_PRED_EXEC 0x00002300
+#define R600_IT_START_3D_CMDBUF 0x00002400
+#define R600_IT_DRAW_INDEX_2 0x00002700
+#define R600_IT_CONTEXT_CONTROL 0x00002800
+#define R600_IT_DRAW_INDEX_IMMD_BE 0x00002900
+#define R600_IT_INDEX_TYPE 0x00002A00
+#define R600_IT_DRAW_INDEX 0x00002B00
+#define R600_IT_DRAW_INDEX_AUTO 0x00002D00
+#define R600_IT_DRAW_INDEX_IMMD 0x00002E00
+#define R600_IT_NUM_INSTANCES 0x00002F00
+#define R600_IT_STRMOUT_BUFFER_UPDATE 0x00003400
+#define R600_IT_INDIRECT_BUFFER_MP 0x00003800
+#define R600_IT_MEM_SEMAPHORE 0x00003900
+#define R600_IT_MPEG_INDEX 0x00003A00
+#define R600_IT_WAIT_REG_MEM 0x00003C00
+#define R600_IT_MEM_WRITE 0x00003D00
+#define R600_IT_INDIRECT_BUFFER 0x00003200
+#define R600_IT_CP_INTERRUPT 0x00004000
+#define R600_IT_SURFACE_SYNC 0x00004300
+#define R600_IT_ME_INITIALIZE 0x00004400
+#define R600_IT_COND_WRITE 0x00004500
+#define R600_IT_EVENT_WRITE 0x00004600
+#define R600_IT_EVENT_WRITE_EOP 0x00004700
+#define R600_IT_ONE_REG_WRITE 0x00005700
+#define R600_IT_SET_CONFIG_REG 0x00006800
+#define R600_IT_SET_CONTEXT_REG 0x00006900
+#define R600_IT_SET_ALU_CONST 0x00006A00
+#define R600_IT_SET_BOOL_CONST 0x00006B00
+#define R600_IT_SET_LOOP_CONST 0x00006C00
+#define R600_IT_SET_RESOURCE 0x00006D00
+#define R600_IT_SET_SAMPLER 0x00006E00
+#define R600_IT_SET_CTL_CONST 0x00006F00
+#define R600_IT_SURFACE_BASE_UPDATE 0x00007300
+
+int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv)
+{
+ struct drm_radeon_cs_parser parser;
+ struct drm_radeon_private *dev_priv = dev->dev_private;
+ struct drm_radeon_cs *cs = data;
+ uint32_t cs_id;
+ struct drm_radeon_cs_chunk __user **chunk_ptr = NULL;
+ uint64_t *chunk_array;
+ uint64_t *chunk_array_ptr;
+ long size;
+ int r, i;
+
+ DRM_LOCK();
+ /* set command stream id to 0 which is fake id */
+ cs_id = 0;
+ cs->cs_id = cs_id;
+
+ if (dev_priv == NULL) {
+ DRM_ERROR("called with no initialization\n");
+ DRM_UNLOCK();
+ return EINVAL;
+ }
+ if (!cs->num_chunks) {
+ DRM_UNLOCK();
+ return 0;
+ }
+
+
+ chunk_array = drm_calloc(cs->num_chunks, sizeof(uint64_t));
+ if (!chunk_array) {
+ DRM_UNLOCK();
+ return ENOMEM;
+ }
+
+ chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks);
+
+ if (copyin(chunk_array_ptr, chunk_array,
+ sizeof(uint64_t) * cs->num_chunks)) {
+ r = EFAULT;
+ goto out;
+ }
+
+ parser.dev = dev;
+ parser.file_priv = fpriv;
+ parser.reloc_index = -1;
+ parser.ib_index = -1;
+ parser.num_chunks = cs->num_chunks;
+ /* copy out the chunk headers */
+ parser.chunks = drm_calloc(parser.num_chunks,
+ sizeof(struct drm_radeon_kernel_chunk));
+ if (!parser.chunks) {
+ r = ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < parser.num_chunks; i++) {
+ struct drm_radeon_cs_chunk user_chunk;
+
+ chunk_ptr = (void __user *)(unsigned long)chunk_array[i];
+
+ if (copyin(chunk_ptr, &user_chunk,
+ sizeof(struct drm_radeon_cs_chunk))) {
+ r = EFAULT;
+ goto out;
+ }
+ parser.chunks[i].chunk_id = user_chunk.chunk_id;
+
+ if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_RELOCS)
+ parser.reloc_index = i;
+
+ if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_IB)
+ parser.ib_index = i;
+
+ if (parser.chunks[i].chunk_id == RADEON_CHUNK_ID_OLD) {
+ parser.ib_index = i;
+ parser.reloc_index = -1;
+ }
+
+ parser.chunks[i].length_dw = user_chunk.length_dw;
+ parser.chunks[i].chunk_data = (uint32_t *)(unsigned long)user_chunk.chunk_data;
+
+ parser.chunks[i].kdata = NULL;
+ size = parser.chunks[i].length_dw * sizeof(uint32_t);
+
+ switch(parser.chunks[i].chunk_id) {
+ case RADEON_CHUNK_ID_IB:
+ case RADEON_CHUNK_ID_OLD:
+ if (size == 0) {
+ r = EINVAL;
+ goto out;
+ }
+ case RADEON_CHUNK_ID_RELOCS:
+ if (size) {
+ parser.chunks[i].kdata = drm_alloc(size);
+ if (!parser.chunks[i].kdata) {
+ r = ENOMEM;
+ goto out;
+ }
+
+ if (copyin(parser.chunks[i].chunk_data,
+ parser.chunks[i].kdata, size)) {
+ r = EFAULT;
+ goto out;
+ }
+ } else
+ parser.chunks[i].kdata = NULL;
+ break;
+ default:
+ break;
+ }
+ DRM_DEBUG("chunk %d %d %d %p\n", i, parser.chunks[i].chunk_id, parser.chunks[i].length_dw,
+ parser.chunks[i].chunk_data);
+ }
+
+ if (parser.chunks[parser.ib_index].length_dw > (16 * 1024)) {
+ DRM_ERROR("cs->dwords too big: %d\n", parser.chunks[parser.ib_index].length_dw);
+ r = EINVAL;
+ goto out;
+ }
+
+ /* get ib */
+ r = dev_priv->cs.ib_get(&parser);
+ if (r) {
+ DRM_ERROR("ib_get failed\n");
+ goto out;
+ }
+
+ /* now parse command stream */
+ r = dev_priv->cs.parse(&parser);
+ if (r) {
+ goto out;
+ }
+
+out:
+ dev_priv->cs.ib_free(&parser, r);
+
+ /* emit cs id sequence */
+ dev_priv->cs.id_emit(&parser, &cs_id);
+
+ cs->cs_id = cs_id;
+
+ DRM_UNLOCK();
+
+ for (i = 0; i < parser.num_chunks; i++) {
+ if (parser.chunks[i].kdata)
+ drm_free(parser.chunks[i].kdata);
+
+ }
+
+ drm_free(parser.chunks);
+ drm_free(chunk_array);
+
+ return r;
+}
+
+/* for non-mm */
+static int r600_nomm_relocate(struct drm_radeon_cs_parser *parser, uint32_t *reloc, uint64_t *offset)
+{
+ struct drm_device *dev = parser->dev;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ struct drm_radeon_kernel_chunk *reloc_chunk = &parser->chunks[parser->reloc_index];
+ uint32_t offset_dw = reloc[1];
+
+ //DRM_INFO("reloc: 0x%08x 0x%08x\n", reloc[0], reloc[1]);
+ //DRM_INFO("length: %d\n", reloc_chunk->length_dw);
+
+ if (!reloc_chunk->kdata)
+ return EINVAL;
+
+ if (offset_dw > reloc_chunk->length_dw) {
+ DRM_ERROR("Offset larger than chunk 0x%x %d\n", offset_dw, reloc_chunk->length_dw);
+ return EINVAL;
+ }
+
+ /* 40 bit addr */
+ *offset = reloc_chunk->kdata[offset_dw + 3];
+ *offset <<= 32;
+ *offset |= reloc_chunk->kdata[offset_dw + 0];
+
+ //DRM_INFO("offset 0x%lx\n", *offset);
+
+ if (!radeon_check_offset(dev_priv, *offset)) {
+ DRM_ERROR("bad offset! 0x%lx\n", (unsigned long)*offset);
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+static inline int r600_cs_packet0(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p)
+{
+ uint32_t hdr, num_dw, reg;
+ int count_dw = 1;
+ int ret = 0;
+ uint32_t offset_dw = *offset_dw_p;
+ int incr = 2;
+
+ hdr = parser->chunks[parser->ib_index].kdata[offset_dw];
+ num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2;
+ reg = (hdr & 0xffff) << 2;
+
+ while (count_dw < num_dw) {
+ switch (reg) {
+ case AVIVO_D1MODE_VLINE_START_END:
+ case AVIVO_D2MODE_VLINE_START_END:
+ break;
+ default:
+ ret = EINVAL;
+ DRM_ERROR("bad packet 0 reg: 0x%08x\n", reg);
+ break;
+ }
+ if (ret)
+ break;
+ count_dw++;
+ reg += 4;
+ }
+ *offset_dw_p += incr;
+ return ret;
+}
+
+static inline int r600_cs_packet3(struct drm_radeon_cs_parser *parser, uint32_t *offset_dw_p)
+{
+ struct drm_device *dev = parser->dev;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ uint32_t hdr, num_dw, start_reg, end_reg, reg;
+ uint32_t *reloc;
+ uint64_t offset;
+ int ret = 0;
+ uint32_t offset_dw = *offset_dw_p;
+ int incr = 2;
+ int i;
+ struct drm_radeon_kernel_chunk *ib_chunk;
+
+ ib_chunk = &parser->chunks[parser->ib_index];
+
+ hdr = ib_chunk->kdata[offset_dw];
+ num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2;
+
+ /* just the ones we use for now, add more later */
+ switch (hdr & 0xff00) {
+ case R600_IT_START_3D_CMDBUF:
+ //DRM_INFO("R600_IT_START_3D_CMDBUF\n");
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770)
+ ret = EINVAL;
+ if (num_dw != 2)
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad START_3D\n");
+ break;
+ case R600_IT_CONTEXT_CONTROL:
+ //DRM_INFO("R600_IT_CONTEXT_CONTROL\n");
+ if (num_dw != 3)
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad CONTEXT_CONTROL\n");
+ break;
+ case R600_IT_INDEX_TYPE:
+ case R600_IT_NUM_INSTANCES:
+ //DRM_INFO("R600_IT_INDEX_TYPE/R600_IT_NUM_INSTANCES\n");
+ if (num_dw != 2)
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad INDEX_TYPE/NUM_INSTANCES\n");
+ break;
+ case R600_IT_DRAW_INDEX:
+ //DRM_INFO("R600_IT_DRAW_INDEX\n");
+ if (num_dw != 5) {
+ ret = EINVAL;
+ DRM_ERROR("bad DRAW_INDEX\n");
+ break;
+ }
+ reloc = ib_chunk->kdata + offset_dw + num_dw;
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret) {
+ DRM_ERROR("bad DRAW_INDEX\n");
+ break;
+ }
+ ib_chunk->kdata[offset_dw + 1] += (offset & 0xffffffff);
+ ib_chunk->kdata[offset_dw + 2] += (upper_32_bits(offset) & 0xff);
+ break;
+ case R600_IT_DRAW_INDEX_AUTO:
+ //DRM_INFO("R600_IT_DRAW_INDEX_AUTO\n");
+ if (num_dw != 3)
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad DRAW_INDEX_AUTO\n");
+ break;
+ case R600_IT_DRAW_INDEX_IMMD_BE:
+ case R600_IT_DRAW_INDEX_IMMD:
+ //DRM_INFO("R600_IT_DRAW_INDEX_IMMD\n");
+ if (num_dw < 4)
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad DRAW_INDEX_IMMD\n");
+ break;
+ case R600_IT_WAIT_REG_MEM:
+ //DRM_INFO("R600_IT_WAIT_REG_MEM\n");
+ if (num_dw != 7)
+ ret = EINVAL;
+ /* bit 4 is reg (0) or mem (1) */
+ if (ib_chunk->kdata[offset_dw + 1] & 0x10) {
+ reloc = ib_chunk->kdata + offset_dw + num_dw;
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret) {
+ DRM_ERROR("bad WAIT_REG_MEM\n");
+ break;
+ }
+ ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
+ ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
+ }
+ if (ret)
+ DRM_ERROR("bad WAIT_REG_MEM\n");
+ break;
+ case R600_IT_SURFACE_SYNC:
+ //DRM_INFO("R600_IT_SURFACE_SYNC\n");
+ if (num_dw != 5)
+ ret = EINVAL;
+ /* 0xffffffff/0x0 is flush all cache flag */
+ else if ((ib_chunk->kdata[offset_dw + 2] == 0xffffffff) &&
+ (ib_chunk->kdata[offset_dw + 3] == 0))
+ ret = 0;
+ else {
+ reloc = ib_chunk->kdata + offset_dw + num_dw;
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret) {
+ DRM_ERROR("bad SURFACE_SYNC\n");
+ break;
+ }
+ ib_chunk->kdata[offset_dw + 3] += ((offset >> 8) & 0xffffffff);
+ }
+ break;
+ case R600_IT_EVENT_WRITE:
+ //DRM_INFO("R600_IT_EVENT_WRITE\n");
+ if ((num_dw != 4) && (num_dw != 2))
+ ret = EINVAL;
+ if (num_dw > 2) {
+ reloc = ib_chunk->kdata + offset_dw + num_dw;
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret) {
+ DRM_ERROR("bad EVENT_WRITE\n");
+ break;
+ }
+ ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
+ ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
+ }
+ if (ret)
+ DRM_ERROR("bad EVENT_WRITE\n");
+ break;
+ case R600_IT_EVENT_WRITE_EOP:
+ //DRM_INFO("R600_IT_EVENT_WRITE_EOP\n");
+ if (num_dw != 6) {
+ ret = EINVAL;
+ DRM_ERROR("bad EVENT_WRITE_EOP\n");
+ break;
+ }
+ reloc = ib_chunk->kdata + offset_dw + num_dw;
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret) {
+ DRM_ERROR("bad EVENT_WRITE_EOP\n");
+ break;
+ }
+ ib_chunk->kdata[offset_dw + 2] += (offset & 0xffffffff);
+ ib_chunk->kdata[offset_dw + 3] += (upper_32_bits(offset) & 0xff);
+ break;
+ case R600_IT_SET_CONFIG_REG:
+ //DRM_INFO("R600_IT_SET_CONFIG_REG\n");
+ start_reg = (ib_chunk->kdata[offset_dw + 1] << 2) + R600_SET_CONFIG_REG_OFFSET;
+ end_reg = 4 * (num_dw - 2) + start_reg - 4;
+ if ((start_reg < R600_SET_CONFIG_REG_OFFSET) ||
+ (start_reg >= R600_SET_CONFIG_REG_END) ||
+ (end_reg >= R600_SET_CONFIG_REG_END))
+ ret = EINVAL;
+ else {
+ for (i = 0; i < (num_dw - 2); i++) {
+ reg = start_reg + (4 * i);
+ switch (reg) {
+ case R600_CP_COHER_BASE:
+ /* use R600_IT_SURFACE_SYNC */
+ ret = EINVAL;
+ break;
+ default:
+ break;
+ }
+ if (ret)
+ break;
+ }
+ }
+ if (ret)
+ DRM_ERROR("bad SET_CONFIG_REG\n");
+ break;
+ case R600_IT_SET_CONTEXT_REG:
+ //DRM_INFO("R600_IT_SET_CONTEXT_REG\n");
+ start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+ start_reg += R600_SET_CONTEXT_REG_OFFSET;
+ end_reg = 4 * (num_dw - 2) + start_reg - 4;
+ if ((start_reg < R600_SET_CONTEXT_REG_OFFSET) ||
+ (start_reg >= R600_SET_CONTEXT_REG_END) ||
+ (end_reg >= R600_SET_CONTEXT_REG_END))
+ ret = EINVAL;
+ else {
+ for (i = 0; i < (num_dw - 2); i++) {
+ reg = start_reg + (4 * i);
+ switch (reg) {
+ case R600_DB_DEPTH_BASE:
+ case R600_CB_COLOR0_BASE:
+ case R600_CB_COLOR1_BASE:
+ case R600_CB_COLOR2_BASE:
+ case R600_CB_COLOR3_BASE:
+ case R600_CB_COLOR4_BASE:
+ case R600_CB_COLOR5_BASE:
+ case R600_CB_COLOR6_BASE:
+ case R600_CB_COLOR7_BASE:
+ case R600_SQ_PGM_START_FS:
+ case R600_SQ_PGM_START_ES:
+ case R600_SQ_PGM_START_VS:
+ case R600_SQ_PGM_START_GS:
+ case R600_SQ_PGM_START_PS:
+ //DRM_INFO("reg: 0x%08x\n", reg);
+ reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 2);
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret) {
+ DRM_ERROR("bad SET_CONTEXT_REG\n");
+ break;
+ }
+ ib_chunk->kdata[offset_dw + 2 + i] +=
+ ((offset >> 8) & 0xffffffff);
+ break;
+ case R600_VGT_DMA_BASE:
+ case R600_VGT_DMA_BASE_HI:
+ /* These should be handled by DRAW_INDEX packet 3 */
+ case R600_VGT_STRMOUT_BASE_OFFSET_0:
+ case R600_VGT_STRMOUT_BASE_OFFSET_1:
+ case R600_VGT_STRMOUT_BASE_OFFSET_2:
+ case R600_VGT_STRMOUT_BASE_OFFSET_3:
+ case R600_VGT_STRMOUT_BASE_OFFSET_HI_0:
+ case R600_VGT_STRMOUT_BASE_OFFSET_HI_1:
+ case R600_VGT_STRMOUT_BASE_OFFSET_HI_2:
+ case R600_VGT_STRMOUT_BASE_OFFSET_HI_3:
+ case R600_VGT_STRMOUT_BUFFER_BASE_0:
+ case R600_VGT_STRMOUT_BUFFER_BASE_1:
+ case R600_VGT_STRMOUT_BUFFER_BASE_2:
+ case R600_VGT_STRMOUT_BUFFER_BASE_3:
+ case R600_VGT_STRMOUT_BUFFER_OFFSET_0:
+ case R600_VGT_STRMOUT_BUFFER_OFFSET_1:
+ case R600_VGT_STRMOUT_BUFFER_OFFSET_2:
+ case R600_VGT_STRMOUT_BUFFER_OFFSET_3:
+ /* These should be handled by STRMOUT_BUFFER packet 3 */
+ DRM_ERROR("bad context reg: 0x%08x\n", reg);
+ ret = EINVAL;
+ break;
+ default:
+ break;
+ }
+ if (ret)
+ break;
+ }
+ }
+ if (ret)
+ DRM_ERROR("bad SET_CONTEXT_REG\n");
+ break;
+ case R600_IT_SET_RESOURCE:
+ //DRM_INFO("R600_IT_SET_RESOURCE\n");
+ if ((num_dw - 2) % 7)
+ ret = EINVAL;
+ start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+ start_reg += R600_SET_RESOURCE_OFFSET;
+ end_reg = 4 * (num_dw - 2) + start_reg - 4;
+ if ((start_reg < R600_SET_RESOURCE_OFFSET) ||
+ (start_reg >= R600_SET_RESOURCE_END) ||
+ (end_reg >= R600_SET_RESOURCE_END))
+ ret = EINVAL;
+ else {
+ for (i = 0; i < ((num_dw - 2) / 7); i++) {
+ switch ((ib_chunk->kdata[offset_dw + (i * 7) + 6 + 2] & 0xc0000000) >> 30) {
+ case R600_SQ_TEX_VTX_INVALID_TEXTURE:
+ case R600_SQ_TEX_VTX_INVALID_BUFFER:
+ default:
+ ret = EINVAL;
+ break;
+ case R600_SQ_TEX_VTX_VALID_TEXTURE:
+ /* tex base */
+ reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 4);
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret)
+ break;
+ ib_chunk->kdata[offset_dw + (i * 7) + 2 + 2] +=
+ ((offset >> 8) & 0xffffffff);
+ /* tex mip base */
+ reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 4) + 2;
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret)
+ break;
+ ib_chunk->kdata[offset_dw + (i * 7) + 3 + 2] +=
+ ((offset >> 8) & 0xffffffff);
+ break;
+ case R600_SQ_TEX_VTX_VALID_BUFFER:
+ /* vtx base */
+ reloc = ib_chunk->kdata + offset_dw + num_dw + (i * 2);
+ ret = dev_priv->cs.relocate(parser, reloc, &offset);
+ if (ret)
+ break;
+ ib_chunk->kdata[offset_dw + (i * 7) + 0 + 2] += (offset & 0xffffffff);
+ ib_chunk->kdata[offset_dw + (i * 7) + 2 + 2] += (upper_32_bits(offset) & 0xff);
+ break;
+ }
+ if (ret)
+ break;
+ }
+ }
+ if (ret)
+ DRM_ERROR("bad SET_RESOURCE\n");
+ break;
+ case R600_IT_SET_ALU_CONST:
+ //DRM_INFO("R600_IT_SET_ALU_CONST\n");
+ start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+ start_reg += R600_SET_ALU_CONST_OFFSET;
+ end_reg = 4 * (num_dw - 2) + start_reg - 4;
+ if ((start_reg < R600_SET_ALU_CONST_OFFSET) ||
+ (start_reg >= R600_SET_ALU_CONST_END) ||
+ (end_reg >= R600_SET_ALU_CONST_END))
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad SET_ALU_CONST\n");
+ break;
+ case R600_IT_SET_BOOL_CONST:
+ //DRM_INFO("R600_IT_SET_BOOL_CONST\n");
+ start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+ start_reg += R600_SET_BOOL_CONST_OFFSET;
+ end_reg = 4 * (num_dw - 2) + start_reg - 4;
+ if ((start_reg < R600_SET_BOOL_CONST_OFFSET) ||
+ (start_reg >= R600_SET_BOOL_CONST_END) ||
+ (end_reg >= R600_SET_BOOL_CONST_END))
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad SET_BOOL_CONST\n");
+ break;
+ case R600_IT_SET_LOOP_CONST:
+ //DRM_INFO("R600_IT_SET_LOOP_CONST\n");
+ start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+ start_reg += R600_SET_LOOP_CONST_OFFSET;
+ end_reg = 4 * (num_dw - 2) + start_reg - 4;
+ if ((start_reg < R600_SET_LOOP_CONST_OFFSET) ||
+ (start_reg >= R600_SET_LOOP_CONST_END) ||
+ (end_reg >= R600_SET_LOOP_CONST_END))
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad SET_LOOP_CONST\n");
+ break;
+ case R600_IT_SET_CTL_CONST:
+ //DRM_INFO("R600_IT_SET_CTL_CONST\n");
+ start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+ start_reg += R600_SET_CTL_CONST_OFFSET;
+ end_reg = 4 * (num_dw - 2) + start_reg - 4;
+ if ((start_reg < R600_SET_CTL_CONST_OFFSET) ||
+ (start_reg >= R600_SET_CTL_CONST_END) ||
+ (end_reg >= R600_SET_CTL_CONST_END))
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad SET_CTL_CONST\n");
+ break;
+ case R600_IT_SET_SAMPLER:
+ //DRM_INFO("R600_IT_SET_SAMPLER\n");
+ if ((num_dw - 2) % 3)
+ ret = EINVAL;
+ start_reg = ib_chunk->kdata[offset_dw + 1] << 2;
+ start_reg += R600_SET_SAMPLER_OFFSET;
+ end_reg = 4 * (num_dw - 2) + start_reg - 4;
+ if ((start_reg < R600_SET_SAMPLER_OFFSET) ||
+ (start_reg >= R600_SET_SAMPLER_END) ||
+ (end_reg >= R600_SET_SAMPLER_END))
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad SET_SAMPLER\n");
+ break;
+ case R600_IT_SURFACE_BASE_UPDATE:
+ //DRM_INFO("R600_IT_SURFACE_BASE_UPDATE\n");
+ if (((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RV770) ||
+ ((dev_priv->flags & RADEON_FAMILY_MASK) == CHIP_R600))
+ ret = EINVAL;
+ if (num_dw != 2)
+ ret = EINVAL;
+ if (ret)
+ DRM_ERROR("bad SURFACE_BASE_UPDATE\n");
+ break;
+ case RADEON_CP_NOP:
+ //DRM_INFO("NOP: %d\n", ib_chunk->kdata[offset_dw + 1]);
+ break;
+ default:
+ DRM_ERROR("invalid packet 3 0x%08x\n", 0xff00);
+ ret = EINVAL;
+ break;
+ }
+
+ *offset_dw_p += incr;
+ return ret;
+}
+
+static int r600_cs_parse(struct drm_radeon_cs_parser *parser)
+{
+ struct drm_radeon_kernel_chunk *ib_chunk;
+ /* scan the packet for various things */
+ int count_dw = 0, size_dw;
+ int ret = 0;
+
+ ib_chunk = &parser->chunks[parser->ib_index];
+ size_dw = ib_chunk->length_dw;
+
+ while (count_dw < size_dw && ret == 0) {
+ int hdr = ib_chunk->kdata[count_dw];
+ int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16;
+
+ switch (hdr & RADEON_CP_PACKET_MASK) {
+ case RADEON_CP_PACKET0:
+ ret = r600_cs_packet0(parser, &count_dw);
+ break;
+ case RADEON_CP_PACKET1:
+ ret = EINVAL;
+ break;
+ case RADEON_CP_PACKET2:
+ DRM_DEBUG("Packet 2\n");
+ num_dw += 1;
+ break;
+ case RADEON_CP_PACKET3:
+ ret = r600_cs_packet3(parser, &count_dw);
+ break;
+ }
+
+ count_dw += num_dw;
+ }
+
+ if (ret)
+ return ret;
+
+
+ /* copy the packet into the IB */
+ memcpy(parser->ib, ib_chunk->kdata, ib_chunk->length_dw * sizeof(uint32_t));
+
+ /* make sure that the wc buffers are flushed before we emit */
+ DRM_MEMORYBARRIER();
+
+ return 0;
+}
+
+static uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon)
+{
+ /* FIXME: protect with a spinlock */
+ /* FIXME: check if wrap affect last reported wrap & sequence */
+ radeon->cs.id_scnt = (radeon->cs.id_scnt + 1) & 0x00FFFFFF;
+ if (!radeon->cs.id_scnt) {
+ /* increment wrap counter */
+ radeon->cs.id_wcnt += 0x01000000;
+ /* valid sequence counter start at 1 */
+ radeon->cs.id_scnt = 1;
+ }
+ return (radeon->cs.id_scnt | radeon->cs.id_wcnt);
+}
+
+static void r600_cs_id_emit(struct drm_radeon_cs_parser *parser, uint32_t *id)
+{
+ drm_radeon_private_t *dev_priv = parser->dev->dev_private;
+
+ //dev_priv->irq_emitted = radeon_update_breadcrumb(parser->dev);
+
+ *id = radeon_cs_id_get(dev_priv);
+
+ /* SCRATCH 2 */
+ BEGIN_RING(3);
+ R600_CLEAR_AGE(*id);
+ ADVANCE_RING();
+ COMMIT_RING();
+}
+
+static uint32_t r600_cs_id_last_get(struct drm_device *dev)
+{
+ //drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ //return GET_R600_SCRATCH(dev_priv, 2);
+ return 0;
+}
+
+static int r600_ib_get(struct drm_radeon_cs_parser *parser)
+{
+ struct drm_device *dev = parser->dev;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ struct drm_buf *buf;
+
+ buf = radeon_freelist_get(dev);
+ if (!buf) {
+ dev_priv->cs_buf = NULL;
+ return EBUSY;
+ }
+ buf->file_priv = parser->file_priv;
+ dev_priv->cs_buf = buf;
+ parser->ib = (void *)(dev->agp_buffer_map->handle + buf->offset);
+
+ return 0;
+}
+
+static void r600_ib_free(struct drm_radeon_cs_parser *parser, int error)
+{
+ struct drm_device *dev = parser->dev;
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+ struct drm_buf *buf = dev_priv->cs_buf;
+
+ if (buf) {
+ if (!error)
+ r600_cp_dispatch_indirect(dev, buf, 0,
+ parser->chunks[parser->ib_index].length_dw * sizeof(uint32_t));
+ radeon_cp_discard_buffer(dev, buf);
+ COMMIT_RING();
+ }
+}
+
+int r600_cs_init(struct drm_device *dev)
+{
+ drm_radeon_private_t *dev_priv = dev->dev_private;
+
+ dev_priv->cs.ib_get = r600_ib_get;
+ dev_priv->cs.ib_free = r600_ib_free;
+ dev_priv->cs.id_emit = r600_cs_id_emit;
+ dev_priv->cs.id_last_get = r600_cs_id_last_get;
+ dev_priv->cs.parse = r600_cs_parse;
+ dev_priv->cs.relocate = r600_nomm_relocate;
+ return 0;
+}
diff --git a/sys/dev/pci/drm/radeon_drv.c b/sys/dev/pci/drm/radeon_drv.c
index fd54e04f1ab..4fc6a13cb7c 100644
--- a/sys/dev/pci/drm/radeon_drv.c
+++ b/sys/dev/pci/drm/radeon_drv.c
@@ -747,6 +747,8 @@ radeondrm_ioctl(struct drm_device *dev, u_long cmd, caddr_t data,
return (radeon_surface_alloc(dev, data, file_priv));
case DRM_IOCTL_RADEON_SURF_FREE:
return (radeon_surface_free(dev, data, file_priv));
+ case DRM_IOCTL_RADEON_CS:
+ return (radeon_cs_ioctl(dev, data, file_priv));
}
}
@@ -800,10 +802,14 @@ radeondrm_write_rptr(struct drm_radeon_private *dev_priv, u_int32_t off,
u_int32_t
radeondrm_get_ring_head(struct drm_radeon_private *dev_priv)
{
- if (dev_priv->writeback_works)
+ if (dev_priv->writeback_works) {
return (radeondrm_read_rptr(dev_priv, 0));
- else
- return (RADEON_READ(RADEON_CP_RB_RPTR));
+ } else {
+ if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
+ return (RADEON_READ(R600_CP_RB_RPTR));
+ else
+ return (RADEON_READ(RADEON_CP_RB_RPTR));
+ }
}
void
diff --git a/sys/dev/pci/drm/radeon_drv.h b/sys/dev/pci/drm/radeon_drv.h
index febaa7c55f7..547889bf73f 100644
--- a/sys/dev/pci/drm/radeon_drv.h
+++ b/sys/dev/pci/drm/radeon_drv.h
@@ -140,9 +140,9 @@ enum radeon_family {
CHIP_R600,
CHIP_RV610,
CHIP_RV630,
+ CHIP_RV670,
CHIP_RV620,
CHIP_RV635,
- CHIP_RV670,
CHIP_RS780,
CHIP_RS880,
CHIP_RV770,
@@ -218,6 +218,46 @@ struct radeon_virt_surface {
struct drm_file *file_priv;
#define PCIGART_FILE_PRIV ((void *) -1L)
};
+
+struct drm_radeon_kernel_chunk {
+ uint32_t chunk_id;
+ uint32_t length_dw;
+ uint32_t __user *chunk_data;
+ uint32_t *kdata;
+};
+
+struct drm_radeon_cs_parser {
+ struct drm_device *dev;
+ struct drm_file *file_priv;
+ uint32_t num_chunks;
+ struct drm_radeon_kernel_chunk *chunks;
+ int ib_index;
+ int reloc_index;
+ uint32_t card_offset;
+ void *ib;
+};
+
+/* command submission struct */
+struct drm_radeon_cs_priv {
+ struct mutex cs_mutex;
+ uint32_t id_wcnt;
+ uint32_t id_scnt;
+ uint32_t id_last_wcnt;
+ uint32_t id_last_scnt;
+
+ int (*parse)(struct drm_radeon_cs_parser *parser);
+ void (*id_emit)(struct drm_radeon_cs_parser *parser, uint32_t *id);
+ uint32_t (*id_last_get)(struct drm_device *dev);
+ /* this ib handling callback are for hidding memory manager drm
+ * from memory manager less drm, free have to emit ib discard
+ * sequence into the ring */
+ int (*ib_get)(struct drm_radeon_cs_parser *parser);
+ uint32_t (*ib_get_ptr)(struct drm_device *dev, void *ib);
+ void (*ib_free)(struct drm_radeon_cs_parser *parser, int error);
+ /* do a relocation either MM or non-MM */
+ int (*relocate)(struct drm_radeon_cs_parser *parser,
+ uint32_t *reloc, uint64_t *offset);
+};
#define RADEON_FLUSH_EMITED (1 << 0)
#define RADEON_PURGE_EMITED (1 << 1)
@@ -329,6 +369,9 @@ typedef struct drm_radeon_private {
int r700_sc_earlyz_tile_fifo_fize;
/* r6xx/r7xx drm blit vertex buffer */
struct drm_buf *blit_vb;
+ /* CS */
+ struct drm_radeon_cs_priv cs;
+ struct drm_buf *cs_buf;
uint32_t chip_family; /* extract from flags */
} drm_radeon_private_t;
@@ -375,6 +418,7 @@ void radeondrm_out_ring_table(struct drm_radeon_private *,
u_int32_t *, int);
/* radeon_cp.c */
+u32 RADEON_READ_MM(struct drm_radeon_private *, int);
u32 radeon_read_fb_location(drm_radeon_private_t *);
void radeon_write_fb_location(drm_radeon_private_t *, u32);
void radeon_write_fb_location(drm_radeon_private_t *, u32);
@@ -467,6 +511,9 @@ void r600_blit_copy(struct drm_device *, uint64_t, uint64_t, int);
void r600_blit_swap(struct drm_device *, uint64_t, uint64_t, int, int,
int, int, int, int, int, int, int);
+int radeon_cs_ioctl(struct drm_device *, void *, struct drm_file *);
+int r600_cs_init(struct drm_device *);
+
/* Register definitions, register access macros and drmAddMap constants
* for Radeon kernel driver.
*/
@@ -669,6 +716,7 @@ void r600_blit_swap(struct drm_device *, uint64_t, uint64_t, int, int,
#define R400_GB_PIPE_SELECT 0x402c
#define RV530_GB_PIPE_SELECT2 0x4124
#define R500_DYN_SCLK_PWMEM_PIPE 0x000d /* PLL */
+#define R500_SU_REG_DEST 0x42c8
#define R300_GB_TILE_CONFIG 0x4018
# define R300_ENABLE_TILING (1 << 0)
# define R300_PIPE_COUNT_RV350 (0 << 1)
@@ -1833,8 +1881,8 @@ extern u32 radeon_get_scratch(drm_radeon_private_t *dev_priv, int index);
#define RADEON_PCIGART_TABLE_SIZE (32*1024)
-#define RADEON_READ(reg) bus_space_read_4(dev_priv->regs->bst, \
- dev_priv->regs->bsh, (reg))
+#define RADEON_READ(reg) RADEON_READ_MM(dev_priv, reg)
+
#define RADEON_WRITE(reg,val) \
do { \
if (reg < 0x10000) { \
diff --git a/sys/dev/pci/drm/radeon_irq.c b/sys/dev/pci/drm/radeon_irq.c
index 80ca577e4b9..1cdf958645c 100644
--- a/sys/dev/pci/drm/radeon_irq.c
+++ b/sys/dev/pci/drm/radeon_irq.c
@@ -196,6 +196,8 @@ radeondrm_intr(void *arg)
drm_radeon_private_t *dev_priv = dev->dev_private;
u_int32_t stat, r500_disp_int;
+ if (dev_priv->cp_running == 0)
+ return (0);
/* XXX wtf? */
if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600)
return (0);