diff options
author | Jeff Garzik <jgarzik@pobox.com> | 2005-09-01 18:02:27 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@pobox.com> | 2005-09-01 18:02:27 -0400 |
commit | ceeec3dc375e3b0618f16b34efc56fe093918f8b (patch) | |
tree | 2293d02721ee05131aaf1c60e4fba7e281585eec /drivers/char/drm/savage_state.c | |
parent | fbff868db3a4cc6a89d51da9a6d49b26c29d04fb (diff) | |
parent | e3ee3b78f83688a0ae4315e8be71b2eac559904a (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.c | 1146 |
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 | |||
29 | void 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 | |||
55 | void 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 | |||
81 | static 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, ®s[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, ®s[reg-start]); \ | ||
121 | dev_priv->state.where = (tmp & (mask)) | \ | ||
122 | (dev_priv->state.where & ~(mask)); \ | ||
123 | } \ | ||
124 | } while (0) | ||
125 | static 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 | |||
155 | static 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 | |||
193 | static 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 | |||
276 | static 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 | |||
416 | static 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 | |||
536 | static 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 | |||
682 | static 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 | |||
803 | static 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 | |||
883 | static 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 | |||
915 | static 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 | |||
985 | int 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 | } | ||