aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/drm/mga_dma.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 18:20:36 -0400
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/char/drm/mga_dma.c
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history, even though we have it. We can create a separate "historical" git archive of that later if we want to, and in the meantime it's about 3.2GB when imported into git - space that would just make the early git days unnecessarily complicated, when we don't have a lot of good infrastructure for it. Let it rip!
Diffstat (limited to 'drivers/char/drm/mga_dma.c')
-rw-r--r--drivers/char/drm/mga_dma.c754
1 files changed, 754 insertions, 0 deletions
diff --git a/drivers/char/drm/mga_dma.c b/drivers/char/drm/mga_dma.c
new file mode 100644
index 000000000000..832eaf8a5068
--- /dev/null
+++ b/drivers/char/drm/mga_dma.c
@@ -0,0 +1,754 @@
1/* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*-
2 * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com
3 *
4 * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
5 * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
6 * All Rights Reserved.
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a
9 * copy of this software and associated documentation files (the "Software"),
10 * to deal in the Software without restriction, including without limitation
11 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12 * and/or sell copies of the Software, and to permit persons to whom the
13 * Software is furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice (including the next
16 * paragraph) shall be included in all copies or substantial portions of the
17 * Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
23 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 * DEALINGS IN THE SOFTWARE.
26 *
27 * Authors:
28 * Rickard E. (Rik) Faith <faith@valinux.com>
29 * Jeff Hartmann <jhartmann@valinux.com>
30 * Keith Whitwell <keith@tungstengraphics.com>
31 *
32 * Rewritten by:
33 * Gareth Hughes <gareth@valinux.com>
34 */
35
36#include "drmP.h"
37#include "drm.h"
38#include "mga_drm.h"
39#include "mga_drv.h"
40
41#define MGA_DEFAULT_USEC_TIMEOUT 10000
42#define MGA_FREELIST_DEBUG 0
43
44static int mga_do_cleanup_dma( drm_device_t *dev );
45
46/* ================================================================
47 * Engine control
48 */
49
50int mga_do_wait_for_idle( drm_mga_private_t *dev_priv )
51{
52 u32 status = 0;
53 int i;
54 DRM_DEBUG( "\n" );
55
56 for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
57 status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
58 if ( status == MGA_ENDPRDMASTS ) {
59 MGA_WRITE8( MGA_CRTC_INDEX, 0 );
60 return 0;
61 }
62 DRM_UDELAY( 1 );
63 }
64
65#if MGA_DMA_DEBUG
66 DRM_ERROR( "failed!\n" );
67 DRM_INFO( " status=0x%08x\n", status );
68#endif
69 return DRM_ERR(EBUSY);
70}
71
72static int mga_do_dma_reset( drm_mga_private_t *dev_priv )
73{
74 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
75 drm_mga_primary_buffer_t *primary = &dev_priv->prim;
76
77 DRM_DEBUG( "\n" );
78
79 /* The primary DMA stream should look like new right about now.
80 */
81 primary->tail = 0;
82 primary->space = primary->size;
83 primary->last_flush = 0;
84
85 sarea_priv->last_wrap = 0;
86
87 /* FIXME: Reset counters, buffer ages etc...
88 */
89
90 /* FIXME: What else do we need to reinitialize? WARP stuff?
91 */
92
93 return 0;
94}
95
96/* ================================================================
97 * Primary DMA stream
98 */
99
100void mga_do_dma_flush( drm_mga_private_t *dev_priv )
101{
102 drm_mga_primary_buffer_t *primary = &dev_priv->prim;
103 u32 head, tail;
104 u32 status = 0;
105 int i;
106 DMA_LOCALS;
107 DRM_DEBUG( "\n" );
108
109 /* We need to wait so that we can do an safe flush */
110 for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
111 status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
112 if ( status == MGA_ENDPRDMASTS ) break;
113 DRM_UDELAY( 1 );
114 }
115
116 if ( primary->tail == primary->last_flush ) {
117 DRM_DEBUG( " bailing out...\n" );
118 return;
119 }
120
121 tail = primary->tail + dev_priv->primary->offset;
122
123 /* We need to pad the stream between flushes, as the card
124 * actually (partially?) reads the first of these commands.
125 * See page 4-16 in the G400 manual, middle of the page or so.
126 */
127 BEGIN_DMA( 1 );
128
129 DMA_BLOCK( MGA_DMAPAD, 0x00000000,
130 MGA_DMAPAD, 0x00000000,
131 MGA_DMAPAD, 0x00000000,
132 MGA_DMAPAD, 0x00000000 );
133
134 ADVANCE_DMA();
135
136 primary->last_flush = primary->tail;
137
138 head = MGA_READ( MGA_PRIMADDRESS );
139
140 if ( head <= tail ) {
141 primary->space = primary->size - primary->tail;
142 } else {
143 primary->space = head - tail;
144 }
145
146 DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset );
147 DRM_DEBUG( " tail = 0x%06lx\n", tail - dev_priv->primary->offset );
148 DRM_DEBUG( " space = 0x%06x\n", primary->space );
149
150 mga_flush_write_combine();
151 MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
152
153 DRM_DEBUG( "done.\n" );
154}
155
156void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv )
157{
158 drm_mga_primary_buffer_t *primary = &dev_priv->prim;
159 u32 head, tail;
160 DMA_LOCALS;
161 DRM_DEBUG( "\n" );
162
163 BEGIN_DMA_WRAP();
164
165 DMA_BLOCK( MGA_DMAPAD, 0x00000000,
166 MGA_DMAPAD, 0x00000000,
167 MGA_DMAPAD, 0x00000000,
168 MGA_DMAPAD, 0x00000000 );
169
170 ADVANCE_DMA();
171
172 tail = primary->tail + dev_priv->primary->offset;
173
174 primary->tail = 0;
175 primary->last_flush = 0;
176 primary->last_wrap++;
177
178 head = MGA_READ( MGA_PRIMADDRESS );
179
180 if ( head == dev_priv->primary->offset ) {
181 primary->space = primary->size;
182 } else {
183 primary->space = head - dev_priv->primary->offset;
184 }
185
186 DRM_DEBUG( " head = 0x%06lx\n",
187 head - dev_priv->primary->offset );
188 DRM_DEBUG( " tail = 0x%06x\n", primary->tail );
189 DRM_DEBUG( " wrap = %d\n", primary->last_wrap );
190 DRM_DEBUG( " space = 0x%06x\n", primary->space );
191
192 mga_flush_write_combine();
193 MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
194
195 set_bit( 0, &primary->wrapped );
196 DRM_DEBUG( "done.\n" );
197}
198
199void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv )
200{
201 drm_mga_primary_buffer_t *primary = &dev_priv->prim;
202 drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
203 u32 head = dev_priv->primary->offset;
204 DRM_DEBUG( "\n" );
205
206 sarea_priv->last_wrap++;
207 DRM_DEBUG( " wrap = %d\n", sarea_priv->last_wrap );
208
209 mga_flush_write_combine();
210 MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL );
211
212 clear_bit( 0, &primary->wrapped );
213 DRM_DEBUG( "done.\n" );
214}
215
216
217/* ================================================================
218 * Freelist management
219 */
220
221#define MGA_BUFFER_USED ~0
222#define MGA_BUFFER_FREE 0
223
224#if MGA_FREELIST_DEBUG
225static void mga_freelist_print( drm_device_t *dev )
226{
227 drm_mga_private_t *dev_priv = dev->dev_private;
228 drm_mga_freelist_t *entry;
229
230 DRM_INFO( "\n" );
231 DRM_INFO( "current dispatch: last=0x%x done=0x%x\n",
232 dev_priv->sarea_priv->last_dispatch,
233 (unsigned int)(MGA_READ( MGA_PRIMADDRESS ) -
234 dev_priv->primary->offset) );
235 DRM_INFO( "current freelist:\n" );
236
237 for ( entry = dev_priv->head->next ; entry ; entry = entry->next ) {
238 DRM_INFO( " %p idx=%2d age=0x%x 0x%06lx\n",
239 entry, entry->buf->idx, entry->age.head,
240 entry->age.head - dev_priv->primary->offset );
241 }
242 DRM_INFO( "\n" );
243}
244#endif
245
246static int mga_freelist_init( drm_device_t *dev, drm_mga_private_t *dev_priv )
247{
248 drm_device_dma_t *dma = dev->dma;
249 drm_buf_t *buf;
250 drm_mga_buf_priv_t *buf_priv;
251 drm_mga_freelist_t *entry;
252 int i;
253 DRM_DEBUG( "count=%d\n", dma->buf_count );
254
255 dev_priv->head = drm_alloc( sizeof(drm_mga_freelist_t),
256 DRM_MEM_DRIVER );
257 if ( dev_priv->head == NULL )
258 return DRM_ERR(ENOMEM);
259
260 memset( dev_priv->head, 0, sizeof(drm_mga_freelist_t) );
261 SET_AGE( &dev_priv->head->age, MGA_BUFFER_USED, 0 );
262
263 for ( i = 0 ; i < dma->buf_count ; i++ ) {
264 buf = dma->buflist[i];
265 buf_priv = buf->dev_private;
266
267 entry = drm_alloc( sizeof(drm_mga_freelist_t),
268 DRM_MEM_DRIVER );
269 if ( entry == NULL )
270 return DRM_ERR(ENOMEM);
271
272 memset( entry, 0, sizeof(drm_mga_freelist_t) );
273
274 entry->next = dev_priv->head->next;
275 entry->prev = dev_priv->head;
276 SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 );
277 entry->buf = buf;
278
279 if ( dev_priv->head->next != NULL )
280 dev_priv->head->next->prev = entry;
281 if ( entry->next == NULL )
282 dev_priv->tail = entry;
283
284 buf_priv->list_entry = entry;
285 buf_priv->discard = 0;
286 buf_priv->dispatched = 0;
287
288 dev_priv->head->next = entry;
289 }
290
291 return 0;
292}
293
294static void mga_freelist_cleanup( drm_device_t *dev )
295{
296 drm_mga_private_t *dev_priv = dev->dev_private;
297 drm_mga_freelist_t *entry;
298 drm_mga_freelist_t *next;
299 DRM_DEBUG( "\n" );
300
301 entry = dev_priv->head;
302 while ( entry ) {
303 next = entry->next;
304 drm_free( entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER );
305 entry = next;
306 }
307
308 dev_priv->head = dev_priv->tail = NULL;
309}
310
311#if 0
312/* FIXME: Still needed?
313 */
314static void mga_freelist_reset( drm_device_t *dev )
315{
316 drm_device_dma_t *dma = dev->dma;
317 drm_buf_t *buf;
318 drm_mga_buf_priv_t *buf_priv;
319 int i;
320
321 for ( i = 0 ; i < dma->buf_count ; i++ ) {
322 buf = dma->buflist[i];
323 buf_priv = buf->dev_private;
324 SET_AGE( &buf_priv->list_entry->age,
325 MGA_BUFFER_FREE, 0 );
326 }
327}
328#endif
329
330static drm_buf_t *mga_freelist_get( drm_device_t *dev )
331{
332 drm_mga_private_t *dev_priv = dev->dev_private;
333 drm_mga_freelist_t *next;
334 drm_mga_freelist_t *prev;
335 drm_mga_freelist_t *tail = dev_priv->tail;
336 u32 head, wrap;
337 DRM_DEBUG( "\n" );
338
339 head = MGA_READ( MGA_PRIMADDRESS );
340 wrap = dev_priv->sarea_priv->last_wrap;
341
342 DRM_DEBUG( " tail=0x%06lx %d\n",
343 tail->age.head ?
344 tail->age.head - dev_priv->primary->offset : 0,
345 tail->age.wrap );
346 DRM_DEBUG( " head=0x%06lx %d\n",
347 head - dev_priv->primary->offset, wrap );
348
349 if ( TEST_AGE( &tail->age, head, wrap ) ) {
350 prev = dev_priv->tail->prev;
351 next = dev_priv->tail;
352 prev->next = NULL;
353 next->prev = next->next = NULL;
354 dev_priv->tail = prev;
355 SET_AGE( &next->age, MGA_BUFFER_USED, 0 );
356 return next->buf;
357 }
358
359 DRM_DEBUG( "returning NULL!\n" );
360 return NULL;
361}
362
363int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf )
364{
365 drm_mga_private_t *dev_priv = dev->dev_private;
366 drm_mga_buf_priv_t *buf_priv = buf->dev_private;
367 drm_mga_freelist_t *head, *entry, *prev;
368
369 DRM_DEBUG( "age=0x%06lx wrap=%d\n",
370 buf_priv->list_entry->age.head -
371 dev_priv->primary->offset,
372 buf_priv->list_entry->age.wrap );
373
374 entry = buf_priv->list_entry;
375 head = dev_priv->head;
376
377 if ( buf_priv->list_entry->age.head == MGA_BUFFER_USED ) {
378 SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 );
379 prev = dev_priv->tail;
380 prev->next = entry;
381 entry->prev = prev;
382 entry->next = NULL;
383 } else {
384 prev = head->next;
385 head->next = entry;
386 prev->prev = entry;
387 entry->prev = head;
388 entry->next = prev;
389 }
390
391 return 0;
392}
393
394
395/* ================================================================
396 * DMA initialization, cleanup
397 */
398
399static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
400{
401 drm_mga_private_t *dev_priv;
402 int ret;
403 DRM_DEBUG( "\n" );
404
405 dev_priv = drm_alloc( sizeof(drm_mga_private_t), DRM_MEM_DRIVER );
406 if ( !dev_priv )
407 return DRM_ERR(ENOMEM);
408
409 memset( dev_priv, 0, sizeof(drm_mga_private_t) );
410
411 dev_priv->chipset = init->chipset;
412
413 dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
414
415 if ( init->sgram ) {
416 dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK;
417 } else {
418 dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR;
419 }
420 dev_priv->maccess = init->maccess;
421
422 dev_priv->fb_cpp = init->fb_cpp;
423 dev_priv->front_offset = init->front_offset;
424 dev_priv->front_pitch = init->front_pitch;
425 dev_priv->back_offset = init->back_offset;
426 dev_priv->back_pitch = init->back_pitch;
427
428 dev_priv->depth_cpp = init->depth_cpp;
429 dev_priv->depth_offset = init->depth_offset;
430 dev_priv->depth_pitch = init->depth_pitch;
431
432 /* FIXME: Need to support AGP textures...
433 */
434 dev_priv->texture_offset = init->texture_offset[0];
435 dev_priv->texture_size = init->texture_size[0];
436
437 DRM_GETSAREA();
438
439 if(!dev_priv->sarea) {
440 DRM_ERROR( "failed to find sarea!\n" );
441 /* Assign dev_private so we can do cleanup. */
442 dev->dev_private = (void *)dev_priv;
443 mga_do_cleanup_dma( dev );
444 return DRM_ERR(EINVAL);
445 }
446
447 dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
448 if(!dev_priv->mmio) {
449 DRM_ERROR( "failed to find mmio region!\n" );
450 /* Assign dev_private so we can do cleanup. */
451 dev->dev_private = (void *)dev_priv;
452 mga_do_cleanup_dma( dev );
453 return DRM_ERR(EINVAL);
454 }
455 dev_priv->status = drm_core_findmap(dev, init->status_offset);
456 if(!dev_priv->status) {
457 DRM_ERROR( "failed to find status page!\n" );
458 /* Assign dev_private so we can do cleanup. */
459 dev->dev_private = (void *)dev_priv;
460 mga_do_cleanup_dma( dev );
461 return DRM_ERR(EINVAL);
462 }
463 dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
464 if(!dev_priv->warp) {
465 DRM_ERROR( "failed to find warp microcode region!\n" );
466 /* Assign dev_private so we can do cleanup. */
467 dev->dev_private = (void *)dev_priv;
468 mga_do_cleanup_dma( dev );
469 return DRM_ERR(EINVAL);
470 }
471 dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
472 if(!dev_priv->primary) {
473 DRM_ERROR( "failed to find primary dma region!\n" );
474 /* Assign dev_private so we can do cleanup. */
475 dev->dev_private = (void *)dev_priv;
476 mga_do_cleanup_dma( dev );
477 return DRM_ERR(EINVAL);
478 }
479 dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
480 if(!dev->agp_buffer_map) {
481 DRM_ERROR( "failed to find dma buffer region!\n" );
482 /* Assign dev_private so we can do cleanup. */
483 dev->dev_private = (void *)dev_priv;
484 mga_do_cleanup_dma( dev );
485 return DRM_ERR(EINVAL);
486 }
487
488 dev_priv->sarea_priv =
489 (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle +
490 init->sarea_priv_offset);
491
492 drm_core_ioremap( dev_priv->warp, dev );
493 drm_core_ioremap( dev_priv->primary, dev );
494 drm_core_ioremap( dev->agp_buffer_map, dev );
495
496 if(!dev_priv->warp->handle ||
497 !dev_priv->primary->handle ||
498 !dev->agp_buffer_map->handle ) {
499 DRM_ERROR( "failed to ioremap agp regions!\n" );
500 /* Assign dev_private so we can do cleanup. */
501 dev->dev_private = (void *)dev_priv;
502 mga_do_cleanup_dma( dev );
503 return DRM_ERR(ENOMEM);
504 }
505
506 ret = mga_warp_install_microcode( dev_priv );
507 if ( ret < 0 ) {
508 DRM_ERROR( "failed to install WARP ucode!\n" );
509 /* Assign dev_private so we can do cleanup. */
510 dev->dev_private = (void *)dev_priv;
511 mga_do_cleanup_dma( dev );
512 return ret;
513 }
514
515 ret = mga_warp_init( dev_priv );
516 if ( ret < 0 ) {
517 DRM_ERROR( "failed to init WARP engine!\n" );
518 /* Assign dev_private so we can do cleanup. */
519 dev->dev_private = (void *)dev_priv;
520 mga_do_cleanup_dma( dev );
521 return ret;
522 }
523
524 dev_priv->prim.status = (u32 *)dev_priv->status->handle;
525
526 mga_do_wait_for_idle( dev_priv );
527
528 /* Init the primary DMA registers.
529 */
530 MGA_WRITE( MGA_PRIMADDRESS,
531 dev_priv->primary->offset | MGA_DMA_GENERAL );
532#if 0
533 MGA_WRITE( MGA_PRIMPTR,
534 virt_to_bus((void *)dev_priv->prim.status) |
535 MGA_PRIMPTREN0 | /* Soft trap, SECEND, SETUPEND */
536 MGA_PRIMPTREN1 ); /* DWGSYNC */
537#endif
538
539 dev_priv->prim.start = (u8 *)dev_priv->primary->handle;
540 dev_priv->prim.end = ((u8 *)dev_priv->primary->handle
541 + dev_priv->primary->size);
542 dev_priv->prim.size = dev_priv->primary->size;
543
544 dev_priv->prim.tail = 0;
545 dev_priv->prim.space = dev_priv->prim.size;
546 dev_priv->prim.wrapped = 0;
547
548 dev_priv->prim.last_flush = 0;
549 dev_priv->prim.last_wrap = 0;
550
551 dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE;
552
553 dev_priv->prim.status[0] = dev_priv->primary->offset;
554 dev_priv->prim.status[1] = 0;
555
556 dev_priv->sarea_priv->last_wrap = 0;
557 dev_priv->sarea_priv->last_frame.head = 0;
558 dev_priv->sarea_priv->last_frame.wrap = 0;
559
560 if ( mga_freelist_init( dev, dev_priv ) < 0 ) {
561 DRM_ERROR( "could not initialize freelist\n" );
562 /* Assign dev_private so we can do cleanup. */
563 dev->dev_private = (void *)dev_priv;
564 mga_do_cleanup_dma( dev );
565 return DRM_ERR(ENOMEM);
566 }
567
568 /* Make dev_private visable to others. */
569 dev->dev_private = (void *)dev_priv;
570 return 0;
571}
572
573static int mga_do_cleanup_dma( drm_device_t *dev )
574{
575 DRM_DEBUG( "\n" );
576
577 /* Make sure interrupts are disabled here because the uninstall ioctl
578 * may not have been called from userspace and after dev_private
579 * is freed, it's too late.
580 */
581 if ( dev->irq_enabled ) drm_irq_uninstall(dev);
582
583 if ( dev->dev_private ) {
584 drm_mga_private_t *dev_priv = dev->dev_private;
585
586 if ( dev_priv->warp != NULL )
587 drm_core_ioremapfree( dev_priv->warp, dev );
588 if ( dev_priv->primary != NULL )
589 drm_core_ioremapfree( dev_priv->primary, dev );
590 if ( dev->agp_buffer_map != NULL )
591 drm_core_ioremapfree( dev->agp_buffer_map, dev );
592
593 if ( dev_priv->head != NULL ) {
594 mga_freelist_cleanup( dev );
595 }
596
597 drm_free( dev->dev_private, sizeof(drm_mga_private_t),
598 DRM_MEM_DRIVER );
599 dev->dev_private = NULL;
600 }
601
602 return 0;
603}
604
605int mga_dma_init( DRM_IOCTL_ARGS )
606{
607 DRM_DEVICE;
608 drm_mga_init_t init;
609
610 LOCK_TEST_WITH_RETURN( dev, filp );
611
612 DRM_COPY_FROM_USER_IOCTL( init, (drm_mga_init_t __user *)data, sizeof(init) );
613
614 switch ( init.func ) {
615 case MGA_INIT_DMA:
616 return mga_do_init_dma( dev, &init );
617 case MGA_CLEANUP_DMA:
618 return mga_do_cleanup_dma( dev );
619 }
620
621 return DRM_ERR(EINVAL);
622}
623
624
625/* ================================================================
626 * Primary DMA stream management
627 */
628
629int mga_dma_flush( DRM_IOCTL_ARGS )
630{
631 DRM_DEVICE;
632 drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
633 drm_lock_t lock;
634
635 LOCK_TEST_WITH_RETURN( dev, filp );
636
637 DRM_COPY_FROM_USER_IOCTL( lock, (drm_lock_t __user *)data, sizeof(lock) );
638
639 DRM_DEBUG( "%s%s%s\n",
640 (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
641 (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
642 (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "" );
643
644 WRAP_WAIT_WITH_RETURN( dev_priv );
645
646 if ( lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL) ) {
647 mga_do_dma_flush( dev_priv );
648 }
649
650 if ( lock.flags & _DRM_LOCK_QUIESCENT ) {
651#if MGA_DMA_DEBUG
652 int ret = mga_do_wait_for_idle( dev_priv );
653 if ( ret < 0 )
654 DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ );
655 return ret;
656#else
657 return mga_do_wait_for_idle( dev_priv );
658#endif
659 } else {
660 return 0;
661 }
662}
663
664int mga_dma_reset( DRM_IOCTL_ARGS )
665{
666 DRM_DEVICE;
667 drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
668
669 LOCK_TEST_WITH_RETURN( dev, filp );
670
671 return mga_do_dma_reset( dev_priv );
672}
673
674
675/* ================================================================
676 * DMA buffer management
677 */
678
679static int mga_dma_get_buffers( DRMFILE filp,
680 drm_device_t *dev, drm_dma_t *d )
681{
682 drm_buf_t *buf;
683 int i;
684
685 for ( i = d->granted_count ; i < d->request_count ; i++ ) {
686 buf = mga_freelist_get( dev );
687 if ( !buf ) return DRM_ERR(EAGAIN);
688
689 buf->filp = filp;
690
691 if ( DRM_COPY_TO_USER( &d->request_indices[i],
692 &buf->idx, sizeof(buf->idx) ) )
693 return DRM_ERR(EFAULT);
694 if ( DRM_COPY_TO_USER( &d->request_sizes[i],
695 &buf->total, sizeof(buf->total) ) )
696 return DRM_ERR(EFAULT);
697
698 d->granted_count++;
699 }
700 return 0;
701}
702
703int mga_dma_buffers( DRM_IOCTL_ARGS )
704{
705 DRM_DEVICE;
706 drm_device_dma_t *dma = dev->dma;
707 drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
708 drm_dma_t __user *argp = (void __user *)data;
709 drm_dma_t d;
710 int ret = 0;
711
712 LOCK_TEST_WITH_RETURN( dev, filp );
713
714 DRM_COPY_FROM_USER_IOCTL( d, argp, sizeof(d) );
715
716 /* Please don't send us buffers.
717 */
718 if ( d.send_count != 0 ) {
719 DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n",
720 DRM_CURRENTPID, d.send_count );
721 return DRM_ERR(EINVAL);
722 }
723
724 /* We'll send you buffers.
725 */
726 if ( d.request_count < 0 || d.request_count > dma->buf_count ) {
727 DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n",
728 DRM_CURRENTPID, d.request_count, dma->buf_count );
729 return DRM_ERR(EINVAL);
730 }
731
732 WRAP_TEST_WITH_RETURN( dev_priv );
733
734 d.granted_count = 0;
735
736 if ( d.request_count ) {
737 ret = mga_dma_get_buffers( filp, dev, &d );
738 }
739
740 DRM_COPY_TO_USER_IOCTL( argp, d, sizeof(d) );
741
742 return ret;
743}
744
745void mga_driver_pretakedown(drm_device_t *dev)
746{
747 mga_do_cleanup_dma( dev );
748}
749
750int mga_driver_dma_quiescent(drm_device_t *dev)
751{
752 drm_mga_private_t *dev_priv = dev->dev_private;
753 return mga_do_wait_for_idle( dev_priv );
754}