PageRenderTime 50ms CodeModel.GetById 12ms app.highlight 31ms RepoModel.GetById 2ms app.codeStats 0ms

/drivers/char/drm/mga_dma.c

https://bitbucket.org/evzijst/gittest
C | 754 lines | 518 code | 148 blank | 88 comment | 66 complexity | e1ddadc07c451b598332733205fb1d7d MD5 | raw file
  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}