mga_dma.c revision 145132
195584Sanholt/* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*-
2139749Simp * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com */
3139749Simp/*-
495584Sanholt * Copyright 1999 Precision Insight, Inc., Cedar Park, Texas.
595584Sanholt * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California.
695584Sanholt * All Rights Reserved.
795584Sanholt *
895584Sanholt * Permission is hereby granted, free of charge, to any person obtaining a
995584Sanholt * copy of this software and associated documentation files (the "Software"),
1095584Sanholt * to deal in the Software without restriction, including without limitation
1195584Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1295584Sanholt * and/or sell copies of the Software, and to permit persons to whom the
1395584Sanholt * Software is furnished to do so, subject to the following conditions:
1495584Sanholt *
1595584Sanholt * The above copyright notice and this permission notice (including the next
1695584Sanholt * paragraph) shall be included in all copies or substantial portions of the
1795584Sanholt * Software.
1895584Sanholt *
1995584Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2095584Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2195584Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
2295584Sanholt * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
2395584Sanholt * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
2495584Sanholt * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2595584Sanholt * DEALINGS IN THE SOFTWARE.
2695584Sanholt *
2795584Sanholt * Authors:
2895584Sanholt *    Rickard E. (Rik) Faith <faith@valinux.com>
2995584Sanholt *    Jeff Hartmann <jhartmann@valinux.com>
30112015Sanholt *    Keith Whitwell <keith@tungstengraphics.com>
3195584Sanholt *
3295584Sanholt * Rewritten by:
3395584Sanholt *    Gareth Hughes <gareth@valinux.com>
3495584Sanholt *
3595584Sanholt * $FreeBSD: head/sys/dev/drm/mga_dma.c 145132 2005-04-16 03:44:47Z anholt $
3695584Sanholt */
3795584Sanholt
3895584Sanholt#include "dev/drm/drmP.h"
39112015Sanholt#include "dev/drm/drm.h"
4095746Sanholt#include "dev/drm/mga_drm.h"
4195584Sanholt#include "dev/drm/mga_drv.h"
4295584Sanholt
4395584Sanholt#define MGA_DEFAULT_USEC_TIMEOUT	10000
4495584Sanholt#define MGA_FREELIST_DEBUG		0
4595584Sanholt
46145132Sanholtstatic int mga_do_cleanup_dma(drm_device_t * dev);
4795584Sanholt
4895584Sanholt/* ================================================================
4995584Sanholt * Engine control
5095584Sanholt */
5195584Sanholt
52145132Sanholtint mga_do_wait_for_idle(drm_mga_private_t * dev_priv)
5395584Sanholt{
5495584Sanholt	u32 status = 0;
5595584Sanholt	int i;
56145132Sanholt	DRM_DEBUG("\n");
5795584Sanholt
58145132Sanholt	for (i = 0; i < dev_priv->usec_timeout; i++) {
59145132Sanholt		status = MGA_READ(MGA_STATUS) & MGA_ENGINE_IDLE_MASK;
60145132Sanholt		if (status == MGA_ENDPRDMASTS) {
61145132Sanholt			MGA_WRITE8(MGA_CRTC_INDEX, 0);
6295584Sanholt			return 0;
6395584Sanholt		}
64145132Sanholt		DRM_UDELAY(1);
6595584Sanholt	}
6695584Sanholt
6795584Sanholt#if MGA_DMA_DEBUG
68145132Sanholt	DRM_ERROR("failed!\n");
69145132Sanholt	DRM_INFO("   status=0x%08x\n", status);
7095584Sanholt#endif
71112015Sanholt	return DRM_ERR(EBUSY);
7295584Sanholt}
7395584Sanholt
74145132Sanholtstatic int mga_do_dma_reset(drm_mga_private_t * dev_priv)
7595584Sanholt{
7695584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
7795584Sanholt	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
7895584Sanholt
79145132Sanholt	DRM_DEBUG("\n");
8095584Sanholt
8195584Sanholt	/* The primary DMA stream should look like new right about now.
8295584Sanholt	 */
8395584Sanholt	primary->tail = 0;
8495584Sanholt	primary->space = primary->size;
8595584Sanholt	primary->last_flush = 0;
8695584Sanholt
8795584Sanholt	sarea_priv->last_wrap = 0;
8895584Sanholt
8995584Sanholt	/* FIXME: Reset counters, buffer ages etc...
9095584Sanholt	 */
9195584Sanholt
9295584Sanholt	/* FIXME: What else do we need to reinitialize?  WARP stuff?
9395584Sanholt	 */
9495584Sanholt
9595584Sanholt	return 0;
9695584Sanholt}
9795584Sanholt
9895584Sanholt/* ================================================================
9995584Sanholt * Primary DMA stream
10095584Sanholt */
10195584Sanholt
102145132Sanholtvoid mga_do_dma_flush(drm_mga_private_t * dev_priv)
10395584Sanholt{
10495584Sanholt	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
10595584Sanholt	u32 head, tail;
106112015Sanholt	u32 status = 0;
107112015Sanholt	int i;
108145132Sanholt	DMA_LOCALS;
109145132Sanholt	DRM_DEBUG("\n");
11095584Sanholt
111145132Sanholt	/* We need to wait so that we can do an safe flush */
112145132Sanholt	for (i = 0; i < dev_priv->usec_timeout; i++) {
113145132Sanholt		status = MGA_READ(MGA_STATUS) & MGA_ENGINE_IDLE_MASK;
114145132Sanholt		if (status == MGA_ENDPRDMASTS)
115145132Sanholt			break;
116145132Sanholt		DRM_UDELAY(1);
117112015Sanholt	}
118112015Sanholt
119145132Sanholt	if (primary->tail == primary->last_flush) {
120145132Sanholt		DRM_DEBUG("   bailing out...\n");
12195584Sanholt		return;
12295584Sanholt	}
12395584Sanholt
12495584Sanholt	tail = primary->tail + dev_priv->primary->offset;
12595584Sanholt
12695584Sanholt	/* We need to pad the stream between flushes, as the card
12795584Sanholt	 * actually (partially?) reads the first of these commands.
12895584Sanholt	 * See page 4-16 in the G400 manual, middle of the page or so.
12995584Sanholt	 */
130145132Sanholt	BEGIN_DMA(1);
13195584Sanholt
132145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
133145132Sanholt		  MGA_DMAPAD, 0x00000000,
134145132Sanholt		  MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
13595584Sanholt
13695584Sanholt	ADVANCE_DMA();
13795584Sanholt
13895584Sanholt	primary->last_flush = primary->tail;
13995584Sanholt
140145132Sanholt	head = MGA_READ(MGA_PRIMADDRESS);
14195584Sanholt
142145132Sanholt	if (head <= tail) {
14395584Sanholt		primary->space = primary->size - primary->tail;
14495584Sanholt	} else {
14595584Sanholt		primary->space = head - tail;
14695584Sanholt	}
14795584Sanholt
148145132Sanholt	DRM_DEBUG("   head = 0x%06lx\n", head - dev_priv->primary->offset);
149145132Sanholt	DRM_DEBUG("   tail = 0x%06lx\n", tail - dev_priv->primary->offset);
150145132Sanholt	DRM_DEBUG("  space = 0x%06x\n", primary->space);
15195584Sanholt
15295584Sanholt	mga_flush_write_combine();
153145132Sanholt	MGA_WRITE(MGA_PRIMEND, tail | MGA_PAGPXFER);
15495584Sanholt
155145132Sanholt	DRM_DEBUG("done.\n");
15695584Sanholt}
15795584Sanholt
158145132Sanholtvoid mga_do_dma_wrap_start(drm_mga_private_t * dev_priv)
15995584Sanholt{
16095584Sanholt	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
16195584Sanholt	u32 head, tail;
16295584Sanholt	DMA_LOCALS;
163145132Sanholt	DRM_DEBUG("\n");
16495584Sanholt
16595584Sanholt	BEGIN_DMA_WRAP();
16695584Sanholt
167145132Sanholt	DMA_BLOCK(MGA_DMAPAD, 0x00000000,
168145132Sanholt		  MGA_DMAPAD, 0x00000000,
169145132Sanholt		  MGA_DMAPAD, 0x00000000, MGA_DMAPAD, 0x00000000);
17095584Sanholt
17195584Sanholt	ADVANCE_DMA();
17295584Sanholt
17395584Sanholt	tail = primary->tail + dev_priv->primary->offset;
17495584Sanholt
17595584Sanholt	primary->tail = 0;
17695584Sanholt	primary->last_flush = 0;
17795584Sanholt	primary->last_wrap++;
17895584Sanholt
179145132Sanholt	head = MGA_READ(MGA_PRIMADDRESS);
18095584Sanholt
181145132Sanholt	if (head == dev_priv->primary->offset) {
18295584Sanholt		primary->space = primary->size;
18395584Sanholt	} else {
18495584Sanholt		primary->space = head - dev_priv->primary->offset;
18595584Sanholt	}
18695584Sanholt
187145132Sanholt	DRM_DEBUG("   head = 0x%06lx\n", head - dev_priv->primary->offset);
188145132Sanholt	DRM_DEBUG("   tail = 0x%06x\n", primary->tail);
189145132Sanholt	DRM_DEBUG("   wrap = %d\n", primary->last_wrap);
190145132Sanholt	DRM_DEBUG("  space = 0x%06x\n", primary->space);
19195584Sanholt
19295584Sanholt	mga_flush_write_combine();
193145132Sanholt	MGA_WRITE(MGA_PRIMEND, tail | MGA_PAGPXFER);
19495584Sanholt
195145132Sanholt	set_bit(0, &primary->wrapped);
196145132Sanholt	DRM_DEBUG("done.\n");
19795584Sanholt}
19895584Sanholt
199145132Sanholtvoid mga_do_dma_wrap_end(drm_mga_private_t * dev_priv)
20095584Sanholt{
20195584Sanholt	drm_mga_primary_buffer_t *primary = &dev_priv->prim;
20295584Sanholt	drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv;
20395584Sanholt	u32 head = dev_priv->primary->offset;
204145132Sanholt	DRM_DEBUG("\n");
20595584Sanholt
20695584Sanholt	sarea_priv->last_wrap++;
207145132Sanholt	DRM_DEBUG("   wrap = %d\n", sarea_priv->last_wrap);
20895584Sanholt
20995584Sanholt	mga_flush_write_combine();
210145132Sanholt	MGA_WRITE(MGA_PRIMADDRESS, head | MGA_DMA_GENERAL);
21195584Sanholt
212145132Sanholt	clear_bit(0, &primary->wrapped);
213145132Sanholt	DRM_DEBUG("done.\n");
21495584Sanholt}
21595584Sanholt
21695584Sanholt/* ================================================================
21795584Sanholt * Freelist management
21895584Sanholt */
21995584Sanholt
22095584Sanholt#define MGA_BUFFER_USED		~0
22195584Sanholt#define MGA_BUFFER_FREE		0
22295584Sanholt
22395584Sanholt#if MGA_FREELIST_DEBUG
224145132Sanholtstatic void mga_freelist_print(drm_device_t * dev)
22595584Sanholt{
22695584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
22795584Sanholt	drm_mga_freelist_t *entry;
22895584Sanholt
229145132Sanholt	DRM_INFO("\n");
230145132Sanholt	DRM_INFO("current dispatch: last=0x%x done=0x%x\n",
231145132Sanholt		 dev_priv->sarea_priv->last_dispatch,
232145132Sanholt		 (unsigned int)(MGA_READ(MGA_PRIMADDRESS) -
233145132Sanholt				dev_priv->primary->offset));
234145132Sanholt	DRM_INFO("current freelist:\n");
23595584Sanholt
236145132Sanholt	for (entry = dev_priv->head->next; entry; entry = entry->next) {
237145132Sanholt		DRM_INFO("   %p   idx=%2d  age=0x%x 0x%06lx\n",
238145132Sanholt			 entry, entry->buf->idx, entry->age.head,
239145132Sanholt			 entry->age.head - dev_priv->primary->offset);
24095584Sanholt	}
241145132Sanholt	DRM_INFO("\n");
24295584Sanholt}
24395584Sanholt#endif
24495584Sanholt
245145132Sanholtstatic int mga_freelist_init(drm_device_t * dev, drm_mga_private_t * dev_priv)
24695584Sanholt{
24795584Sanholt	drm_device_dma_t *dma = dev->dma;
24895584Sanholt	drm_buf_t *buf;
24995584Sanholt	drm_mga_buf_priv_t *buf_priv;
25095584Sanholt	drm_mga_freelist_t *entry;
25195584Sanholt	int i;
252145132Sanholt	DRM_DEBUG("count=%d\n", dma->buf_count);
25395584Sanholt
254145132Sanholt	dev_priv->head = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
255145132Sanholt	if (dev_priv->head == NULL)
256112015Sanholt		return DRM_ERR(ENOMEM);
25795584Sanholt
258145132Sanholt	memset(dev_priv->head, 0, sizeof(drm_mga_freelist_t));
259145132Sanholt	SET_AGE(&dev_priv->head->age, MGA_BUFFER_USED, 0);
26095584Sanholt
261145132Sanholt	for (i = 0; i < dma->buf_count; i++) {
26295584Sanholt		buf = dma->buflist[i];
263145132Sanholt		buf_priv = buf->dev_private;
26495584Sanholt
265145132Sanholt		entry = drm_alloc(sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
266145132Sanholt		if (entry == NULL)
267112015Sanholt			return DRM_ERR(ENOMEM);
26895584Sanholt
269145132Sanholt		memset(entry, 0, sizeof(drm_mga_freelist_t));
27095584Sanholt
27195584Sanholt		entry->next = dev_priv->head->next;
27295584Sanholt		entry->prev = dev_priv->head;
273145132Sanholt		SET_AGE(&entry->age, MGA_BUFFER_FREE, 0);
27495584Sanholt		entry->buf = buf;
27595584Sanholt
276145132Sanholt		if (dev_priv->head->next != NULL)
27795584Sanholt			dev_priv->head->next->prev = entry;
278145132Sanholt		if (entry->next == NULL)
27995584Sanholt			dev_priv->tail = entry;
28095584Sanholt
28195584Sanholt		buf_priv->list_entry = entry;
28295584Sanholt		buf_priv->discard = 0;
28395584Sanholt		buf_priv->dispatched = 0;
28495584Sanholt
28595584Sanholt		dev_priv->head->next = entry;
28695584Sanholt	}
28795584Sanholt
28895584Sanholt	return 0;
28995584Sanholt}
29095584Sanholt
291145132Sanholtstatic void mga_freelist_cleanup(drm_device_t * dev)
29295584Sanholt{
29395584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
29495584Sanholt	drm_mga_freelist_t *entry;
29595584Sanholt	drm_mga_freelist_t *next;
296145132Sanholt	DRM_DEBUG("\n");
29795584Sanholt
29895584Sanholt	entry = dev_priv->head;
299145132Sanholt	while (entry) {
30095584Sanholt		next = entry->next;
301145132Sanholt		drm_free(entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER);
30295584Sanholt		entry = next;
30395584Sanholt	}
30495584Sanholt
30595584Sanholt	dev_priv->head = dev_priv->tail = NULL;
30695584Sanholt}
30795584Sanholt
30895584Sanholt#if 0
30995584Sanholt/* FIXME: Still needed?
31095584Sanholt */
311145132Sanholtstatic void mga_freelist_reset(drm_device_t * dev)
31295584Sanholt{
31395584Sanholt	drm_device_dma_t *dma = dev->dma;
31495584Sanholt	drm_buf_t *buf;
31595584Sanholt	drm_mga_buf_priv_t *buf_priv;
31695584Sanholt	int i;
31795584Sanholt
318145132Sanholt	for (i = 0; i < dma->buf_count; i++) {
31995584Sanholt		buf = dma->buflist[i];
320145132Sanholt		buf_priv = buf->dev_private;
321145132Sanholt		SET_AGE(&buf_priv->list_entry->age, MGA_BUFFER_FREE, 0);
32295584Sanholt	}
32395584Sanholt}
32495584Sanholt#endif
32595584Sanholt
326145132Sanholtstatic drm_buf_t *mga_freelist_get(drm_device_t * dev)
32795584Sanholt{
32895584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
32995584Sanholt	drm_mga_freelist_t *next;
33095584Sanholt	drm_mga_freelist_t *prev;
33195584Sanholt	drm_mga_freelist_t *tail = dev_priv->tail;
33295584Sanholt	u32 head, wrap;
333145132Sanholt	DRM_DEBUG("\n");
33495584Sanholt
335145132Sanholt	head = MGA_READ(MGA_PRIMADDRESS);
33695584Sanholt	wrap = dev_priv->sarea_priv->last_wrap;
33795584Sanholt
338145132Sanholt	DRM_DEBUG("   tail=0x%06lx %d\n",
339145132Sanholt		  tail->age.head ?
340145132Sanholt		  tail->age.head - dev_priv->primary->offset : 0,
341145132Sanholt		  tail->age.wrap);
342145132Sanholt	DRM_DEBUG("   head=0x%06lx %d\n",
343145132Sanholt		  head - dev_priv->primary->offset, wrap);
34495584Sanholt
345145132Sanholt	if (TEST_AGE(&tail->age, head, wrap)) {
34695584Sanholt		prev = dev_priv->tail->prev;
34795584Sanholt		next = dev_priv->tail;
34895584Sanholt		prev->next = NULL;
34995584Sanholt		next->prev = next->next = NULL;
35095584Sanholt		dev_priv->tail = prev;
351145132Sanholt		SET_AGE(&next->age, MGA_BUFFER_USED, 0);
35295584Sanholt		return next->buf;
35395584Sanholt	}
35495584Sanholt
355145132Sanholt	DRM_DEBUG("returning NULL!\n");
35695584Sanholt	return NULL;
35795584Sanholt}
35895584Sanholt
359145132Sanholtint mga_freelist_put(drm_device_t * dev, drm_buf_t * buf)
36095584Sanholt{
36195584Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
36295584Sanholt	drm_mga_buf_priv_t *buf_priv = buf->dev_private;
36395584Sanholt	drm_mga_freelist_t *head, *entry, *prev;
36495584Sanholt
365145132Sanholt	DRM_DEBUG("age=0x%06lx wrap=%d\n",
366145132Sanholt		  buf_priv->list_entry->age.head -
367145132Sanholt		  dev_priv->primary->offset, buf_priv->list_entry->age.wrap);
36895584Sanholt
36995584Sanholt	entry = buf_priv->list_entry;
37095584Sanholt	head = dev_priv->head;
37195584Sanholt
372145132Sanholt	if (buf_priv->list_entry->age.head == MGA_BUFFER_USED) {
373145132Sanholt		SET_AGE(&entry->age, MGA_BUFFER_FREE, 0);
37495584Sanholt		prev = dev_priv->tail;
37595584Sanholt		prev->next = entry;
37695584Sanholt		entry->prev = prev;
37795584Sanholt		entry->next = NULL;
37895584Sanholt	} else {
37995584Sanholt		prev = head->next;
38095584Sanholt		head->next = entry;
38195584Sanholt		prev->prev = entry;
38295584Sanholt		entry->prev = head;
38395584Sanholt		entry->next = prev;
38495584Sanholt	}
38595584Sanholt
38695584Sanholt	return 0;
38795584Sanholt}
38895584Sanholt
38995584Sanholt/* ================================================================
39095584Sanholt * DMA initialization, cleanup
39195584Sanholt */
39295584Sanholt
393145132Sanholtstatic int mga_do_init_dma(drm_device_t * dev, drm_mga_init_t * init)
39495584Sanholt{
39595584Sanholt	drm_mga_private_t *dev_priv;
39695584Sanholt	int ret;
397145132Sanholt	DRM_DEBUG("\n");
39895584Sanholt
399145132Sanholt	dev_priv = drm_alloc(sizeof(drm_mga_private_t), DRM_MEM_DRIVER);
400145132Sanholt	if (!dev_priv)
401112015Sanholt		return DRM_ERR(ENOMEM);
40295584Sanholt
403145132Sanholt	memset(dev_priv, 0, sizeof(drm_mga_private_t));
40495584Sanholt
40595584Sanholt	dev_priv->chipset = init->chipset;
40695584Sanholt
40795584Sanholt	dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT;
40895584Sanholt
409145132Sanholt	if (init->sgram) {
41095584Sanholt		dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK;
41195584Sanholt	} else {
41295584Sanholt		dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR;
41395584Sanholt	}
414145132Sanholt	dev_priv->maccess = init->maccess;
41595584Sanholt
416145132Sanholt	dev_priv->fb_cpp = init->fb_cpp;
417145132Sanholt	dev_priv->front_offset = init->front_offset;
418145132Sanholt	dev_priv->front_pitch = init->front_pitch;
419145132Sanholt	dev_priv->back_offset = init->back_offset;
420145132Sanholt	dev_priv->back_pitch = init->back_pitch;
42195584Sanholt
422145132Sanholt	dev_priv->depth_cpp = init->depth_cpp;
423145132Sanholt	dev_priv->depth_offset = init->depth_offset;
424145132Sanholt	dev_priv->depth_pitch = init->depth_pitch;
42595584Sanholt
42695584Sanholt	/* FIXME: Need to support AGP textures...
42795584Sanholt	 */
42895584Sanholt	dev_priv->texture_offset = init->texture_offset[0];
42995584Sanholt	dev_priv->texture_size = init->texture_size[0];
43095584Sanholt
431112015Sanholt	DRM_GETSAREA();
43295584Sanholt
433145132Sanholt	if (!dev_priv->sarea) {
434145132Sanholt		DRM_ERROR("failed to find sarea!\n");
43595584Sanholt		/* Assign dev_private so we can do cleanup. */
43695584Sanholt		dev->dev_private = (void *)dev_priv;
437145132Sanholt		mga_do_cleanup_dma(dev);
438112015Sanholt		return DRM_ERR(EINVAL);
43995584Sanholt	}
44095584Sanholt
441145132Sanholt	dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset);
442145132Sanholt	if (!dev_priv->mmio) {
443145132Sanholt		DRM_ERROR("failed to find mmio region!\n");
44495584Sanholt		/* Assign dev_private so we can do cleanup. */
44595584Sanholt		dev->dev_private = (void *)dev_priv;
446145132Sanholt		mga_do_cleanup_dma(dev);
447112015Sanholt		return DRM_ERR(EINVAL);
44895584Sanholt	}
449145132Sanholt	dev_priv->status = drm_core_findmap(dev, init->status_offset);
450145132Sanholt	if (!dev_priv->status) {
451145132Sanholt		DRM_ERROR("failed to find status page!\n");
45295584Sanholt		/* Assign dev_private so we can do cleanup. */
45395584Sanholt		dev->dev_private = (void *)dev_priv;
454145132Sanholt		mga_do_cleanup_dma(dev);
455112015Sanholt		return DRM_ERR(EINVAL);
45695584Sanholt	}
457145132Sanholt	dev_priv->warp = drm_core_findmap(dev, init->warp_offset);
458145132Sanholt	if (!dev_priv->warp) {
459145132Sanholt		DRM_ERROR("failed to find warp microcode region!\n");
46095584Sanholt		/* Assign dev_private so we can do cleanup. */
46195584Sanholt		dev->dev_private = (void *)dev_priv;
462145132Sanholt		mga_do_cleanup_dma(dev);
463112015Sanholt		return DRM_ERR(EINVAL);
46495584Sanholt	}
465145132Sanholt	dev_priv->primary = drm_core_findmap(dev, init->primary_offset);
466145132Sanholt	if (!dev_priv->primary) {
467145132Sanholt		DRM_ERROR("failed to find primary dma region!\n");
46895584Sanholt		/* Assign dev_private so we can do cleanup. */
46995584Sanholt		dev->dev_private = (void *)dev_priv;
470145132Sanholt		mga_do_cleanup_dma(dev);
471112015Sanholt		return DRM_ERR(EINVAL);
47295584Sanholt	}
473145132Sanholt	dev->agp_buffer_map = drm_core_findmap(dev, init->buffers_offset);
474145132Sanholt	if (!dev->agp_buffer_map) {
475145132Sanholt		DRM_ERROR("failed to find dma buffer region!\n");
47695584Sanholt		/* Assign dev_private so we can do cleanup. */
47795584Sanholt		dev->dev_private = (void *)dev_priv;
478145132Sanholt		mga_do_cleanup_dma(dev);
479112015Sanholt		return DRM_ERR(EINVAL);
48095584Sanholt	}
48195584Sanholt
48295584Sanholt	dev_priv->sarea_priv =
483145132Sanholt	    (drm_mga_sarea_t *) ((u8 *) dev_priv->sarea->handle +
484145132Sanholt				 init->sarea_priv_offset);
48595584Sanholt
486145132Sanholt	drm_core_ioremap(dev_priv->warp, dev);
487145132Sanholt	drm_core_ioremap(dev_priv->primary, dev);
488145132Sanholt	drm_core_ioremap(dev->agp_buffer_map, dev);
48995584Sanholt
490145132Sanholt	if (!dev_priv->warp->handle ||
491145132Sanholt	    !dev_priv->primary->handle || !dev->agp_buffer_map->handle) {
492145132Sanholt		DRM_ERROR("failed to ioremap agp regions!\n");
49395584Sanholt		/* Assign dev_private so we can do cleanup. */
49495584Sanholt		dev->dev_private = (void *)dev_priv;
495145132Sanholt		mga_do_cleanup_dma(dev);
496112015Sanholt		return DRM_ERR(ENOMEM);
49795584Sanholt	}
49895584Sanholt
499145132Sanholt	ret = mga_warp_install_microcode(dev_priv);
500145132Sanholt	if (ret < 0) {
501145132Sanholt		DRM_ERROR("failed to install WARP ucode!\n");
50295584Sanholt		/* Assign dev_private so we can do cleanup. */
50395584Sanholt		dev->dev_private = (void *)dev_priv;
504145132Sanholt		mga_do_cleanup_dma(dev);
505112015Sanholt		return ret;
50695584Sanholt	}
50795584Sanholt
508145132Sanholt	ret = mga_warp_init(dev_priv);
509145132Sanholt	if (ret < 0) {
510145132Sanholt		DRM_ERROR("failed to init WARP engine!\n");
51195584Sanholt		/* Assign dev_private so we can do cleanup. */
51295584Sanholt		dev->dev_private = (void *)dev_priv;
513145132Sanholt		mga_do_cleanup_dma(dev);
514112015Sanholt		return ret;
51595584Sanholt	}
51695584Sanholt
517145132Sanholt	dev_priv->prim.status = (u32 *) dev_priv->status->handle;
51895584Sanholt
519145132Sanholt	mga_do_wait_for_idle(dev_priv);
52095584Sanholt
52195584Sanholt	/* Init the primary DMA registers.
52295584Sanholt	 */
523145132Sanholt	MGA_WRITE(MGA_PRIMADDRESS, dev_priv->primary->offset | MGA_DMA_GENERAL);
52495584Sanholt#if 0
525145132Sanholt	MGA_WRITE(MGA_PRIMPTR, virt_to_bus((void *)dev_priv->prim.status) | MGA_PRIMPTREN0 |	/* Soft trap, SECEND, SETUPEND */
526145132Sanholt		  MGA_PRIMPTREN1);	/* DWGSYNC */
52795584Sanholt#endif
52895584Sanholt
529145132Sanholt	dev_priv->prim.start = (u8 *) dev_priv->primary->handle;
530145132Sanholt	dev_priv->prim.end = ((u8 *) dev_priv->primary->handle
53195584Sanholt			      + dev_priv->primary->size);
53295584Sanholt	dev_priv->prim.size = dev_priv->primary->size;
53395584Sanholt
53495584Sanholt	dev_priv->prim.tail = 0;
53595584Sanholt	dev_priv->prim.space = dev_priv->prim.size;
53695584Sanholt	dev_priv->prim.wrapped = 0;
53795584Sanholt
53895584Sanholt	dev_priv->prim.last_flush = 0;
53995584Sanholt	dev_priv->prim.last_wrap = 0;
54095584Sanholt
54195584Sanholt	dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE;
54295584Sanholt
54395584Sanholt	dev_priv->prim.status[0] = dev_priv->primary->offset;
54495584Sanholt	dev_priv->prim.status[1] = 0;
54595584Sanholt
54695584Sanholt	dev_priv->sarea_priv->last_wrap = 0;
54795584Sanholt	dev_priv->sarea_priv->last_frame.head = 0;
54895584Sanholt	dev_priv->sarea_priv->last_frame.wrap = 0;
54995584Sanholt
550145132Sanholt	if (mga_freelist_init(dev, dev_priv) < 0) {
551145132Sanholt		DRM_ERROR("could not initialize freelist\n");
55295584Sanholt		/* Assign dev_private so we can do cleanup. */
55395584Sanholt		dev->dev_private = (void *)dev_priv;
554145132Sanholt		mga_do_cleanup_dma(dev);
555112015Sanholt		return DRM_ERR(ENOMEM);
55695584Sanholt	}
55795584Sanholt
55895584Sanholt	/* Make dev_private visable to others. */
55995584Sanholt	dev->dev_private = (void *)dev_priv;
56095584Sanholt	return 0;
56195584Sanholt}
56295584Sanholt
563145132Sanholtstatic int mga_do_cleanup_dma(drm_device_t * dev)
56495584Sanholt{
565145132Sanholt	DRM_DEBUG("\n");
56695584Sanholt
567119098Sanholt	/* Make sure interrupts are disabled here because the uninstall ioctl
568119098Sanholt	 * may not have been called from userspace and after dev_private
569119098Sanholt	 * is freed, it's too late.
570119098Sanholt	 */
571145132Sanholt	if (dev->irq_enabled)
572145132Sanholt		drm_irq_uninstall(dev);
573119098Sanholt
574145132Sanholt	if (dev->dev_private) {
57595584Sanholt		drm_mga_private_t *dev_priv = dev->dev_private;
57695584Sanholt
577145132Sanholt		if (dev_priv->warp != NULL)
578145132Sanholt			drm_core_ioremapfree(dev_priv->warp, dev);
579145132Sanholt		if (dev_priv->primary != NULL)
580145132Sanholt			drm_core_ioremapfree(dev_priv->primary, dev);
581145132Sanholt		if (dev->agp_buffer_map != NULL) {
582145132Sanholt			drm_core_ioremapfree(dev->agp_buffer_map, dev);
583145132Sanholt			dev->agp_buffer_map = NULL;
584145132Sanholt		}
58595584Sanholt
586145132Sanholt		if (dev_priv->head != NULL) {
587145132Sanholt			mga_freelist_cleanup(dev);
58895584Sanholt		}
58995584Sanholt
590145132Sanholt		drm_free(dev->dev_private, sizeof(drm_mga_private_t),
591145132Sanholt			 DRM_MEM_DRIVER);
59295584Sanholt		dev->dev_private = NULL;
59395584Sanholt	}
59495584Sanholt
59595584Sanholt	return 0;
59695584Sanholt}
59795584Sanholt
598145132Sanholtint mga_dma_init(DRM_IOCTL_ARGS)
59995584Sanholt{
600112015Sanholt	DRM_DEVICE;
60195584Sanholt	drm_mga_init_t init;
60295584Sanholt
603145132Sanholt	LOCK_TEST_WITH_RETURN(dev, filp);
604119098Sanholt
605145132Sanholt	DRM_COPY_FROM_USER_IOCTL(init, (drm_mga_init_t __user *) data,
606145132Sanholt				 sizeof(init));
60795584Sanholt
608145132Sanholt	switch (init.func) {
60995584Sanholt	case MGA_INIT_DMA:
610145132Sanholt		return mga_do_init_dma(dev, &init);
61195584Sanholt	case MGA_CLEANUP_DMA:
612145132Sanholt		return mga_do_cleanup_dma(dev);
61395584Sanholt	}
61495584Sanholt
615112015Sanholt	return DRM_ERR(EINVAL);
61695584Sanholt}
61795584Sanholt
61895584Sanholt/* ================================================================
61995584Sanholt * Primary DMA stream management
62095584Sanholt */
62195584Sanholt
622145132Sanholtint mga_dma_flush(DRM_IOCTL_ARGS)
62395584Sanholt{
624112015Sanholt	DRM_DEVICE;
625145132Sanholt	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
62695584Sanholt	drm_lock_t lock;
62795584Sanholt
628145132Sanholt	LOCK_TEST_WITH_RETURN(dev, filp);
62995584Sanholt
630145132Sanholt	DRM_COPY_FROM_USER_IOCTL(lock, (drm_lock_t __user *) data,
631145132Sanholt				 sizeof(lock));
63295584Sanholt
633145132Sanholt	DRM_DEBUG("%s%s%s\n",
634145132Sanholt		  (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "",
635145132Sanholt		  (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "",
636145132Sanholt		  (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "");
63795584Sanholt
638145132Sanholt	WRAP_WAIT_WITH_RETURN(dev_priv);
63995584Sanholt
640145132Sanholt	if (lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL)) {
641145132Sanholt		mga_do_dma_flush(dev_priv);
64295584Sanholt	}
64395584Sanholt
644145132Sanholt	if (lock.flags & _DRM_LOCK_QUIESCENT) {
64595584Sanholt#if MGA_DMA_DEBUG
646145132Sanholt		int ret = mga_do_wait_for_idle(dev_priv);
647145132Sanholt		if (ret < 0)
648145132Sanholt			DRM_INFO("%s: -EBUSY\n", __FUNCTION__);
64995584Sanholt		return ret;
65095584Sanholt#else
651145132Sanholt		return mga_do_wait_for_idle(dev_priv);
65295584Sanholt#endif
65395584Sanholt	} else {
65495584Sanholt		return 0;
65595584Sanholt	}
65695584Sanholt}
65795584Sanholt
658145132Sanholtint mga_dma_reset(DRM_IOCTL_ARGS)
65995584Sanholt{
660112015Sanholt	DRM_DEVICE;
661145132Sanholt	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
66295584Sanholt
663145132Sanholt	LOCK_TEST_WITH_RETURN(dev, filp);
66495584Sanholt
665145132Sanholt	return mga_do_dma_reset(dev_priv);
66695584Sanholt}
66795584Sanholt
66895584Sanholt/* ================================================================
66995584Sanholt * DMA buffer management
67095584Sanholt */
67195584Sanholt
672145132Sanholtstatic int mga_dma_get_buffers(DRMFILE filp, drm_device_t * dev, drm_dma_t * d)
67395584Sanholt{
67495584Sanholt	drm_buf_t *buf;
67595584Sanholt	int i;
67695584Sanholt
677145132Sanholt	for (i = d->granted_count; i < d->request_count; i++) {
678145132Sanholt		buf = mga_freelist_get(dev);
679145132Sanholt		if (!buf)
680145132Sanholt			return DRM_ERR(EAGAIN);
68195584Sanholt
682113995Sanholt		buf->filp = filp;
68395584Sanholt
684145132Sanholt		if (DRM_COPY_TO_USER(&d->request_indices[i],
685145132Sanholt				     &buf->idx, sizeof(buf->idx)))
686112015Sanholt			return DRM_ERR(EFAULT);
687145132Sanholt		if (DRM_COPY_TO_USER(&d->request_sizes[i],
688145132Sanholt				     &buf->total, sizeof(buf->total)))
689112015Sanholt			return DRM_ERR(EFAULT);
69095584Sanholt
69195584Sanholt		d->granted_count++;
69295584Sanholt	}
69395584Sanholt	return 0;
69495584Sanholt}
69595584Sanholt
696145132Sanholtint mga_dma_buffers(DRM_IOCTL_ARGS)
69795584Sanholt{
698112015Sanholt	DRM_DEVICE;
69995584Sanholt	drm_device_dma_t *dma = dev->dma;
700145132Sanholt	drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
701145132Sanholt	drm_dma_t __user *argp = (void __user *)data;
70295584Sanholt	drm_dma_t d;
70395584Sanholt	int ret = 0;
70495584Sanholt
705145132Sanholt	LOCK_TEST_WITH_RETURN(dev, filp);
70695584Sanholt
707145132Sanholt	DRM_COPY_FROM_USER_IOCTL(d, argp, sizeof(d));
70895584Sanholt
70995584Sanholt	/* Please don't send us buffers.
71095584Sanholt	 */
711145132Sanholt	if (d.send_count != 0) {
712145132Sanholt		DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n",
713145132Sanholt			  DRM_CURRENTPID, d.send_count);
714112015Sanholt		return DRM_ERR(EINVAL);
71595584Sanholt	}
71695584Sanholt
71795584Sanholt	/* We'll send you buffers.
71895584Sanholt	 */
719145132Sanholt	if (d.request_count < 0 || d.request_count > dma->buf_count) {
720145132Sanholt		DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n",
721145132Sanholt			  DRM_CURRENTPID, d.request_count, dma->buf_count);
722112015Sanholt		return DRM_ERR(EINVAL);
72395584Sanholt	}
72495584Sanholt
725145132Sanholt	WRAP_TEST_WITH_RETURN(dev_priv);
72695584Sanholt
72795584Sanholt	d.granted_count = 0;
72895584Sanholt
729145132Sanholt	if (d.request_count) {
730145132Sanholt		ret = mga_dma_get_buffers(filp, dev, &d);
73195584Sanholt	}
73295584Sanholt
733145132Sanholt	DRM_COPY_TO_USER_IOCTL(argp, d, sizeof(d));
73495584Sanholt
73595584Sanholt	return ret;
73695584Sanholt}
737145132Sanholt
738145132Sanholtvoid mga_driver_pretakedown(drm_device_t * dev)
739145132Sanholt{
740145132Sanholt	mga_do_cleanup_dma(dev);
741145132Sanholt}
742145132Sanholt
743145132Sanholtint mga_driver_dma_quiescent(drm_device_t * dev)
744145132Sanholt{
745145132Sanholt	drm_mga_private_t *dev_priv = dev->dev_private;
746145132Sanholt	return mga_do_wait_for_idle(dev_priv);
747145132Sanholt}
748