diff options
author | 2011-05-30 21:50:46 +0000 | |
---|---|---|
committer | 2011-05-30 21:50:46 +0000 | |
commit | 3d3e7161e2b12f2e1ccd3430b7dbf6bb4f9aa3bd (patch) | |
tree | fc3e7a8fa1cf3a9deea885bb6366a32788cbd740 | |
parent | for (some; stuff; here) (diff) | |
download | wireguard-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.drm | 3 | ||||
-rw-r--r-- | sys/dev/pci/drm/r600_blit.c | 95 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_cp.c | 21 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_cs.c | 856 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_drv.c | 12 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_drv.h | 54 | ||||
-rw-r--r-- | sys/dev/pci/drm/radeon_irq.c | 2 |
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); |