2 * Copyright 2008 Jerome Glisse.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice (including the next
13 * paragraph) shall be included in all copies or substantial portions of the
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
25 * Jerome Glisse <glisse@freedesktop.org>
28 #include "radeon_drm.h"
29 #include "radeon_drv.h"
32 int radeon_cs_ioctl(struct drm_device *dev, void *data, struct drm_file *fpriv)
34 struct drm_radeon_private *dev_priv = dev->dev_private;
35 struct drm_radeon_cs *cs = data;
36 uint32_t *packets = NULL;
44 /* set command stream id to 0 which is fake id */
46 DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t));
48 if (dev_priv == NULL) {
49 DRM_ERROR("called with no initialization\n");
55 /* limit cs to 64K ib */
56 if (cs->dwords > (16 * 1024)) {
59 /* copy cs from userspace maybe we should copy into ib to save
60 * one copy but ib will be mapped wc so not good for cmd checking
61 * somethings worth testing i guess (Jerome)
63 size = cs->dwords * sizeof(uint32_t);
64 packets = drm_alloc(size, DRM_MEM_DRIVER);
65 if (packets == NULL) {
68 if (DRM_COPY_FROM_USER(packets, (void __user *)(unsigned long)cs->packets, size)) {
73 r = dev_priv->cs.ib_get(dev, &ib, cs->dwords, &card_offset);
78 /* now parse command stream */
79 r = dev_priv->cs.parse(dev, fpriv, ib, packets, cs->dwords);
85 OUT_RING(CP_PACKET0(RADEON_CP_IB_BASE, 1));
86 OUT_RING(card_offset);
88 OUT_RING(CP_PACKET2());
91 /* emit cs id sequence */
92 dev_priv->cs.id_emit(dev, &cs_id);
95 DRM_COPY_TO_USER(&cs->cs_id, &cs_id, sizeof(uint32_t));
97 dev_priv->cs.ib_free(dev, ib, cs->dwords);
98 drm_free(packets, size, DRM_MEM_DRIVER);
103 static int radeon_nomm_relocate(struct drm_device *dev, struct drm_file *file_priv, uint32_t *reloc, uint32_t *offset)
109 #define RADEON_2D_OFFSET_MASK 0x3fffff
111 static __inline__ int radeon_cs_relocate_packet0(struct drm_device *dev, struct drm_file *file_priv,
112 uint32_t *packets, uint32_t offset_dw)
114 drm_radeon_private_t *dev_priv = dev->dev_private;
115 uint32_t hdr = packets[offset_dw];
116 uint32_t reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2;
117 uint32_t val = packets[offset_dw + 1];
118 uint32_t packet3_hdr = packets[offset_dw+2];
119 uint32_t tmp, offset;
122 /* this is too strict we may want to expand the length in the future and have
123 old kernels ignore it. */
124 if (packet3_hdr != (RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16))) {
125 DRM_ERROR("Packet 3 was %x should have been %x\n", packet3_hdr, RADEON_CP_PACKET3 | RADEON_CP_NOP | (RELOC_SIZE << 16));
130 case RADEON_DST_PITCH_OFFSET:
131 case RADEON_SRC_PITCH_OFFSET:
132 /* pass in the start of the reloc */
133 ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset);
136 tmp = (val & RADEON_2D_OFFSET_MASK) << 10;
137 val &= ~RADEON_2D_OFFSET_MASK;
142 case R300_RB3D_COLOROFFSET0:
143 case R300_ZB_DEPTHOFFSET:
144 case R300_TX_OFFSET_0:
145 case R300_TX_OFFSET_0+4:
146 ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + 2, &offset);
150 offset &= 0xffffffe0;
157 packets[offset_dw + 1] = val;
161 static int radeon_cs_relocate_packet3(struct drm_device *dev, struct drm_file *file_priv,
162 uint32_t *packets, uint32_t offset_dw)
164 drm_radeon_private_t *dev_priv = dev->dev_private;
165 uint32_t hdr = packets[offset_dw];
166 int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16;
167 uint32_t reg = hdr & 0xff00;
168 uint32_t offset, val, tmp;
172 case RADEON_CNTL_HOSTDATA_BLT:
174 val = packets[offset_dw + 2];
175 ret = dev_priv->cs.relocate(dev, file_priv, packets + offset_dw + num_dw + 2, &offset);
179 tmp = (val & RADEON_2D_OFFSET_MASK) << 10;
180 val &= ~RADEON_2D_OFFSET_MASK;
185 packets[offset_dw + 2] = val;
193 static __inline__ int radeon_cs_check_offset(struct drm_device *dev,
194 uint32_t reg, uint32_t val)
199 case RADEON_DST_PITCH_OFFSET:
200 case RADEON_SRC_PITCH_OFFSET:
201 offset = val & ((1 << 22) - 1);
204 case R300_RB3D_COLOROFFSET0:
205 case R300_ZB_DEPTHOFFSET:
208 case R300_TX_OFFSET_0:
209 case R300_TX_OFFSET_0+4:
210 offset = val & 0xffffffe0;
217 int radeon_cs_packet0(struct drm_device *dev, struct drm_file *file_priv,
218 uint32_t *packets, uint32_t offset_dw)
220 drm_radeon_private_t *dev_priv = dev->dev_private;
221 uint32_t hdr = packets[offset_dw];
222 int num_dw = ((hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16) + 2;
224 int reg = (hdr & R300_CP_PACKET0_REG_MASK) << 2;
228 while (count_dw < num_dw) {
229 /* need to have something like the r300 validation here -
230 list of allowed registers */
233 ret = r300_check_range(reg, 1);
236 DRM_ERROR("Illegal register %x\n", reg);
241 flags = r300_get_reg_flags(reg);
242 if (flags == MARK_CHECK_OFFSET) {
244 DRM_ERROR("Cannot relocate inside type stream of reg0 packets\n");
248 ret = radeon_cs_relocate_packet0(dev, file_priv, packets, offset_dw);
251 DRM_DEBUG("need to relocate %x %d\n", reg, flags);
252 /* okay it should be followed by a NOP */
253 } else if (flags == MARK_CHECK_SCISSOR) {
254 DRM_DEBUG("need to validate scissor %x %d\n", reg, flags);
256 DRM_DEBUG("illegal register %x %d\n", reg, flags);
267 int radeon_cs_parse(struct drm_device *dev, struct drm_file *file_priv,
268 void *ib, uint32_t *packets, uint32_t dwords)
270 drm_radeon_private_t *dev_priv = dev->dev_private;
272 int size_dw = dwords;
273 /* scan the packet for various things */
277 while (count_dw < size_dw && ret == 0) {
278 int hdr = packets[count_dw];
279 int num_dw = (hdr & RADEON_CP_PACKET_COUNT_MASK) >> 16;
282 switch (hdr & RADEON_CP_PACKET_MASK) {
283 case RADEON_CP_PACKET0:
284 ret = radeon_cs_packet0(dev, file_priv, packets, count_dw);
286 case RADEON_CP_PACKET1:
287 case RADEON_CP_PACKET2:
288 reg = hdr & RADEON_CP_PACKET0_REG_MASK;
289 DRM_DEBUG("Packet 1/2: %d %x\n", num_dw, reg);
292 case RADEON_CP_PACKET3:
296 case RADEON_CNTL_HOSTDATA_BLT:
297 radeon_cs_relocate_packet3(dev, file_priv, packets, count_dw);
300 case RADEON_CNTL_BITBLT_MULTI:
301 case RADEON_3D_LOAD_VBPNTR: /* load vertex array pointers */
302 case RADEON_CP_INDX_BUFFER:
303 DRM_ERROR("need relocate packet 3 for %x\n", reg);
306 case RADEON_CP_3D_DRAW_IMMD_2: /* triggers drawing using in-packet vertex data */
307 case RADEON_CP_3D_DRAW_VBUF_2: /* triggers drawing of vertex buffers setup elsewhere */
308 case RADEON_CP_3D_DRAW_INDX_2: /* triggers drawing using indices to vertex buffer */
309 case RADEON_WAIT_FOR_IDLE:
313 DRM_ERROR("unknown packet 3 %x\n", reg);
319 count_dw += num_dw+2;
326 /* copy the packet into the IB */
327 memcpy(ib, packets, dwords * sizeof(uint32_t));
329 /* read back last byte to flush WC buffers */
330 rb = readl((ib + (dwords-1) * sizeof(uint32_t)));
335 uint32_t radeon_cs_id_get(struct drm_radeon_private *radeon)
337 /* FIXME: protect with a spinlock */
338 /* FIXME: check if wrap affect last reported wrap & sequence */
339 radeon->cs.id_scnt = (radeon->cs.id_scnt + 1) & 0x00FFFFFF;
340 if (!radeon->cs.id_scnt) {
341 /* increment wrap counter */
342 radeon->cs.id_wcnt += 0x01000000;
343 /* valid sequence counter start at 1 */
344 radeon->cs.id_scnt = 1;
346 return (radeon->cs.id_scnt | radeon->cs.id_wcnt);
349 void r100_cs_id_emit(struct drm_device *dev, uint32_t *id)
351 drm_radeon_private_t *dev_priv = dev->dev_private;
354 /* ISYNC_CNTL should have CPSCRACTH bit set */
355 *id = radeon_cs_id_get(dev_priv);
356 /* emit id in SCRATCH4 (not used yet in old drm) */
358 OUT_RING(CP_PACKET0(RADEON_SCRATCH_REG4, 0));
363 void r300_cs_id_emit(struct drm_device *dev, uint32_t *id)
365 drm_radeon_private_t *dev_priv = dev->dev_private;
368 /* ISYNC_CNTL should not have CPSCRACTH bit set */
369 *id = radeon_cs_id_get(dev_priv);
370 /* emit id in SCRATCH6 */
372 OUT_RING(CP_PACKET0(R300_CP_RESYNC_ADDR, 0));
374 OUT_RING(CP_PACKET0(R300_CP_RESYNC_DATA, 0));
376 OUT_RING(CP_PACKET0(R300_RB3D_DSTCACHE_CTLSTAT, 0));
377 OUT_RING(R300_RB3D_DC_FINISH);
378 RADEON_WAIT_UNTIL_3D_IDLE();
382 uint32_t r100_cs_id_last_get(struct drm_device *dev)
384 drm_radeon_private_t *dev_priv = dev->dev_private;
386 return RADEON_READ(RADEON_SCRATCH_REG4);
389 uint32_t r300_cs_id_last_get(struct drm_device *dev)
391 drm_radeon_private_t *dev_priv = dev->dev_private;
393 return RADEON_READ(RADEON_SCRATCH_REG6);
396 int radeon_cs_init(struct drm_device *dev)
398 drm_radeon_private_t *dev_priv = dev->dev_private;
400 if (dev_priv->chip_family < CHIP_RV280) {
401 dev_priv->cs.id_emit = r100_cs_id_emit;
402 dev_priv->cs.id_last_get = r100_cs_id_last_get;
403 } else if (dev_priv->chip_family < CHIP_R600) {
404 dev_priv->cs.id_emit = r300_cs_id_emit;
405 dev_priv->cs.id_last_get = r300_cs_id_last_get;
408 dev_priv->cs.parse = radeon_cs_parse;
409 /* ib get depends on memory manager or not so memory manager */
410 dev_priv->cs.relocate = radeon_nomm_relocate;