aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/savage_state.c
diff options
context:
space:
mode:
authorJeff Garzik <jgarzik@pobox.com>2005-09-01 18:02:27 -0400
committerJeff Garzik <jgarzik@pobox.com>2005-09-01 18:02:27 -0400
commitceeec3dc375e3b0618f16b34efc56fe093918f8b (patch)
tree2293d02721ee05131aaf1c60e4fba7e281585eec /drivers/char/drm/savage_state.c
parentfbff868db3a4cc6a89d51da9a6d49b26c29d04fb (diff)
parente3ee3b78f83688a0ae4315e8be71b2eac559904a (diff)
/spare/repo/netdev-2.6 branch 'ieee80211'
Diffstat (limited to 'drivers/char/drm/savage_state.c')
-rw-r--r--drivers/char/drm/savage_state.c1146
1 files changed, 1146 insertions, 0 deletions
diff --git a/drivers/char/drm/savage_state.c b/drivers/char/drm/savage_state.c
new file mode 100644
index 000000000000..475695a00083
--- /dev/null
+++ b/drivers/char/drm/savage_state.c
@@ -0,0 +1,1146 @@
1/* savage_state.c -- State and drawing support for Savage
2 *
3 * Copyright 2004 Felix Kuehling
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sub license,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NON-INFRINGEMENT. IN NO EVENT SHALL FELIX KUEHLING BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
22 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25#include "drmP.h"
26#include "savage_drm.h"
27#include "savage_drv.h"
28
29void savage_emit_clip_rect_s3d(drm_savage_private_t *dev_priv,
30 drm_clip_rect_t *pbox)
31{
32 uint32_t scstart = dev_priv->state.s3d.new_scstart;
33 uint32_t scend = dev_priv->state.s3d.new_scend;
34 scstart = (scstart & ~SAVAGE_SCISSOR_MASK_S3D) |
35 ((uint32_t)pbox->x1 & 0x000007ff) |
36 (((uint32_t)pbox->y1 << 16) & 0x07ff0000);
37 scend = (scend & ~SAVAGE_SCISSOR_MASK_S3D) |
38 (((uint32_t)pbox->x2-1) & 0x000007ff) |
39 ((((uint32_t)pbox->y2-1) << 16) & 0x07ff0000);
40 if (scstart != dev_priv->state.s3d.scstart ||
41 scend != dev_priv->state.s3d.scend) {
42 DMA_LOCALS;
43 BEGIN_DMA(4);
44 DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D);
45 DMA_SET_REGISTERS(SAVAGE_SCSTART_S3D, 2);
46 DMA_WRITE(scstart);
47 DMA_WRITE(scend);
48 dev_priv->state.s3d.scstart = scstart;
49 dev_priv->state.s3d.scend = scend;
50 dev_priv->waiting = 1;
51 DMA_COMMIT();
52 }
53}
54
55void savage_emit_clip_rect_s4(drm_savage_private_t *dev_priv,
56 drm_clip_rect_t *pbox)
57{
58 uint32_t drawctrl0 = dev_priv->state.s4.new_drawctrl0;
59 uint32_t drawctrl1 = dev_priv->state.s4.new_drawctrl1;
60 drawctrl0 = (drawctrl0 & ~SAVAGE_SCISSOR_MASK_S4) |
61 ((uint32_t)pbox->x1 & 0x000007ff) |
62 (((uint32_t)pbox->y1 << 12) & 0x00fff000);
63 drawctrl1 = (drawctrl1 & ~SAVAGE_SCISSOR_MASK_S4) |
64 (((uint32_t)pbox->x2-1) & 0x000007ff) |
65 ((((uint32_t)pbox->y2-1) << 12) & 0x00fff000);
66 if (drawctrl0 != dev_priv->state.s4.drawctrl0 ||
67 drawctrl1 != dev_priv->state.s4.drawctrl1) {
68 DMA_LOCALS;
69 BEGIN_DMA(4);
70 DMA_WRITE(BCI_CMD_WAIT|BCI_CMD_WAIT_3D);
71 DMA_SET_REGISTERS(SAVAGE_DRAWCTRL0_S4, 2);
72 DMA_WRITE(drawctrl0);
73 DMA_WRITE(drawctrl1);
74 dev_priv->state.s4.drawctrl0 = drawctrl0;
75 dev_priv->state.s4.drawctrl1 = drawctrl1;
76 dev_priv->waiting = 1;
77 DMA_COMMIT();
78 }
79}
80
81static int savage_verify_texaddr(drm_savage_private_t *dev_priv, int unit,
82 uint32_t addr)
83{
84 if ((addr & 6) != 2) { /* reserved bits */
85 DRM_ERROR("bad texAddr%d %08x (reserved bits)\n", unit, addr);
86 return DRM_ERR(EINVAL);
87 }
88 if (!(addr & 1)) { /* local */
89 addr &= ~7;
90 if (addr < dev_priv->texture_offset ||
91 addr >= dev_priv->texture_offset+dev_priv->texture_size) {
92 DRM_ERROR("bad texAddr%d %08x (local addr out of range)\n",
93 unit, addr);
94 return DRM_ERR(EINVAL);
95 }
96 } else { /* AGP */
97 if (!dev_priv->agp_textures) {
98 DRM_ERROR("bad texAddr%d %08x (AGP not available)\n",
99 unit, addr);
100 return DRM_ERR(EINVAL);
101 }
102 addr &= ~7;
103 if (addr < dev_priv->agp_textures->offset ||
104 addr >= (dev_priv->agp_textures->offset +
105 dev_priv->agp_textures->size)) {
106 DRM_ERROR("bad texAddr%d %08x (AGP addr out of range)\n",
107 unit, addr);
108 return DRM_ERR(EINVAL);
109 }
110 }
111 return 0;
112}
113
114#define SAVE_STATE(reg,where) \
115 if(start <= reg && start+count > reg) \
116 DRM_GET_USER_UNCHECKED(dev_priv->state.where, &regs[reg-start])
117#define SAVE_STATE_MASK(reg,where,mask) do { \
118 if(start <= reg && start+count > reg) { \
119 uint32_t tmp; \
120 DRM_GET_USER_UNCHECKED(tmp, &regs[reg-start]); \
121 dev_priv->state.where = (tmp & (mask)) | \
122 (dev_priv->state.where & ~(mask)); \
123 } \
124} while (0)
125static int savage_verify_state_s3d(drm_savage_private_t *dev_priv,
126 unsigned int start, unsigned int count,
127 const uint32_t __user *regs)
128{
129 if (start < SAVAGE_TEXPALADDR_S3D ||
130 start+count-1 > SAVAGE_DESTTEXRWWATERMARK_S3D) {
131 DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
132 start, start+count-1);
133 return DRM_ERR(EINVAL);
134 }
135
136 SAVE_STATE_MASK(SAVAGE_SCSTART_S3D, s3d.new_scstart,
137 ~SAVAGE_SCISSOR_MASK_S3D);
138 SAVE_STATE_MASK(SAVAGE_SCEND_S3D, s3d.new_scend,
139 ~SAVAGE_SCISSOR_MASK_S3D);
140
141 /* if any texture regs were changed ... */
142 if (start <= SAVAGE_TEXCTRL_S3D &&
143 start+count > SAVAGE_TEXPALADDR_S3D) {
144 /* ... check texture state */
145 SAVE_STATE(SAVAGE_TEXCTRL_S3D, s3d.texctrl);
146 SAVE_STATE(SAVAGE_TEXADDR_S3D, s3d.texaddr);
147 if (dev_priv->state.s3d.texctrl & SAVAGE_TEXCTRL_TEXEN_MASK)
148 return savage_verify_texaddr(
149 dev_priv, 0, dev_priv->state.s3d.texaddr);
150 }
151
152 return 0;
153}
154
155static int savage_verify_state_s4(drm_savage_private_t *dev_priv,
156 unsigned int start, unsigned int count,
157 const uint32_t __user *regs)
158{
159 int ret = 0;
160
161 if (start < SAVAGE_DRAWLOCALCTRL_S4 ||
162 start+count-1 > SAVAGE_TEXBLENDCOLOR_S4) {
163 DRM_ERROR("invalid register range (0x%04x-0x%04x)\n",
164 start, start+count-1);
165 return DRM_ERR(EINVAL);
166 }
167
168 SAVE_STATE_MASK(SAVAGE_DRAWCTRL0_S4, s4.new_drawctrl0,
169 ~SAVAGE_SCISSOR_MASK_S4);
170 SAVE_STATE_MASK(SAVAGE_DRAWCTRL1_S4, s4.new_drawctrl1,
171 ~SAVAGE_SCISSOR_MASK_S4);
172
173 /* if any texture regs were changed ... */
174 if (start <= SAVAGE_TEXDESCR_S4 &&
175 start+count > SAVAGE_TEXPALADDR_S4) {
176 /* ... check texture state */
177 SAVE_STATE(SAVAGE_TEXDESCR_S4, s4.texdescr);
178 SAVE_STATE(SAVAGE_TEXADDR0_S4, s4.texaddr0);
179 SAVE_STATE(SAVAGE_TEXADDR1_S4, s4.texaddr1);
180 if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX0EN_MASK)
181 ret |= savage_verify_texaddr(
182 dev_priv, 0, dev_priv->state.s4.texaddr0);
183 if (dev_priv->state.s4.texdescr & SAVAGE_TEXDESCR_TEX1EN_MASK)
184 ret |= savage_verify_texaddr(
185 dev_priv, 1, dev_priv->state.s4.texaddr1);
186 }
187
188 return ret;
189}
190#undef SAVE_STATE
191#undef SAVE_STATE_MASK
192
193static int savage_dispatch_state(drm_savage_private_t *dev_priv,
194 const drm_savage_cmd_header_t *cmd_header,
195 const uint32_t __user *regs)
196{
197 unsigned int count = cmd_header->state.count;
198 unsigned int start = cmd_header->state.start;
199 unsigned int count2 = 0;
200 unsigned int bci_size;
201 int ret;
202 DMA_LOCALS;
203
204 if (!count)
205 return 0;
206
207 if (DRM_VERIFYAREA_READ(regs, count*4))
208 return DRM_ERR(EFAULT);
209
210 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
211 ret = savage_verify_state_s3d(dev_priv, start, count, regs);
212 if (ret != 0)
213 return ret;
214 /* scissor regs are emitted in savage_dispatch_draw */
215 if (start < SAVAGE_SCSTART_S3D) {
216 if (start+count > SAVAGE_SCEND_S3D+1)
217 count2 = count - (SAVAGE_SCEND_S3D+1 - start);
218 if (start+count > SAVAGE_SCSTART_S3D)
219 count = SAVAGE_SCSTART_S3D - start;
220 } else if (start <= SAVAGE_SCEND_S3D) {
221 if (start+count > SAVAGE_SCEND_S3D+1) {
222 count -= SAVAGE_SCEND_S3D+1 - start;
223 start = SAVAGE_SCEND_S3D+1;
224 } else
225 return 0;
226 }
227 } else {
228 ret = savage_verify_state_s4(dev_priv, start, count, regs);
229 if (ret != 0)
230 return ret;
231 /* scissor regs are emitted in savage_dispatch_draw */
232 if (start < SAVAGE_DRAWCTRL0_S4) {
233 if (start+count > SAVAGE_DRAWCTRL1_S4+1)
234 count2 = count - (SAVAGE_DRAWCTRL1_S4+1 - start);
235 if (start+count > SAVAGE_DRAWCTRL0_S4)
236 count = SAVAGE_DRAWCTRL0_S4 - start;
237 } else if (start <= SAVAGE_DRAWCTRL1_S4) {
238 if (start+count > SAVAGE_DRAWCTRL1_S4+1) {
239 count -= SAVAGE_DRAWCTRL1_S4+1 - start;
240 start = SAVAGE_DRAWCTRL1_S4+1;
241 } else
242 return 0;
243 }
244 }
245
246 bci_size = count + (count+254)/255 + count2 + (count2+254)/255;
247
248 if (cmd_header->state.global) {
249 BEGIN_DMA(bci_size+1);
250 DMA_WRITE(BCI_CMD_WAIT | BCI_CMD_WAIT_3D);
251 dev_priv->waiting = 1;
252 } else {
253 BEGIN_DMA(bci_size);
254 }
255
256 do {
257 while (count > 0) {
258 unsigned int n = count < 255 ? count : 255;
259 DMA_SET_REGISTERS(start, n);
260 DMA_COPY_FROM_USER(regs, n);
261 count -= n;
262 start += n;
263 regs += n;
264 }
265 start += 2;
266 regs += 2;
267 count = count2;
268 count2 = 0;
269 } while (count);
270
271 DMA_COMMIT();
272
273 return 0;
274}
275
276static int savage_dispatch_dma_prim(drm_savage_private_t *dev_priv,
277 const drm_savage_cmd_header_t *cmd_header,
278 const drm_buf_t *dmabuf)
279{
280 unsigned char reorder = 0;
281 unsigned int prim = cmd_header->prim.prim;
282 unsigned int skip = cmd_header->prim.skip;
283 unsigned int n = cmd_header->prim.count;
284 unsigned int start = cmd_header->prim.start;
285 unsigned int i;
286 BCI_LOCALS;
287
288 if (!dmabuf) {
289 DRM_ERROR("called without dma buffers!\n");
290 return DRM_ERR(EINVAL);
291 }
292
293 if (!n)
294 return 0;
295
296 switch (prim) {
297 case SAVAGE_PRIM_TRILIST_201:
298 reorder = 1;
299 prim = SAVAGE_PRIM_TRILIST;
300 case SAVAGE_PRIM_TRILIST:
301 if (n % 3 != 0) {
302 DRM_ERROR("wrong number of vertices %u in TRILIST\n",
303 n);
304 return DRM_ERR(EINVAL);
305 }
306 break;
307 case SAVAGE_PRIM_TRISTRIP:
308 case SAVAGE_PRIM_TRIFAN:
309 if (n < 3) {
310 DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",
311 n);
312 return DRM_ERR(EINVAL);
313 }
314 break;
315 default:
316 DRM_ERROR("invalid primitive type %u\n", prim);
317 return DRM_ERR(EINVAL);
318 }
319
320 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
321 if (skip != 0) {
322 DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
323 skip);
324 return DRM_ERR(EINVAL);
325 }
326 } else {
327 unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
328 (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
329 (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
330 if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
331 DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
332 skip);
333 return DRM_ERR(EINVAL);
334 }
335 if (reorder) {
336 DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
337 return DRM_ERR(EINVAL);
338 }
339 }
340
341 if (start + n > dmabuf->total/32) {
342 DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
343 start, start + n - 1, dmabuf->total/32);
344 return DRM_ERR(EINVAL);
345 }
346
347 /* Vertex DMA doesn't work with command DMA at the same time,
348 * so we use BCI_... to submit commands here. Flush buffered
349 * faked DMA first. */
350 DMA_FLUSH();
351
352 if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
353 BEGIN_BCI(2);
354 BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
355 BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
356 dev_priv->state.common.vbaddr = dmabuf->bus_address;
357 }
358 if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
359 /* Workaround for what looks like a hardware bug. If a
360 * WAIT_3D_IDLE was emitted some time before the
361 * indexed drawing command then the engine will lock
362 * up. There are two known workarounds:
363 * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
364 BEGIN_BCI(63);
365 for (i = 0; i < 63; ++i)
366 BCI_WRITE(BCI_CMD_WAIT);
367 dev_priv->waiting = 0;
368 }
369
370 prim <<= 25;
371 while (n != 0) {
372 /* Can emit up to 255 indices (85 triangles) at once. */
373 unsigned int count = n > 255 ? 255 : n;
374 if (reorder) {
375 /* Need to reorder indices for correct flat
376 * shading while preserving the clock sense
377 * for correct culling. Only on Savage3D. */
378 int reorder[3] = {-1, -1, -1};
379 reorder[start%3] = 2;
380
381 BEGIN_BCI((count+1+1)/2);
382 BCI_DRAW_INDICES_S3D(count, prim, start+2);
383
384 for (i = start+1; i+1 < start+count; i += 2)
385 BCI_WRITE((i + reorder[i % 3]) |
386 ((i+1 + reorder[(i+1) % 3]) << 16));
387 if (i < start+count)
388 BCI_WRITE(i + reorder[i%3]);
389 } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
390 BEGIN_BCI((count+1+1)/2);
391 BCI_DRAW_INDICES_S3D(count, prim, start);
392
393 for (i = start+1; i+1 < start+count; i += 2)
394 BCI_WRITE(i | ((i+1) << 16));
395 if (i < start+count)
396 BCI_WRITE(i);
397 } else {
398 BEGIN_BCI((count+2+1)/2);
399 BCI_DRAW_INDICES_S4(count, prim, skip);
400
401 for (i = start; i+1 < start+count; i += 2)
402 BCI_WRITE(i | ((i+1) << 16));
403 if (i < start+count)
404 BCI_WRITE(i);
405 }
406
407 start += count;
408 n -= count;
409
410 prim |= BCI_CMD_DRAW_CONT;
411 }
412
413 return 0;
414}
415
416static int savage_dispatch_vb_prim(drm_savage_private_t *dev_priv,
417 const drm_savage_cmd_header_t *cmd_header,
418 const uint32_t __user *vtxbuf,
419 unsigned int vb_size,
420 unsigned int vb_stride)
421{
422 unsigned char reorder = 0;
423 unsigned int prim = cmd_header->prim.prim;
424 unsigned int skip = cmd_header->prim.skip;
425 unsigned int n = cmd_header->prim.count;
426 unsigned int start = cmd_header->prim.start;
427 unsigned int vtx_size;
428 unsigned int i;
429 DMA_LOCALS;
430
431 if (!n)
432 return 0;
433
434 switch (prim) {
435 case SAVAGE_PRIM_TRILIST_201:
436 reorder = 1;
437 prim = SAVAGE_PRIM_TRILIST;
438 case SAVAGE_PRIM_TRILIST:
439 if (n % 3 != 0) {
440 DRM_ERROR("wrong number of vertices %u in TRILIST\n",
441 n);
442 return DRM_ERR(EINVAL);
443 }
444 break;
445 case SAVAGE_PRIM_TRISTRIP:
446 case SAVAGE_PRIM_TRIFAN:
447 if (n < 3) {
448 DRM_ERROR("wrong number of vertices %u in TRIFAN/STRIP\n",
449 n);
450 return DRM_ERR(EINVAL);
451 }
452 break;
453 default:
454 DRM_ERROR("invalid primitive type %u\n", prim);
455 return DRM_ERR(EINVAL);
456 }
457
458 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
459 if (skip > SAVAGE_SKIP_ALL_S3D) {
460 DRM_ERROR("invalid skip flags 0x%04x\n", skip);
461 return DRM_ERR(EINVAL);
462 }
463 vtx_size = 8; /* full vertex */
464 } else {
465 if (skip > SAVAGE_SKIP_ALL_S4) {
466 DRM_ERROR("invalid skip flags 0x%04x\n", skip);
467 return DRM_ERR(EINVAL);
468 }
469 vtx_size = 10; /* full vertex */
470 }
471
472 vtx_size -= (skip & 1) + (skip >> 1 & 1) +
473 (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
474 (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
475
476 if (vtx_size > vb_stride) {
477 DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
478 vtx_size, vb_stride);
479 return DRM_ERR(EINVAL);
480 }
481
482 if (start + n > vb_size / (vb_stride*4)) {
483 DRM_ERROR("vertex indices (%u-%u) out of range (0-%u)\n",
484 start, start + n - 1, vb_size / (vb_stride*4));
485 return DRM_ERR(EINVAL);
486 }
487
488 prim <<= 25;
489 while (n != 0) {
490 /* Can emit up to 255 vertices (85 triangles) at once. */
491 unsigned int count = n > 255 ? 255 : n;
492 if (reorder) {
493 /* Need to reorder vertices for correct flat
494 * shading while preserving the clock sense
495 * for correct culling. Only on Savage3D. */
496 int reorder[3] = {-1, -1, -1};
497 reorder[start%3] = 2;
498
499 BEGIN_DMA(count*vtx_size+1);
500 DMA_DRAW_PRIMITIVE(count, prim, skip);
501
502 for (i = start; i < start+count; ++i) {
503 unsigned int j = i + reorder[i % 3];
504 DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
505 vtx_size);
506 }
507
508 DMA_COMMIT();
509 } else {
510 BEGIN_DMA(count*vtx_size+1);
511 DMA_DRAW_PRIMITIVE(count, prim, skip);
512
513 if (vb_stride == vtx_size) {
514 DMA_COPY_FROM_USER(&vtxbuf[vb_stride*start],
515 vtx_size*count);
516 } else {
517 for (i = start; i < start+count; ++i) {
518 DMA_COPY_FROM_USER(
519 &vtxbuf[vb_stride*i],
520 vtx_size);
521 }
522 }
523
524 DMA_COMMIT();
525 }
526
527 start += count;
528 n -= count;
529
530 prim |= BCI_CMD_DRAW_CONT;
531 }
532
533 return 0;
534}
535
536static int savage_dispatch_dma_idx(drm_savage_private_t *dev_priv,
537 const drm_savage_cmd_header_t *cmd_header,
538 const uint16_t __user *usr_idx,
539 const drm_buf_t *dmabuf)
540{
541 unsigned char reorder = 0;
542 unsigned int prim = cmd_header->idx.prim;
543 unsigned int skip = cmd_header->idx.skip;
544 unsigned int n = cmd_header->idx.count;
545 unsigned int i;
546 BCI_LOCALS;
547
548 if (!dmabuf) {
549 DRM_ERROR("called without dma buffers!\n");
550 return DRM_ERR(EINVAL);
551 }
552
553 if (!n)
554 return 0;
555
556 switch (prim) {
557 case SAVAGE_PRIM_TRILIST_201:
558 reorder = 1;
559 prim = SAVAGE_PRIM_TRILIST;
560 case SAVAGE_PRIM_TRILIST:
561 if (n % 3 != 0) {
562 DRM_ERROR("wrong number of indices %u in TRILIST\n",
563 n);
564 return DRM_ERR(EINVAL);
565 }
566 break;
567 case SAVAGE_PRIM_TRISTRIP:
568 case SAVAGE_PRIM_TRIFAN:
569 if (n < 3) {
570 DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",
571 n);
572 return DRM_ERR(EINVAL);
573 }
574 break;
575 default:
576 DRM_ERROR("invalid primitive type %u\n", prim);
577 return DRM_ERR(EINVAL);
578 }
579
580 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
581 if (skip != 0) {
582 DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
583 skip);
584 return DRM_ERR(EINVAL);
585 }
586 } else {
587 unsigned int size = 10 - (skip & 1) - (skip >> 1 & 1) -
588 (skip >> 2 & 1) - (skip >> 3 & 1) - (skip >> 4 & 1) -
589 (skip >> 5 & 1) - (skip >> 6 & 1) - (skip >> 7 & 1);
590 if (skip > SAVAGE_SKIP_ALL_S4 || size != 8) {
591 DRM_ERROR("invalid skip flags 0x%04x for DMA\n",
592 skip);
593 return DRM_ERR(EINVAL);
594 }
595 if (reorder) {
596 DRM_ERROR("TRILIST_201 used on Savage4 hardware\n");
597 return DRM_ERR(EINVAL);
598 }
599 }
600
601 /* Vertex DMA doesn't work with command DMA at the same time,
602 * so we use BCI_... to submit commands here. Flush buffered
603 * faked DMA first. */
604 DMA_FLUSH();
605
606 if (dmabuf->bus_address != dev_priv->state.common.vbaddr) {
607 BEGIN_BCI(2);
608 BCI_SET_REGISTERS(SAVAGE_VERTBUFADDR, 1);
609 BCI_WRITE(dmabuf->bus_address | dev_priv->dma_type);
610 dev_priv->state.common.vbaddr = dmabuf->bus_address;
611 }
612 if (S3_SAVAGE3D_SERIES(dev_priv->chipset) && dev_priv->waiting) {
613 /* Workaround for what looks like a hardware bug. If a
614 * WAIT_3D_IDLE was emitted some time before the
615 * indexed drawing command then the engine will lock
616 * up. There are two known workarounds:
617 * WAIT_IDLE_EMPTY or emit at least 63 NOPs. */
618 BEGIN_BCI(63);
619 for (i = 0; i < 63; ++i)
620 BCI_WRITE(BCI_CMD_WAIT);
621 dev_priv->waiting = 0;
622 }
623
624 prim <<= 25;
625 while (n != 0) {
626 /* Can emit up to 255 indices (85 triangles) at once. */
627 unsigned int count = n > 255 ? 255 : n;
628 /* Is it ok to allocate 510 bytes on the stack in an ioctl? */
629 uint16_t idx[255];
630
631 /* Copy and check indices */
632 DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count*2);
633 for (i = 0; i < count; ++i) {
634 if (idx[i] > dmabuf->total/32) {
635 DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
636 i, idx[i], dmabuf->total/32);
637 return DRM_ERR(EINVAL);
638 }
639 }
640
641 if (reorder) {
642 /* Need to reorder indices for correct flat
643 * shading while preserving the clock sense
644 * for correct culling. Only on Savage3D. */
645 int reorder[3] = {2, -1, -1};
646
647 BEGIN_BCI((count+1+1)/2);
648 BCI_DRAW_INDICES_S3D(count, prim, idx[2]);
649
650 for (i = 1; i+1 < count; i += 2)
651 BCI_WRITE(idx[i + reorder[i % 3]] |
652 (idx[i+1 + reorder[(i+1) % 3]] << 16));
653 if (i < count)
654 BCI_WRITE(idx[i + reorder[i%3]]);
655 } else if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
656 BEGIN_BCI((count+1+1)/2);
657 BCI_DRAW_INDICES_S3D(count, prim, idx[0]);
658
659 for (i = 1; i+1 < count; i += 2)
660 BCI_WRITE(idx[i] | (idx[i+1] << 16));
661 if (i < count)
662 BCI_WRITE(idx[i]);
663 } else {
664 BEGIN_BCI((count+2+1)/2);
665 BCI_DRAW_INDICES_S4(count, prim, skip);
666
667 for (i = 0; i+1 < count; i += 2)
668 BCI_WRITE(idx[i] | (idx[i+1] << 16));
669 if (i < count)
670 BCI_WRITE(idx[i]);
671 }
672
673 usr_idx += count;
674 n -= count;
675
676 prim |= BCI_CMD_DRAW_CONT;
677 }
678
679 return 0;
680}
681
682static int savage_dispatch_vb_idx(drm_savage_private_t *dev_priv,
683 const drm_savage_cmd_header_t *cmd_header,
684 const uint16_t __user *usr_idx,
685 const uint32_t __user *vtxbuf,
686 unsigned int vb_size,
687 unsigned int vb_stride)
688{
689 unsigned char reorder = 0;
690 unsigned int prim = cmd_header->idx.prim;
691 unsigned int skip = cmd_header->idx.skip;
692 unsigned int n = cmd_header->idx.count;
693 unsigned int vtx_size;
694 unsigned int i;
695 DMA_LOCALS;
696
697 if (!n)
698 return 0;
699
700 switch (prim) {
701 case SAVAGE_PRIM_TRILIST_201:
702 reorder = 1;
703 prim = SAVAGE_PRIM_TRILIST;
704 case SAVAGE_PRIM_TRILIST:
705 if (n % 3 != 0) {
706 DRM_ERROR("wrong number of indices %u in TRILIST\n",
707 n);
708 return DRM_ERR(EINVAL);
709 }
710 break;
711 case SAVAGE_PRIM_TRISTRIP:
712 case SAVAGE_PRIM_TRIFAN:
713 if (n < 3) {
714 DRM_ERROR("wrong number of indices %u in TRIFAN/STRIP\n",
715 n);
716 return DRM_ERR(EINVAL);
717 }
718 break;
719 default:
720 DRM_ERROR("invalid primitive type %u\n", prim);
721 return DRM_ERR(EINVAL);
722 }
723
724 if (S3_SAVAGE3D_SERIES(dev_priv->chipset)) {
725 if (skip > SAVAGE_SKIP_ALL_S3D) {
726 DRM_ERROR("invalid skip flags 0x%04x\n", skip);
727 return DRM_ERR(EINVAL);
728 }
729 vtx_size = 8; /* full vertex */
730 } else {
731 if (skip > SAVAGE_SKIP_ALL_S4) {
732 DRM_ERROR("invalid skip flags 0x%04x\n", skip);
733 return DRM_ERR(EINVAL);
734 }
735 vtx_size = 10; /* full vertex */
736 }
737
738 vtx_size -= (skip & 1) + (skip >> 1 & 1) +
739 (skip >> 2 & 1) + (skip >> 3 & 1) + (skip >> 4 & 1) +
740 (skip >> 5 & 1) + (skip >> 6 & 1) + (skip >> 7 & 1);
741
742 if (vtx_size > vb_stride) {
743 DRM_ERROR("vertex size greater than vb stride (%u > %u)\n",
744 vtx_size, vb_stride);
745 return DRM_ERR(EINVAL);
746 }
747
748 prim <<= 25;
749 while (n != 0) {
750 /* Can emit up to 255 vertices (85 triangles) at once. */
751 unsigned int count = n > 255 ? 255 : n;
752 /* Is it ok to allocate 510 bytes on the stack in an ioctl? */
753 uint16_t idx[255];
754
755 /* Copy and check indices */
756 DRM_COPY_FROM_USER_UNCHECKED(idx, usr_idx, count*2);
757 for (i = 0; i < count; ++i) {
758 if (idx[i] > vb_size / (vb_stride*4)) {
759 DRM_ERROR("idx[%u]=%u out of range (0-%u)\n",
760 i, idx[i], vb_size / (vb_stride*4));
761 return DRM_ERR(EINVAL);
762 }
763 }
764
765 if (reorder) {
766 /* Need to reorder vertices for correct flat
767 * shading while preserving the clock sense
768 * for correct culling. Only on Savage3D. */
769 int reorder[3] = {2, -1, -1};
770
771 BEGIN_DMA(count*vtx_size+1);
772 DMA_DRAW_PRIMITIVE(count, prim, skip);
773
774 for (i = 0; i < count; ++i) {
775 unsigned int j = idx[i + reorder[i % 3]];
776 DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
777 vtx_size);
778 }
779
780 DMA_COMMIT();
781 } else {
782 BEGIN_DMA(count*vtx_size+1);
783 DMA_DRAW_PRIMITIVE(count, prim, skip);
784
785 for (i = 0; i < count; ++i) {
786 unsigned int j = idx[i];
787 DMA_COPY_FROM_USER(&vtxbuf[vb_stride*j],
788 vtx_size);
789 }
790
791 DMA_COMMIT();
792 }
793
794 usr_idx += count;
795 n -= count;
796
797 prim |= BCI_CMD_DRAW_CONT;
798 }
799
800 return 0;
801}
802
803static int savage_dispatch_clear(drm_savage_private_t *dev_priv,
804 const drm_savage_cmd_header_t *cmd_header,
805 const drm_savage_cmd_header_t __user *data,
806 unsigned int nbox,
807 const drm_clip_rect_t __user *usr_boxes)
808{
809 unsigned int flags = cmd_header->clear0.flags, mask, value;
810 unsigned int clear_cmd;
811 unsigned int i, nbufs;
812 DMA_LOCALS;
813
814 if (nbox == 0)
815 return 0;
816
817 DRM_GET_USER_UNCHECKED(mask, &((const drm_savage_cmd_header_t*)data)
818 ->clear1.mask);
819 DRM_GET_USER_UNCHECKED(value, &((const drm_savage_cmd_header_t*)data)
820 ->clear1.value);
821
822 clear_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
823 BCI_CMD_SEND_COLOR | BCI_CMD_DEST_PBD_NEW;
824 BCI_CMD_SET_ROP(clear_cmd,0xCC);
825
826 nbufs = ((flags & SAVAGE_FRONT) ? 1 : 0) +
827 ((flags & SAVAGE_BACK) ? 1 : 0) +
828 ((flags & SAVAGE_DEPTH) ? 1 : 0);
829 if (nbufs == 0)
830 return 0;
831
832 if (mask != 0xffffffff) {
833 /* set mask */
834 BEGIN_DMA(2);
835 DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
836 DMA_WRITE(mask);
837 DMA_COMMIT();
838 }
839 for (i = 0; i < nbox; ++i) {
840 drm_clip_rect_t box;
841 unsigned int x, y, w, h;
842 unsigned int buf;
843 DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
844 x = box.x1, y = box.y1;
845 w = box.x2 - box.x1;
846 h = box.y2 - box.y1;
847 BEGIN_DMA(nbufs*6);
848 for (buf = SAVAGE_FRONT; buf <= SAVAGE_DEPTH; buf <<= 1) {
849 if (!(flags & buf))
850 continue;
851 DMA_WRITE(clear_cmd);
852 switch(buf) {
853 case SAVAGE_FRONT:
854 DMA_WRITE(dev_priv->front_offset);
855 DMA_WRITE(dev_priv->front_bd);
856 break;
857 case SAVAGE_BACK:
858 DMA_WRITE(dev_priv->back_offset);
859 DMA_WRITE(dev_priv->back_bd);
860 break;
861 case SAVAGE_DEPTH:
862 DMA_WRITE(dev_priv->depth_offset);
863 DMA_WRITE(dev_priv->depth_bd);
864 break;
865 }
866 DMA_WRITE(value);
867 DMA_WRITE(BCI_X_Y(x, y));
868 DMA_WRITE(BCI_W_H(w, h));
869 }
870 DMA_COMMIT();
871 }
872 if (mask != 0xffffffff) {
873 /* reset mask */
874 BEGIN_DMA(2);
875 DMA_SET_REGISTERS(SAVAGE_BITPLANEWTMASK, 1);
876 DMA_WRITE(0xffffffff);
877 DMA_COMMIT();
878 }
879
880 return 0;
881}
882
883static int savage_dispatch_swap(drm_savage_private_t *dev_priv,
884 unsigned int nbox,
885 const drm_clip_rect_t __user *usr_boxes)
886{
887 unsigned int swap_cmd;
888 unsigned int i;
889 DMA_LOCALS;
890
891 if (nbox == 0)
892 return 0;
893
894 swap_cmd = BCI_CMD_RECT | BCI_CMD_RECT_XP | BCI_CMD_RECT_YP |
895 BCI_CMD_SRC_PBD_COLOR_NEW | BCI_CMD_DEST_GBD;
896 BCI_CMD_SET_ROP(swap_cmd,0xCC);
897
898 for (i = 0; i < nbox; ++i) {
899 drm_clip_rect_t box;
900 DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
901
902 BEGIN_DMA(6);
903 DMA_WRITE(swap_cmd);
904 DMA_WRITE(dev_priv->back_offset);
905 DMA_WRITE(dev_priv->back_bd);
906 DMA_WRITE(BCI_X_Y(box.x1, box.y1));
907 DMA_WRITE(BCI_X_Y(box.x1, box.y1));
908 DMA_WRITE(BCI_W_H(box.x2-box.x1, box.y2-box.y1));
909 DMA_COMMIT();
910 }
911
912 return 0;
913}
914
915static int savage_dispatch_draw(drm_savage_private_t *dev_priv,
916 const drm_savage_cmd_header_t __user *start,
917 const drm_savage_cmd_header_t __user *end,
918 const drm_buf_t *dmabuf,
919 const unsigned int __user *usr_vtxbuf,
920 unsigned int vb_size, unsigned int vb_stride,
921 unsigned int nbox,
922 const drm_clip_rect_t __user *usr_boxes)
923{
924 unsigned int i, j;
925 int ret;
926
927 for (i = 0; i < nbox; ++i) {
928 drm_clip_rect_t box;
929 const drm_savage_cmd_header_t __user *usr_cmdbuf;
930 DRM_COPY_FROM_USER_UNCHECKED(&box, &usr_boxes[i], sizeof(box));
931 dev_priv->emit_clip_rect(dev_priv, &box);
932
933 usr_cmdbuf = start;
934 while (usr_cmdbuf < end) {
935 drm_savage_cmd_header_t cmd_header;
936 DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf,
937 sizeof(cmd_header));
938 usr_cmdbuf++;
939 switch (cmd_header.cmd.cmd) {
940 case SAVAGE_CMD_DMA_PRIM:
941 ret = savage_dispatch_dma_prim(
942 dev_priv, &cmd_header, dmabuf);
943 break;
944 case SAVAGE_CMD_VB_PRIM:
945 ret = savage_dispatch_vb_prim(
946 dev_priv, &cmd_header,
947 (const uint32_t __user *)usr_vtxbuf,
948 vb_size, vb_stride);
949 break;
950 case SAVAGE_CMD_DMA_IDX:
951 j = (cmd_header.idx.count + 3) / 4;
952 /* j was check in savage_bci_cmdbuf */
953 ret = savage_dispatch_dma_idx(
954 dev_priv, &cmd_header,
955 (const uint16_t __user *)usr_cmdbuf,
956 dmabuf);
957 usr_cmdbuf += j;
958 break;
959 case SAVAGE_CMD_VB_IDX:
960 j = (cmd_header.idx.count + 3) / 4;
961 /* j was check in savage_bci_cmdbuf */
962 ret = savage_dispatch_vb_idx(
963 dev_priv, &cmd_header,
964 (const uint16_t __user *)usr_cmdbuf,
965 (const uint32_t __user *)usr_vtxbuf,
966 vb_size, vb_stride);
967 usr_cmdbuf += j;
968 break;
969 default:
970 /* What's the best return code? EFAULT? */
971 DRM_ERROR("IMPLEMENTATION ERROR: "
972 "non-drawing-command %d\n",
973 cmd_header.cmd.cmd);
974 return DRM_ERR(EINVAL);
975 }
976
977 if (ret != 0)
978 return ret;
979 }
980 }
981
982 return 0;
983}
984
985int savage_bci_cmdbuf(DRM_IOCTL_ARGS)
986{
987 DRM_DEVICE;
988 drm_savage_private_t *dev_priv = dev->dev_private;
989 drm_device_dma_t *dma = dev->dma;
990 drm_buf_t *dmabuf;
991 drm_savage_cmdbuf_t cmdbuf;
992 drm_savage_cmd_header_t __user *usr_cmdbuf;
993 drm_savage_cmd_header_t __user *first_draw_cmd;
994 unsigned int __user *usr_vtxbuf;
995 drm_clip_rect_t __user *usr_boxes;
996 unsigned int i, j;
997 int ret = 0;
998
999 DRM_DEBUG("\n");
1000
1001 LOCK_TEST_WITH_RETURN(dev, filp);
1002
1003 DRM_COPY_FROM_USER_IOCTL(cmdbuf, (drm_savage_cmdbuf_t __user *)data,
1004 sizeof(cmdbuf));
1005
1006 if (dma && dma->buflist) {
1007 if (cmdbuf.dma_idx > dma->buf_count) {
1008 DRM_ERROR("vertex buffer index %u out of range (0-%u)\n",
1009 cmdbuf.dma_idx, dma->buf_count-1);
1010 return DRM_ERR(EINVAL);
1011 }
1012 dmabuf = dma->buflist[cmdbuf.dma_idx];
1013 } else {
1014 dmabuf = NULL;
1015 }
1016
1017 usr_cmdbuf = (drm_savage_cmd_header_t __user *)cmdbuf.cmd_addr;
1018 usr_vtxbuf = (unsigned int __user *)cmdbuf.vb_addr;
1019 usr_boxes = (drm_clip_rect_t __user *)cmdbuf.box_addr;
1020 if ((cmdbuf.size && DRM_VERIFYAREA_READ(usr_cmdbuf, cmdbuf.size*8)) ||
1021 (cmdbuf.vb_size && DRM_VERIFYAREA_READ(
1022 usr_vtxbuf, cmdbuf.vb_size)) ||
1023 (cmdbuf.nbox && DRM_VERIFYAREA_READ(
1024 usr_boxes, cmdbuf.nbox*sizeof(drm_clip_rect_t))))
1025 return DRM_ERR(EFAULT);
1026
1027 /* Make sure writes to DMA buffers are finished before sending
1028 * DMA commands to the graphics hardware. */
1029 DRM_MEMORYBARRIER();
1030
1031 /* Coming from user space. Don't know if the Xserver has
1032 * emitted wait commands. Assuming the worst. */
1033 dev_priv->waiting = 1;
1034
1035 i = 0;
1036 first_draw_cmd = NULL;
1037 while (i < cmdbuf.size) {
1038 drm_savage_cmd_header_t cmd_header;
1039 DRM_COPY_FROM_USER_UNCHECKED(&cmd_header, usr_cmdbuf,
1040 sizeof(cmd_header));
1041 usr_cmdbuf++;
1042 i++;
1043
1044 /* Group drawing commands with same state to minimize
1045 * iterations over clip rects. */
1046 j = 0;
1047 switch (cmd_header.cmd.cmd) {
1048 case SAVAGE_CMD_DMA_IDX:
1049 case SAVAGE_CMD_VB_IDX:
1050 j = (cmd_header.idx.count + 3) / 4;
1051 if (i + j > cmdbuf.size) {
1052 DRM_ERROR("indexed drawing command extends "
1053 "beyond end of command buffer\n");
1054 DMA_FLUSH();
1055 return DRM_ERR(EINVAL);
1056 }
1057 /* fall through */
1058 case SAVAGE_CMD_DMA_PRIM:
1059 case SAVAGE_CMD_VB_PRIM:
1060 if (!first_draw_cmd)
1061 first_draw_cmd = usr_cmdbuf-1;
1062 usr_cmdbuf += j;
1063 i += j;
1064 break;
1065 default:
1066 if (first_draw_cmd) {
1067 ret = savage_dispatch_draw (
1068 dev_priv, first_draw_cmd, usr_cmdbuf-1,
1069 dmabuf, usr_vtxbuf, cmdbuf.vb_size,
1070 cmdbuf.vb_stride,
1071 cmdbuf.nbox, usr_boxes);
1072 if (ret != 0)
1073 return ret;
1074 first_draw_cmd = NULL;
1075 }
1076 }
1077 if (first_draw_cmd)
1078 continue;
1079
1080 switch (cmd_header.cmd.cmd) {
1081 case SAVAGE_CMD_STATE:
1082 j = (cmd_header.state.count + 1) / 2;
1083 if (i + j > cmdbuf.size) {
1084 DRM_ERROR("command SAVAGE_CMD_STATE extends "
1085 "beyond end of command buffer\n");
1086 DMA_FLUSH();
1087 return DRM_ERR(EINVAL);
1088 }
1089 ret = savage_dispatch_state(
1090 dev_priv, &cmd_header,
1091 (uint32_t __user *)usr_cmdbuf);
1092 usr_cmdbuf += j;
1093 i += j;
1094 break;
1095 case SAVAGE_CMD_CLEAR:
1096 if (i + 1 > cmdbuf.size) {
1097 DRM_ERROR("command SAVAGE_CMD_CLEAR extends "
1098 "beyond end of command buffer\n");
1099 DMA_FLUSH();
1100 return DRM_ERR(EINVAL);
1101 }
1102 ret = savage_dispatch_clear(dev_priv, &cmd_header,
1103 usr_cmdbuf,
1104 cmdbuf.nbox, usr_boxes);
1105 usr_cmdbuf++;
1106 i++;
1107 break;
1108 case SAVAGE_CMD_SWAP:
1109 ret = savage_dispatch_swap(dev_priv,
1110 cmdbuf.nbox, usr_boxes);
1111 break;
1112 default:
1113 DRM_ERROR("invalid command 0x%x\n", cmd_header.cmd.cmd);
1114 DMA_FLUSH();
1115 return DRM_ERR(EINVAL);
1116 }
1117
1118 if (ret != 0) {
1119 DMA_FLUSH();
1120 return ret;
1121 }
1122 }
1123
1124 if (first_draw_cmd) {
1125 ret = savage_dispatch_draw (
1126 dev_priv, first_draw_cmd, usr_cmdbuf, dmabuf,
1127 usr_vtxbuf, cmdbuf.vb_size, cmdbuf.vb_stride,
1128 cmdbuf.nbox, usr_boxes);
1129 if (ret != 0) {
1130 DMA_FLUSH();
1131 return ret;
1132 }
1133 }
1134
1135 DMA_FLUSH();
1136
1137 if (dmabuf && cmdbuf.discard) {
1138 drm_savage_buf_priv_t *buf_priv = dmabuf->dev_private;
1139 uint16_t event;
1140 event = savage_bci_emit_event(dev_priv, SAVAGE_WAIT_3D);
1141 SET_AGE(&buf_priv->age, event, dev_priv->event_wrap);
1142 savage_freelist_put(dev, dmabuf);
1143 }
1144
1145 return 0;
1146}