The following diff provides the kernel support necessary for OpenGL to
work on R600 and R700 radeon chipsets.

One caveat: the drm doesn't have interrupt support yet (this
involves another firmware (making 3 per chipset for r600+) and a rather
funky ringbuffer for interrupt events (yes, this is strange). Apparently
interrupt support should not be needed.

In practise it should be possible to write interrupt support as well,
but that will take more time and may well get fiddly fast. So, for the
time being, if you pkg_add driconf and change the following two options
then it will work ok:

Method to limit rendering latency -> busy waiting for the graphics
hardware

Synchronization with vertical refresh -> never.

To test this patch you need the bits I commited just before sending this
message (if your system has libdrm_radeon then you're off to a good
start). then do the following two things:

# cd /usr/xenocara/lib/libGL/dri/r600;
# cd ../../
# make obj
# make build

then:

# cd /usr/src/sys/dev/pci/drm
# patch < path_to_patch_from_this_email

and build your kernel as normal.

tested on i386 my matthieu@ on a radeon 3650 and myself on amd64 with a
HD4870. For me at least foobillard, openarena, gears, crack-attack and
glsfcave all worked fine.

Please note that this driver isnt' as amazingly performant as it could
be. the faster stuff is based on the kms code which I still need to find
a large period of time to sit down and write.

And before anyone asks: no I can't update the current in-tree radeon
driver yet. The problem with zaphod mode dual head being utterly hosed
on some ATOMBios cards with the newer driver is still there and having
wasted hours on it I still have no idea. Anyone who needs the newer
driver to get their card to work can mail me privately if they can't
manage to get a newer driver working themselves.

test reports to myself and matthieu please.

Cheers,

-0-

Index: files.drm
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/files.drm,v
retrieving revision 1.20
diff -u -p -r1.20 files.drm
--- files.drm   25 May 2010 17:15:49 -0000      1.20
+++ files.drm   1 May 2011 19:03:57 -0000
@@ -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
Index: r600_blit.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/r600_blit.c,v
retrieving revision 1.1
diff -u -p -r1.1 r600_blit.c
--- r600_blit.c 27 Mar 2010 00:09:50 -0000      1.1
+++ r600_blit.c 1 May 2011 19:03:57 -0000
@@ -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 *d
        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 *
                                    
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;
 }
Index: radeon_cp.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/radeon_cp.c,v
retrieving revision 1.46
diff -u -p -r1.46 radeon_cp.c
--- radeon_cp.c 29 Mar 2010 00:56:00 -0000      1.46
+++ radeon_cp.c 1 May 2011 19:03:57 -0000
@@ -112,6 +112,24 @@ int        radeon_setup_pcigart_surface(drm_rad
 
 
 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;
@@ -3239,6 +3257,9 @@ radeon_do_init_cp(struct drm_device *dev
 
        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;
 }
Index: radeon_cs.c
===================================================================
RCS file: radeon_cs.c
diff -N radeon_cs.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ radeon_cs.c 1 May 2011 19:03:57 -0000
@@ -0,0 +1,858 @@
+/*-
+ * 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 <gli...@freedesktop.org>
+ */
+
+#include <sys/cdefs.h>
+/*__FBSDID("$FreeBSD: src/sys/dev/drm/radeon_cs.c,v 1.2 2009/09/28 22:41:28 
rnoland Exp $");*/
+#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;
+}
Index: radeon_drv.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/radeon_drv.c,v
retrieving revision 1.52
diff -u -p -r1.52 radeon_drv.c
--- radeon_drv.c        24 Apr 2011 03:12:05 -0000      1.52
+++ radeon_drv.c        1 May 2011 19:03:57 -0000
@@ -745,6 +745,8 @@ radeondrm_ioctl(struct drm_device *dev, 
                        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));
                }
        }
 
@@ -798,10 +800,14 @@ radeondrm_write_rptr(struct drm_radeon_p
 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
Index: radeon_drv.h
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/radeon_drv.h,v
retrieving revision 1.32
diff -u -p -r1.32 radeon_drv.h
--- radeon_drv.h        27 Mar 2010 00:09:51 -0000      1.32
+++ radeon_drv.h        2 May 2011 11:14:56 -0000
@@ -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 dr
                    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 *,
 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 *,
 #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
 
 #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) {                                    \
Index: radeon_irq.c
===================================================================
RCS file: /cvs/src/sys/dev/pci/drm/radeon_irq.c,v
retrieving revision 1.24
diff -u -p -r1.24 radeon_irq.c
--- radeon_irq.c        15 Apr 2010 19:17:48 -0000      1.24
+++ radeon_irq.c        1 May 2011 19:03:57 -0000
@@ -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);

-- 
Binary, adj.:
        Possessing the ability to have friends of both sexes.

Reply via email to