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 "mga.h"
37 #include "drmP.h"
38 #include "drm.h"
39 #include "mga_drm.h"
40 #include "mga_drv.h"
41 #include <asm/delay.h>
42 #include "drm_os_linux.h"
43 
44 #define MGA_DEFAULT_USEC_TIMEOUT	10000
45 #define MGA_FREELIST_DEBUG		0
46 
47 
48 /* ================================================================
49  * Engine control
50  */
51 
mga_do_wait_for_idle(drm_mga_private_t * dev_priv)52 int mga_do_wait_for_idle( drm_mga_private_t *dev_priv )
53 {
54 	u32 status = 0;
55 	int i;
56 	DRM_DEBUG( "\n" );
57 
58 	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
59 		status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
60 		if ( status == MGA_ENDPRDMASTS ) {
61 			MGA_WRITE8( MGA_CRTC_INDEX, 0 );
62 			return 0;
63 		}
64 		udelay( 1 );
65 	}
66 
67 #if MGA_DMA_DEBUG
68 	DRM_ERROR( "failed!\n" );
69 	DRM_INFO( "   status=0x%08x\n", status );
70 #endif
71 	return -EBUSY;
72 }
73 
mga_do_dma_idle(drm_mga_private_t * dev_priv)74 int mga_do_dma_idle( drm_mga_private_t *dev_priv )
75 {
76 	u32 status = 0;
77 	int i;
78 	DRM_DEBUG( "\n" );
79 
80 	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
81 		status = MGA_READ( MGA_STATUS ) & MGA_DMA_IDLE_MASK;
82 		if ( status == MGA_ENDPRDMASTS ) return 0;
83 		udelay( 1 );
84 	}
85 
86 #if MGA_DMA_DEBUG
87 	DRM_ERROR( "failed! status=0x%08x\n", status );
88 #endif
89 	return -EBUSY;
90 }
91 
mga_do_dma_reset(drm_mga_private_t * dev_priv)92 int mga_do_dma_reset( drm_mga_private_t *dev_priv )
93 {
94 	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
95 	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
96 
97 	DRM_DEBUG( "\n" );
98 
99 	/* The primary DMA stream should look like new right about now.
100 	 */
101 	primary->tail = 0;
102 	primary->space = primary->size;
103 	primary->last_flush = 0;
104 
105 	sarea_priv->last_wrap = 0;
106 
107 	/* FIXME: Reset counters, buffer ages etc...
108 	 */
109 
110 	/* FIXME: What else do we need to reinitialize?  WARP stuff?
111 	 */
112 
113 	return 0;
114 }
115 
mga_do_engine_reset(drm_mga_private_t * dev_priv)116 int mga_do_engine_reset( drm_mga_private_t *dev_priv )
117 {
118 	DRM_DEBUG( "\n" );
119 
120 	/* Okay, so we've completely screwed up and locked the engine.
121 	 * How about we clean up after ourselves?
122 	 */
123 	MGA_WRITE( MGA_RST, MGA_SOFTRESET );
124 	udelay( 15 );				/* Wait at least 10 usecs */
125 	MGA_WRITE( MGA_RST, 0 );
126 
127 	/* Initialize the registers that get clobbered by the soft
128 	 * reset.  Many of the core register values survive a reset,
129 	 * but the drawing registers are basically all gone.
130 	 *
131 	 * 3D clients should probably die after calling this.  The X
132 	 * server should reset the engine state to known values.
133 	 */
134 #if 0
135 	MGA_WRITE( MGA_PRIMPTR,
136 		   virt_to_bus((void *)dev_priv->prim.status_page) |
137 		   MGA_PRIMPTREN0 |
138 		   MGA_PRIMPTREN1 );
139 #endif
140 
141 	MGA_WRITE( MGA_ICLEAR, MGA_SOFTRAPICLR );
142 	MGA_WRITE( MGA_IEN,    MGA_SOFTRAPIEN );
143 
144 	/* The primary DMA stream should look like new right about now.
145 	 */
146 	mga_do_dma_reset( dev_priv );
147 
148 	/* This bad boy will never fail.
149 	 */
150 	return 0;
151 }
152 
153 
154 /* ================================================================
155  * Primary DMA stream
156  */
157 
mga_do_dma_flush(drm_mga_private_t * dev_priv)158 void mga_do_dma_flush( drm_mga_private_t *dev_priv )
159 {
160 	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
161 	u32 head, tail;
162 	u32 status = 0;
163 	int i;
164  	DMA_LOCALS;
165 	DRM_DEBUG( "\n" );
166 
167         /* We need to wait so that we can do an safe flush */
168 	for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) {
169 		status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK;
170 		if ( status == MGA_ENDPRDMASTS ) break;
171 		udelay( 1 );
172 	}
173 
174 	if ( primary->tail == primary->last_flush ) {
175 		DRM_DEBUG( "   bailing out...\n" );
176 		return;
177 	}
178 
179 	tail = primary->tail + dev_priv->primary->offset;
180 
181 	/* We need to pad the stream between flushes, as the card
182 	 * actually (partially?) reads the first of these commands.
183 	 * See page 4-16 in the G400 manual, middle of the page or so.
184 	 */
185 	BEGIN_DMA( 1 );
186 
187 	DMA_BLOCK( MGA_DMAPAD,  0x00000000,
188 		   MGA_DMAPAD,  0x00000000,
189 		   MGA_DMAPAD,  0x00000000,
190 		   MGA_DMAPAD,	0x00000000 );
191 
192 	ADVANCE_DMA();
193 
194 	primary->last_flush = primary->tail;
195 
196 	head = MGA_READ( MGA_PRIMADDRESS );
197 
198 	if ( head <= tail ) {
199 		primary->space = primary->size - primary->tail;
200 	} else {
201 		primary->space = head - tail;
202 	}
203 
204 	DRM_DEBUG( "   head = 0x%06lx\n", head - dev_priv->primary->offset );
205 	DRM_DEBUG( "   tail = 0x%06lx\n", tail - dev_priv->primary->offset );
206 	DRM_DEBUG( "  space = 0x%06x\n", primary->space );
207 
208 	mga_flush_write_combine();
209 	MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
210 
211 	DRM_DEBUG( "done.\n" );
212 }
213 
mga_do_dma_wrap_start(drm_mga_private_t * dev_priv)214 void mga_do_dma_wrap_start( drm_mga_private_t *dev_priv )
215 {
216 	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
217 	u32 head, tail;
218 	DMA_LOCALS;
219 	DRM_DEBUG( "\n" );
220 
221 	BEGIN_DMA_WRAP();
222 
223 	DMA_BLOCK( MGA_DMAPAD,	0x00000000,
224 		   MGA_DMAPAD,	0x00000000,
225 		   MGA_DMAPAD,	0x00000000,
226 		   MGA_DMAPAD,	0x00000000 );
227 
228 	ADVANCE_DMA();
229 
230 	tail = primary->tail + dev_priv->primary->offset;
231 
232 	primary->tail = 0;
233 	primary->last_flush = 0;
234 	primary->last_wrap++;
235 
236 	head = MGA_READ( MGA_PRIMADDRESS );
237 
238 	if ( head == dev_priv->primary->offset ) {
239 		primary->space = primary->size;
240 	} else {
241 		primary->space = head - dev_priv->primary->offset;
242 	}
243 
244 	DRM_DEBUG( "   head = 0x%06lx\n",
245 		  head - dev_priv->primary->offset );
246 	DRM_DEBUG( "   tail = 0x%06x\n", primary->tail );
247 	DRM_DEBUG( "   wrap = %d\n", primary->last_wrap );
248 	DRM_DEBUG( "  space = 0x%06x\n", primary->space );
249 
250 	mga_flush_write_combine();
251 	MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER );
252 
253 	set_bit( 0, &primary->wrapped );
254 	DRM_DEBUG( "done.\n" );
255 }
256 
mga_do_dma_wrap_end(drm_mga_private_t * dev_priv)257 void mga_do_dma_wrap_end( drm_mga_private_t *dev_priv )
258 {
259 	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
260 	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
261 	u32 head = dev_priv->primary->offset;
262 	DRM_DEBUG( "\n" );
263 
264 	sarea_priv->last_wrap++;
265 	DRM_DEBUG( "   wrap = %d\n", sarea_priv->last_wrap );
266 
267 	mga_flush_write_combine();
268 	MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL );
269 
270 	clear_bit( 0, &primary->wrapped );
271 	DRM_DEBUG( "done.\n" );
272 }
273 
274 
275 /* ================================================================
276  * Freelist management
277  */
278 
279 #define MGA_BUFFER_USED		~0
280 #define MGA_BUFFER_FREE		0
281 
282 #if MGA_FREELIST_DEBUG
mga_freelist_print(drm_device_t * dev)283 static void mga_freelist_print( drm_device_t *dev )
284 {
285 	drm_mga_private_t *dev_priv = dev->dev_private;
286 	drm_mga_freelist_t *entry;
287 
288 	DRM_INFO( "\n" );
289 	DRM_INFO( "current dispatch: last=0x%x done=0x%x\n",
290 		  dev_priv->sarea_priv->last_dispatch,
291 		  (unsigned int)(MGA_READ( MGA_PRIMADDRESS ) -
292 				 dev_priv->primary->offset) );
293 	DRM_INFO( "current freelist:\n" );
294 
295 	for ( entry = dev_priv->head->next ; entry ; entry = entry->next ) {
296 		DRM_INFO( "   %p   idx=%2d  age=0x%x 0x%06lx\n",
297 			  entry, entry->buf->idx, entry->age.head,
298 			  entry->age.head - dev_priv->primary->offset );
299 	}
300 	DRM_INFO( "\n" );
301 }
302 #endif
303 
mga_freelist_init(drm_device_t * dev,drm_mga_private_t * dev_priv)304 static int mga_freelist_init( drm_device_t *dev, drm_mga_private_t *dev_priv )
305 {
306 	drm_device_dma_t *dma = dev->dma;
307 	drm_buf_t *buf;
308 	drm_mga_buf_priv_t *buf_priv;
309 	drm_mga_freelist_t *entry;
310 	int i;
311 	DRM_DEBUG( "count=%d\n", dma->buf_count );
312 
313 	dev_priv->head = DRM(alloc)( sizeof(drm_mga_freelist_t),
314 				     DRM_MEM_DRIVER );
315 	if ( dev_priv->head == NULL )
316 		return -ENOMEM;
317 
318 	memset( dev_priv->head, 0, sizeof(drm_mga_freelist_t) );
319 	SET_AGE( &dev_priv->head->age, MGA_BUFFER_USED, 0 );
320 
321 	for ( i = 0 ; i < dma->buf_count ; i++ ) {
322 		buf = dma->buflist[i];
323 	        buf_priv = buf->dev_private;
324 
325 		entry = DRM(alloc)( sizeof(drm_mga_freelist_t),
326 				    DRM_MEM_DRIVER );
327 		if ( entry == NULL )
328 			return -ENOMEM;
329 
330 		memset( entry, 0, sizeof(drm_mga_freelist_t) );
331 
332 		entry->next = dev_priv->head->next;
333 		entry->prev = dev_priv->head;
334 		SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 );
335 		entry->buf = buf;
336 
337 		if ( dev_priv->head->next != NULL )
338 			dev_priv->head->next->prev = entry;
339 		if ( entry->next == NULL )
340 			dev_priv->tail = entry;
341 
342 		buf_priv->list_entry = entry;
343 		buf_priv->discard = 0;
344 		buf_priv->dispatched = 0;
345 
346 		dev_priv->head->next = entry;
347 	}
348 
349 	return 0;
350 }
351 
mga_freelist_cleanup(drm_device_t * dev)352 static void mga_freelist_cleanup( drm_device_t *dev )
353 {
354 	drm_mga_private_t *dev_priv = dev->dev_private;
355 	drm_mga_freelist_t *entry;
356 	drm_mga_freelist_t *next;
357 	DRM_DEBUG( "\n" );
358 
359 	entry = dev_priv->head;
360 	while ( entry ) {
361 		next = entry->next;
362 		DRM(free)( entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER );
363 		entry = next;
364 	}
365 
366 	dev_priv->head = dev_priv->tail = NULL;
367 }
368 
369 #if 0
370 /* FIXME: Still needed?
371  */
372 static void mga_freelist_reset( drm_device_t *dev )
373 {
374 	drm_device_dma_t *dma = dev->dma;
375 	drm_buf_t *buf;
376 	drm_mga_buf_priv_t *buf_priv;
377 	int i;
378 
379 	for ( i = 0 ; i < dma->buf_count ; i++ ) {
380 		buf = dma->buflist[i];
381 	        buf_priv = buf->dev_private;
382 		SET_AGE( &buf_priv->list_entry->age,
383 			 MGA_BUFFER_FREE, 0 );
384 	}
385 }
386 #endif
387 
mga_freelist_get(drm_device_t * dev)388 static drm_buf_t *mga_freelist_get( drm_device_t *dev )
389 {
390 	drm_mga_private_t *dev_priv = dev->dev_private;
391 	drm_mga_freelist_t *next;
392 	drm_mga_freelist_t *prev;
393 	drm_mga_freelist_t *tail = dev_priv->tail;
394 	u32 head, wrap;
395 	DRM_DEBUG( "\n" );
396 
397 	head = MGA_READ( MGA_PRIMADDRESS );
398 	wrap = dev_priv->sarea_priv->last_wrap;
399 
400 	DRM_DEBUG( "   tail=0x%06lx %d\n",
401 		   tail->age.head ?
402 		   tail->age.head - dev_priv->primary->offset : 0,
403 		   tail->age.wrap );
404 	DRM_DEBUG( "   head=0x%06lx %d\n",
405 		   head - dev_priv->primary->offset, wrap );
406 
407 	if ( TEST_AGE( &tail->age, head, wrap ) ) {
408 		prev = dev_priv->tail->prev;
409 		next = dev_priv->tail;
410 		prev->next = NULL;
411 		next->prev = next->next = NULL;
412 		dev_priv->tail = prev;
413 		SET_AGE( &next->age, MGA_BUFFER_USED, 0 );
414 		return next->buf;
415 	}
416 
417 	DRM_DEBUG( "returning NULL!\n" );
418 	return NULL;
419 }
420 
mga_freelist_put(drm_device_t * dev,drm_buf_t * buf)421 int mga_freelist_put( drm_device_t *dev, drm_buf_t *buf )
422 {
423 	drm_mga_private_t *dev_priv = dev->dev_private;
424 	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
425 	drm_mga_freelist_t *head, *entry, *prev;
426 
427 	DRM_DEBUG( "age=0x%06lx wrap=%d\n",
428 		   buf_priv->list_entry->age.head -
429 		   dev_priv->primary->offset,
430 		   buf_priv->list_entry->age.wrap );
431 
432 	entry = buf_priv->list_entry;
433 	head = dev_priv->head;
434 
435 	if ( buf_priv->list_entry->age.head == MGA_BUFFER_USED ) {
436 		SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 );
437 		prev = dev_priv->tail;
438 		prev->next = entry;
439 		entry->prev = prev;
440 		entry->next = NULL;
441 	} else {
442 		prev = head->next;
443 		head->next = entry;
444 		prev->prev = entry;
445 		entry->prev = head;
446 		entry->next = prev;
447 	}
448 
449 	return 0;
450 }
451 
452 
453 /* ================================================================
454  * DMA initialization, cleanup
455  */
456 
mga_do_init_dma(drm_device_t * dev,drm_mga_init_t * init)457 static int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init )
458 {
459 	drm_mga_private_t *dev_priv;
460 	int ret;
461 	DRM_DEBUG( "\n" );
462 
463 	dev_priv = DRM(alloc)( sizeof(drm_mga_private_t), DRM_MEM_DRIVER );
464 	if ( !dev_priv )
465 		return -ENOMEM;
466 
467 	memset( dev_priv, 0, sizeof(drm_mga_private_t) );
468 
469 	dev_priv->chipset = init->chipset;
470 
471 	dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
472 
473 	if ( init->sgram ) {
474 		dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK;
475 	} else {
476 		dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR;
477 	}
478 	dev_priv->maccess	= init->maccess;
479 
480 	dev_priv->fb_cpp	= init->fb_cpp;
481 	dev_priv->front_offset	= init->front_offset;
482 	dev_priv->front_pitch	= init->front_pitch;
483 	dev_priv->back_offset	= init->back_offset;
484 	dev_priv->back_pitch	= init->back_pitch;
485 
486 	dev_priv->depth_cpp	= init->depth_cpp;
487 	dev_priv->depth_offset	= init->depth_offset;
488 	dev_priv->depth_pitch	= init->depth_pitch;
489 
490 	/* FIXME: Need to support AGP textures...
491 	 */
492 	dev_priv->texture_offset = init->texture_offset[0];
493 	dev_priv->texture_size = init->texture_size[0];
494 
495 	DRM_GETSAREA();
496 
497 	if(!dev_priv->sarea) {
498 		DRM_ERROR( "failed to find sarea!\n" );
499 		/* Assign dev_private so we can do cleanup. */
500 		dev->dev_private = (void *)dev_priv;
501 		mga_do_cleanup_dma( dev );
502 		return -EINVAL;
503 	}
504 
505 	DRM_FIND_MAP( dev_priv->fb, init->fb_offset );
506 	if(!dev_priv->fb) {
507 		DRM_ERROR( "failed to find framebuffer!\n" );
508 		/* Assign dev_private so we can do cleanup. */
509 		dev->dev_private = (void *)dev_priv;
510 		mga_do_cleanup_dma( dev );
511 		return -EINVAL;
512 	}
513 	DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset );
514 	if(!dev_priv->mmio) {
515 		DRM_ERROR( "failed to find mmio region!\n" );
516 		/* Assign dev_private so we can do cleanup. */
517 		dev->dev_private = (void *)dev_priv;
518 		mga_do_cleanup_dma( dev );
519 		return -EINVAL;
520 	}
521 	DRM_FIND_MAP( dev_priv->status, init->status_offset );
522 	if(!dev_priv->status) {
523 		DRM_ERROR( "failed to find status page!\n" );
524 		/* Assign dev_private so we can do cleanup. */
525 		dev->dev_private = (void *)dev_priv;
526 		mga_do_cleanup_dma( dev );
527 		return -EINVAL;
528 	}
529 
530 	DRM_FIND_MAP( dev_priv->warp, init->warp_offset );
531 	if(!dev_priv->warp) {
532 		DRM_ERROR( "failed to find warp microcode region!\n" );
533 		/* Assign dev_private so we can do cleanup. */
534 		dev->dev_private = (void *)dev_priv;
535 		mga_do_cleanup_dma( dev );
536 		return -EINVAL;
537 	}
538 	DRM_FIND_MAP( dev_priv->primary, init->primary_offset );
539 	if(!dev_priv->primary) {
540 		DRM_ERROR( "failed to find primary dma region!\n" );
541 		/* Assign dev_private so we can do cleanup. */
542 		dev->dev_private = (void *)dev_priv;
543 		mga_do_cleanup_dma( dev );
544 		return -EINVAL;
545 	}
546 	DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset );
547 	if(!dev_priv->buffers) {
548 		DRM_ERROR( "failed to find dma buffer region!\n" );
549 		/* Assign dev_private so we can do cleanup. */
550 		dev->dev_private = (void *)dev_priv;
551 		mga_do_cleanup_dma( dev );
552 		return -EINVAL;
553 	}
554 
555 	dev_priv->sarea_priv =
556 		(drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle +
557 				    init->sarea_priv_offset);
558 
559 	DRM_IOREMAP( dev_priv->warp, dev );
560 	DRM_IOREMAP( dev_priv->primary, dev );
561 	DRM_IOREMAP( dev_priv->buffers, dev );
562 
563 	if(!dev_priv->warp->handle ||
564 	   !dev_priv->primary->handle ||
565 	   !dev_priv->buffers->handle ) {
566 		DRM_ERROR( "failed to ioremap agp regions!\n" );
567 		/* Assign dev_private so we can do cleanup. */
568 		dev->dev_private = (void *)dev_priv;
569 		mga_do_cleanup_dma( dev );
570 		return -ENOMEM;
571 	}
572 
573 	ret = mga_warp_install_microcode( dev_priv );
574 	if ( ret < 0 ) {
575 		DRM_ERROR( "failed to install WARP ucode!\n" );
576 		/* Assign dev_private so we can do cleanup. */
577 		dev->dev_private = (void *)dev_priv;
578 		mga_do_cleanup_dma( dev );
579 		return ret;
580 	}
581 
582 	ret = mga_warp_init( dev_priv );
583 	if ( ret < 0 ) {
584 		DRM_ERROR( "failed to init WARP engine!\n" );
585 		/* Assign dev_private so we can do cleanup. */
586 		dev->dev_private = (void *)dev_priv;
587 		mga_do_cleanup_dma( dev );
588 		return ret;
589 	}
590 
591 	dev_priv->prim.status = (u32 *)dev_priv->status->handle;
592 
593 	mga_do_wait_for_idle( dev_priv );
594 
595 	/* Init the primary DMA registers.
596 	 */
597 	MGA_WRITE( MGA_PRIMADDRESS,
598 		   dev_priv->primary->offset | MGA_DMA_GENERAL );
599 #if 0
600 	MGA_WRITE( MGA_PRIMPTR,
601 		   virt_to_bus((void *)dev_priv->prim.status) |
602 		   MGA_PRIMPTREN0 |	/* Soft trap, SECEND, SETUPEND */
603 		   MGA_PRIMPTREN1 );	/* DWGSYNC */
604 #endif
605 
606 	dev_priv->prim.start = (u8 *)dev_priv->primary->handle;
607 	dev_priv->prim.end = ((u8 *)dev_priv->primary->handle
608 			      + dev_priv->primary->size);
609 	dev_priv->prim.size = dev_priv->primary->size;
610 
611 	dev_priv->prim.tail = 0;
612 	dev_priv->prim.space = dev_priv->prim.size;
613 	dev_priv->prim.wrapped = 0;
614 
615 	dev_priv->prim.last_flush = 0;
616 	dev_priv->prim.last_wrap = 0;
617 
618 	dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE;
619 
620 	dev_priv->prim.status[0] = dev_priv->primary->offset;
621 	dev_priv->prim.status[1] = 0;
622 
623 	dev_priv->sarea_priv->last_wrap = 0;
624 	dev_priv->sarea_priv->last_frame.head = 0;
625 	dev_priv->sarea_priv->last_frame.wrap = 0;
626 
627 	if ( mga_freelist_init( dev, dev_priv ) < 0 ) {
628 		DRM_ERROR( "could not initialize freelist\n" );
629 		/* Assign dev_private so we can do cleanup. */
630 		dev->dev_private = (void *)dev_priv;
631 		mga_do_cleanup_dma( dev );
632 		return -ENOMEM;
633 	}
634 
635 	/* Make dev_private visable to others. */
636 	dev->dev_private = (void *)dev_priv;
637 	return 0;
638 }
639 
mga_do_cleanup_dma(drm_device_t * dev)640 int mga_do_cleanup_dma( drm_device_t *dev )
641 {
642 	DRM_DEBUG( "\n" );
643 
644 	if ( dev->dev_private ) {
645 		drm_mga_private_t *dev_priv = dev->dev_private;
646 
647 		DRM_IOREMAPFREE( dev_priv->warp, dev );
648 		DRM_IOREMAPFREE( dev_priv->primary, dev );
649 		DRM_IOREMAPFREE( dev_priv->buffers, dev );
650 
651 		if ( dev_priv->head != NULL ) {
652 			mga_freelist_cleanup( dev );
653 		}
654 
655 		DRM(free)( dev->dev_private, sizeof(drm_mga_private_t),
656 			   DRM_MEM_DRIVER );
657 		dev->dev_private = NULL;
658 	}
659 
660 	return 0;
661 }
662 
mga_dma_init(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)663 int mga_dma_init( struct inode *inode, struct file *filp,
664 		  unsigned int cmd, unsigned long arg )
665 {
666 	drm_file_t *priv = filp->private_data;
667 	drm_device_t *dev = priv->dev;
668 	drm_mga_init_t init;
669 
670 	if ( copy_from_user( &init, (drm_mga_init_t *)arg, sizeof(init) ) )
671 		return -EFAULT;
672 
673 	switch ( init.func ) {
674 	case MGA_INIT_DMA:
675 		return mga_do_init_dma( dev, &init );
676 	case MGA_CLEANUP_DMA:
677 		return mga_do_cleanup_dma( dev );
678 	}
679 
680 	return -EINVAL;
681 }
682 
683 
684 /* ================================================================
685  * Primary DMA stream management
686  */
687 
mga_dma_flush(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)688 int mga_dma_flush( struct inode *inode, struct file *filp,
689 		   unsigned int cmd, unsigned long arg )
690 {
691 	drm_file_t *priv = filp->private_data;
692 	drm_device_t *dev = priv->dev;
693 	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
694 	drm_lock_t lock;
695 
696 	LOCK_TEST_WITH_RETURN( dev );
697 
698 	if ( copy_from_user( &lock, (drm_lock_t *)arg, sizeof(lock) ) )
699 		return -EFAULT;
700 
701 	DRM_DEBUG( "%s: %s%s%s\n",
702 		   __FUNCTION__,
703 		   (lock.flags & _DRM_LOCK_FLUSH) ?	"flush, " : "",
704 		   (lock.flags & _DRM_LOCK_FLUSH_ALL) ?	"flush all, " : "",
705 		   (lock.flags & _DRM_LOCK_QUIESCENT) ?	"idle, " : "" );
706 
707 	WRAP_WAIT_WITH_RETURN( dev_priv );
708 
709 	if ( lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL) ) {
710 		mga_do_dma_flush( dev_priv );
711 	}
712 
713 	if ( lock.flags & _DRM_LOCK_QUIESCENT ) {
714 #if MGA_DMA_DEBUG
715 		int ret = mga_do_wait_for_idle( dev_priv );
716 		if ( ret < 0 )
717 			DRM_INFO( "%s: -EBUSY\n", __FUNCTION__ );
718 		return ret;
719 #else
720 		return mga_do_wait_for_idle( dev_priv );
721 #endif
722 	} else {
723 		return 0;
724 	}
725 }
726 
mga_dma_reset(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)727 int mga_dma_reset( struct inode *inode, struct file *filp,
728 		   unsigned int cmd, unsigned long arg )
729 {
730 	drm_file_t *priv = filp->private_data;
731 	drm_device_t *dev = priv->dev;
732 	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
733 
734 	LOCK_TEST_WITH_RETURN( dev );
735 
736 	return mga_do_dma_reset( dev_priv );
737 }
738 
739 
740 /* ================================================================
741  * DMA buffer management
742  */
743 
mga_dma_get_buffers(drm_device_t * dev,drm_dma_t * d)744 static int mga_dma_get_buffers( drm_device_t *dev, drm_dma_t *d )
745 {
746 	drm_buf_t *buf;
747 	int i;
748 
749 	for ( i = d->granted_count ; i < d->request_count ; i++ ) {
750 		buf = mga_freelist_get( dev );
751 		if ( !buf ) return -EAGAIN;
752 
753 		buf->pid = current->pid;
754 
755 		if ( copy_to_user( &d->request_indices[i],
756 				   &buf->idx, sizeof(buf->idx) ) )
757 			return -EFAULT;
758 		if ( copy_to_user( &d->request_sizes[i],
759 				   &buf->total, sizeof(buf->total) ) )
760 			return -EFAULT;
761 
762 		d->granted_count++;
763 	}
764 	return 0;
765 }
766 
mga_dma_buffers(struct inode * inode,struct file * filp,unsigned int cmd,unsigned long arg)767 int mga_dma_buffers( struct inode *inode, struct file *filp,
768 		     unsigned int cmd, unsigned long arg )
769 {
770 	drm_file_t *priv = filp->private_data;
771 	drm_device_t *dev = priv->dev;
772 	drm_device_dma_t *dma = dev->dma;
773 	drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private;
774 	drm_dma_t d;
775 	int ret = 0;
776 
777 	LOCK_TEST_WITH_RETURN( dev );
778 
779 	if ( copy_from_user( &d, (drm_dma_t *)arg, sizeof(d) ) )
780 		return -EFAULT;
781 
782 	/* Please don't send us buffers.
783 	 */
784 	if ( d.send_count != 0 ) {
785 		DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n",
786 			   current->pid, d.send_count );
787 		return -EINVAL;
788 	}
789 
790 	/* We'll send you buffers.
791 	 */
792 	if ( d.request_count < 0 || d.request_count > dma->buf_count ) {
793 		DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n",
794 			   current->pid, d.request_count, dma->buf_count );
795 		return -EINVAL;
796 	}
797 
798 	WRAP_TEST_WITH_RETURN( dev_priv );
799 
800 	d.granted_count = 0;
801 
802 	if ( d.request_count ) {
803 		ret = mga_dma_get_buffers( dev, &d );
804 	}
805 
806 	if ( copy_to_user( (drm_dma_t *)arg, &d, sizeof(d) ) )
807 		return -EFAULT;
808 
809 	return ret;
810 }
811