mga_dma.c revision 95746
195584Sanholt/* mga_dma.c -- DMA support for mga g200/g400 -*- linux-c -*- 295584Sanholt * Created: Mon Dec 13 01:50:01 1999 by jhartmann@precisioninsight.com 395584Sanholt * 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> 3095584Sanholt * Keith Whitwell <keithw@valinux.com> 3195584Sanholt * 3295584Sanholt * Rewritten by: 3395584Sanholt * Gareth Hughes <gareth@valinux.com> 3495584Sanholt * 3595584Sanholt * $FreeBSD: head/sys/dev/drm/mga_dma.c 95746 2002-04-29 18:18:42Z anholt $ 3695584Sanholt */ 3795584Sanholt 3895584Sanholt#define __NO_VERSION__ 3995584Sanholt#include "dev/drm/mga.h" 4095584Sanholt#include "dev/drm/drmP.h" 4195746Sanholt#include "dev/drm/mga_drm.h" 4295584Sanholt#include "dev/drm/mga_drv.h" 4395584Sanholt 4495584Sanholt#ifdef __linux__ 4595584Sanholt#include <linux/interrupt.h> /* For task queue support */ 4695584Sanholt#include <linux/delay.h> 4795584Sanholt#endif /* __linux__ */ 4895584Sanholt 4995584Sanholt#define MGA_DEFAULT_USEC_TIMEOUT 10000 5095584Sanholt#define MGA_FREELIST_DEBUG 0 5195584Sanholt 5295584Sanholt 5395584Sanholt/* ================================================================ 5495584Sanholt * Engine control 5595584Sanholt */ 5695584Sanholt 5795584Sanholtint mga_do_wait_for_idle( drm_mga_private_t *dev_priv ) 5895584Sanholt{ 5995584Sanholt u32 status = 0; 6095584Sanholt int i; 6195584Sanholt DRM_DEBUG( "%s\n", __FUNCTION__ ); 6295584Sanholt 6395584Sanholt for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { 6495584Sanholt status = MGA_READ( MGA_STATUS ) & MGA_ENGINE_IDLE_MASK; 6595584Sanholt if ( status == MGA_ENDPRDMASTS ) { 6695584Sanholt MGA_WRITE8( MGA_CRTC_INDEX, 0 ); 6795584Sanholt return 0; 6895584Sanholt } 6995584Sanholt DRM_OS_DELAY( 1 ); 7095584Sanholt } 7195584Sanholt 7295584Sanholt#if MGA_DMA_DEBUG 7395584Sanholt DRM_ERROR( "failed!\n" ); 7495584Sanholt DRM_INFO( " status=0x%08x\n", status ); 7595584Sanholt#endif 7695693Sanholt return DRM_OS_ERR(EBUSY); 7795584Sanholt} 7895584Sanholt 7995584Sanholtint mga_do_dma_idle( drm_mga_private_t *dev_priv ) 8095584Sanholt{ 8195584Sanholt u32 status = 0; 8295584Sanholt int i; 8395584Sanholt DRM_DEBUG( "%s\n", __FUNCTION__ ); 8495584Sanholt 8595584Sanholt for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { 8695584Sanholt status = MGA_READ( MGA_STATUS ) & MGA_DMA_IDLE_MASK; 8795584Sanholt if ( status == MGA_ENDPRDMASTS ) return 0; 8895584Sanholt DRM_OS_DELAY( 1 ); 8995584Sanholt } 9095584Sanholt 9195584Sanholt#if MGA_DMA_DEBUG 9295584Sanholt DRM_ERROR( "failed! status=0x%08x\n", status ); 9395584Sanholt#endif 9495693Sanholt return DRM_OS_ERR(EBUSY); 9595584Sanholt} 9695584Sanholt 9795584Sanholtint mga_do_dma_reset( drm_mga_private_t *dev_priv ) 9895584Sanholt{ 9995584Sanholt drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 10095584Sanholt drm_mga_primary_buffer_t *primary = &dev_priv->prim; 10195584Sanholt 10295584Sanholt DRM_DEBUG( "%s\n", __FUNCTION__ ); 10395584Sanholt 10495584Sanholt /* The primary DMA stream should look like new right about now. 10595584Sanholt */ 10695584Sanholt primary->tail = 0; 10795584Sanholt primary->space = primary->size; 10895584Sanholt primary->last_flush = 0; 10995584Sanholt 11095584Sanholt sarea_priv->last_wrap = 0; 11195584Sanholt 11295584Sanholt /* FIXME: Reset counters, buffer ages etc... 11395584Sanholt */ 11495584Sanholt 11595584Sanholt /* FIXME: What else do we need to reinitialize? WARP stuff? 11695584Sanholt */ 11795584Sanholt 11895584Sanholt return 0; 11995584Sanholt} 12095584Sanholt 12195584Sanholtint mga_do_engine_reset( drm_mga_private_t *dev_priv ) 12295584Sanholt{ 12395584Sanholt DRM_DEBUG( "%s\n", __FUNCTION__ ); 12495584Sanholt 12595584Sanholt /* Okay, so we've completely screwed up and locked the engine. 12695584Sanholt * How about we clean up after ourselves? 12795584Sanholt */ 12895584Sanholt MGA_WRITE( MGA_RST, MGA_SOFTRESET ); 12995584Sanholt DRM_OS_DELAY( 15 ); /* Wait at least 10 usecs */ 13095584Sanholt MGA_WRITE( MGA_RST, 0 ); 13195584Sanholt 13295584Sanholt /* Initialize the registers that get clobbered by the soft 13395584Sanholt * reset. Many of the core register values survive a reset, 13495584Sanholt * but the drawing registers are basically all gone. 13595584Sanholt * 13695584Sanholt * 3D clients should probably die after calling this. The X 13795584Sanholt * server should reset the engine state to known values. 13895584Sanholt */ 13995584Sanholt#if 0 14095584Sanholt MGA_WRITE( MGA_PRIMPTR, 14195584Sanholt virt_to_bus((void *)dev_priv->prim.status_page) | 14295584Sanholt MGA_PRIMPTREN0 | 14395584Sanholt MGA_PRIMPTREN1 ); 14495584Sanholt#endif 14595584Sanholt 14695584Sanholt MGA_WRITE( MGA_ICLEAR, MGA_SOFTRAPICLR ); 14795584Sanholt MGA_WRITE( MGA_IEN, MGA_SOFTRAPIEN ); 14895584Sanholt 14995584Sanholt /* The primary DMA stream should look like new right about now. 15095584Sanholt */ 15195584Sanholt mga_do_dma_reset( dev_priv ); 15295584Sanholt 15395584Sanholt /* This bad boy will never fail. 15495584Sanholt */ 15595584Sanholt return 0; 15695584Sanholt} 15795584Sanholt 15895584Sanholt 15995584Sanholt/* ================================================================ 16095584Sanholt * Primary DMA stream 16195584Sanholt */ 16295584Sanholt 16395584Sanholtvoid mga_do_dma_flush( drm_mga_private_t *dev_priv ) 16495584Sanholt{ 16595584Sanholt drm_mga_primary_buffer_t *primary = &dev_priv->prim; 16695584Sanholt u32 head, tail; 16795584Sanholt DMA_LOCALS; 16895584Sanholt DRM_DEBUG( "%s:\n", __FUNCTION__ ); 16995584Sanholt 17095584Sanholt if ( primary->tail == primary->last_flush ) { 17195584Sanholt DRM_DEBUG( " bailing out...\n" ); 17295584Sanholt return; 17395584Sanholt } 17495584Sanholt 17595584Sanholt tail = primary->tail + dev_priv->primary->offset; 17695584Sanholt 17795584Sanholt /* We need to pad the stream between flushes, as the card 17895584Sanholt * actually (partially?) reads the first of these commands. 17995584Sanholt * See page 4-16 in the G400 manual, middle of the page or so. 18095584Sanholt */ 18195584Sanholt BEGIN_DMA( 1 ); 18295584Sanholt 18395584Sanholt DMA_BLOCK( MGA_DMAPAD, 0x00000000, 18495584Sanholt MGA_DMAPAD, 0x00000000, 18595584Sanholt MGA_DMAPAD, 0x00000000, 18695584Sanholt MGA_DMAPAD, 0x00000000 ); 18795584Sanholt 18895584Sanholt ADVANCE_DMA(); 18995584Sanholt 19095584Sanholt primary->last_flush = primary->tail; 19195584Sanholt 19295584Sanholt head = MGA_READ( MGA_PRIMADDRESS ); 19395584Sanholt 19495584Sanholt if ( head <= tail ) { 19595584Sanholt primary->space = primary->size - primary->tail; 19695584Sanholt } else { 19795584Sanholt primary->space = head - tail; 19895584Sanholt } 19995584Sanholt 20095584Sanholt DRM_DEBUG( " head = 0x%06lx\n", head - dev_priv->primary->offset ); 20195584Sanholt DRM_DEBUG( " tail = 0x%06lx\n", tail - dev_priv->primary->offset ); 20295584Sanholt DRM_DEBUG( " space = 0x%06x\n", primary->space ); 20395584Sanholt 20495584Sanholt mga_flush_write_combine(); 20595584Sanholt MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); 20695584Sanholt 20795584Sanholt DRM_DEBUG( "%s: done.\n", __FUNCTION__ ); 20895584Sanholt} 20995584Sanholt 21095584Sanholtvoid mga_do_dma_wrap_start( drm_mga_private_t *dev_priv ) 21195584Sanholt{ 21295584Sanholt drm_mga_primary_buffer_t *primary = &dev_priv->prim; 21395584Sanholt u32 head, tail; 21495584Sanholt DMA_LOCALS; 21595584Sanholt DRM_DEBUG( "%s:\n", __FUNCTION__ ); 21695584Sanholt 21795584Sanholt BEGIN_DMA_WRAP(); 21895584Sanholt 21995584Sanholt DMA_BLOCK( MGA_DMAPAD, 0x00000000, 22095584Sanholt MGA_DMAPAD, 0x00000000, 22195584Sanholt MGA_DMAPAD, 0x00000000, 22295584Sanholt MGA_DMAPAD, 0x00000000 ); 22395584Sanholt 22495584Sanholt ADVANCE_DMA(); 22595584Sanholt 22695584Sanholt tail = primary->tail + dev_priv->primary->offset; 22795584Sanholt 22895584Sanholt primary->tail = 0; 22995584Sanholt primary->last_flush = 0; 23095584Sanholt primary->last_wrap++; 23195584Sanholt 23295584Sanholt head = MGA_READ( MGA_PRIMADDRESS ); 23395584Sanholt 23495584Sanholt if ( head == dev_priv->primary->offset ) { 23595584Sanholt primary->space = primary->size; 23695584Sanholt } else { 23795584Sanholt primary->space = head - dev_priv->primary->offset; 23895584Sanholt } 23995584Sanholt 24095584Sanholt DRM_DEBUG( " head = 0x%06lx\n", 24195584Sanholt head - dev_priv->primary->offset ); 24295584Sanholt DRM_DEBUG( " tail = 0x%06x\n", primary->tail ); 24395584Sanholt DRM_DEBUG( " wrap = %d\n", primary->last_wrap ); 24495584Sanholt DRM_DEBUG( " space = 0x%06x\n", primary->space ); 24595584Sanholt 24695584Sanholt mga_flush_write_combine(); 24795584Sanholt MGA_WRITE( MGA_PRIMEND, tail | MGA_PAGPXFER ); 24895584Sanholt 24995584Sanholt set_bit( 0, &primary->wrapped ); 25095584Sanholt DRM_DEBUG( "%s: done.\n", __FUNCTION__ ); 25195584Sanholt} 25295584Sanholt 25395584Sanholtvoid mga_do_dma_wrap_end( drm_mga_private_t *dev_priv ) 25495584Sanholt{ 25595584Sanholt drm_mga_primary_buffer_t *primary = &dev_priv->prim; 25695584Sanholt drm_mga_sarea_t *sarea_priv = dev_priv->sarea_priv; 25795584Sanholt u32 head = dev_priv->primary->offset; 25895584Sanholt DRM_DEBUG( "%s:\n", __FUNCTION__ ); 25995584Sanholt 26095584Sanholt sarea_priv->last_wrap++; 26195584Sanholt DRM_DEBUG( " wrap = %d\n", sarea_priv->last_wrap ); 26295584Sanholt 26395584Sanholt mga_flush_write_combine(); 26495584Sanholt MGA_WRITE( MGA_PRIMADDRESS, head | MGA_DMA_GENERAL ); 26595584Sanholt 26695584Sanholt clear_bit( 0, &primary->wrapped ); 26795584Sanholt DRM_DEBUG( "%s: done.\n", __FUNCTION__ ); 26895584Sanholt} 26995584Sanholt 27095584Sanholt 27195584Sanholt/* ================================================================ 27295584Sanholt * Freelist management 27395584Sanholt */ 27495584Sanholt 27595584Sanholt#define MGA_BUFFER_USED ~0 27695584Sanholt#define MGA_BUFFER_FREE 0 27795584Sanholt 27895584Sanholt#if MGA_FREELIST_DEBUG 27995584Sanholtstatic void mga_freelist_print( drm_device_t *dev ) 28095584Sanholt{ 28195584Sanholt drm_mga_private_t *dev_priv = dev->dev_private; 28295584Sanholt drm_mga_freelist_t *entry; 28395584Sanholt 28495584Sanholt DRM_INFO( "\n" ); 28595584Sanholt DRM_INFO( "current dispatch: last=0x%x done=0x%x\n", 28695584Sanholt dev_priv->sarea_priv->last_dispatch, 28795584Sanholt (unsigned int)(MGA_READ( MGA_PRIMADDRESS ) - 28895584Sanholt dev_priv->primary->offset) ); 28995584Sanholt DRM_INFO( "current freelist:\n" ); 29095584Sanholt 29195584Sanholt for ( entry = dev_priv->head->next ; entry ; entry = entry->next ) { 29295584Sanholt DRM_INFO( " %p idx=%2d age=0x%x 0x%06lx\n", 29395584Sanholt entry, entry->buf->idx, entry->age.head, 29495584Sanholt entry->age.head - dev_priv->primary->offset ); 29595584Sanholt } 29695584Sanholt DRM_INFO( "\n" ); 29795584Sanholt} 29895584Sanholt#endif 29995584Sanholt 30095584Sanholtstatic int mga_freelist_init( drm_device_t *dev, drm_mga_private_t *dev_priv ) 30195584Sanholt{ 30295584Sanholt drm_device_dma_t *dma = dev->dma; 30395584Sanholt drm_buf_t *buf; 30495584Sanholt drm_mga_buf_priv_t *buf_priv; 30595584Sanholt drm_mga_freelist_t *entry; 30695584Sanholt int i; 30795584Sanholt DRM_DEBUG( "%s: count=%d\n", 30895584Sanholt __FUNCTION__, dma->buf_count ); 30995584Sanholt 31095584Sanholt dev_priv->head = DRM(alloc)( sizeof(drm_mga_freelist_t), 31195584Sanholt DRM_MEM_DRIVER ); 31295584Sanholt if ( dev_priv->head == NULL ) 31395693Sanholt return DRM_OS_ERR(ENOMEM); 31495584Sanholt 31595584Sanholt memset( dev_priv->head, 0, sizeof(drm_mga_freelist_t) ); 31695584Sanholt SET_AGE( &dev_priv->head->age, MGA_BUFFER_USED, 0 ); 31795584Sanholt 31895584Sanholt for ( i = 0 ; i < dma->buf_count ; i++ ) { 31995584Sanholt buf = dma->buflist[i]; 32095584Sanholt buf_priv = buf->dev_private; 32195584Sanholt 32295584Sanholt entry = DRM(alloc)( sizeof(drm_mga_freelist_t), 32395584Sanholt DRM_MEM_DRIVER ); 32495584Sanholt if ( entry == NULL ) 32595693Sanholt return DRM_OS_ERR(ENOMEM); 32695584Sanholt 32795584Sanholt memset( entry, 0, sizeof(drm_mga_freelist_t) ); 32895584Sanholt 32995584Sanholt entry->next = dev_priv->head->next; 33095584Sanholt entry->prev = dev_priv->head; 33195584Sanholt SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 ); 33295584Sanholt entry->buf = buf; 33395584Sanholt 33495584Sanholt if ( dev_priv->head->next != NULL ) 33595584Sanholt dev_priv->head->next->prev = entry; 33695584Sanholt if ( entry->next == NULL ) 33795584Sanholt dev_priv->tail = entry; 33895584Sanholt 33995584Sanholt buf_priv->list_entry = entry; 34095584Sanholt buf_priv->discard = 0; 34195584Sanholt buf_priv->dispatched = 0; 34295584Sanholt 34395584Sanholt dev_priv->head->next = entry; 34495584Sanholt } 34595584Sanholt 34695584Sanholt return 0; 34795584Sanholt} 34895584Sanholt 34995584Sanholtstatic void mga_freelist_cleanup( drm_device_t *dev ) 35095584Sanholt{ 35195584Sanholt drm_mga_private_t *dev_priv = dev->dev_private; 35295584Sanholt drm_mga_freelist_t *entry; 35395584Sanholt drm_mga_freelist_t *next; 35495584Sanholt DRM_DEBUG( "%s\n", __FUNCTION__ ); 35595584Sanholt 35695584Sanholt entry = dev_priv->head; 35795584Sanholt while ( entry ) { 35895584Sanholt next = entry->next; 35995584Sanholt DRM(free)( entry, sizeof(drm_mga_freelist_t), DRM_MEM_DRIVER ); 36095584Sanholt entry = next; 36195584Sanholt } 36295584Sanholt 36395584Sanholt dev_priv->head = dev_priv->tail = NULL; 36495584Sanholt} 36595584Sanholt 36695584Sanholt#if 0 36795584Sanholt/* FIXME: Still needed? 36895584Sanholt */ 36995584Sanholtstatic void mga_freelist_reset( drm_device_t *dev ) 37095584Sanholt{ 37195584Sanholt drm_device_dma_t *dma = dev->dma; 37295584Sanholt drm_buf_t *buf; 37395584Sanholt drm_mga_buf_priv_t *buf_priv; 37495584Sanholt int i; 37595584Sanholt 37695584Sanholt for ( i = 0 ; i < dma->buf_count ; i++ ) { 37795584Sanholt buf = dma->buflist[i]; 37895584Sanholt buf_priv = buf->dev_private; 37995584Sanholt SET_AGE( &buf_priv->list_entry->age, 38095584Sanholt MGA_BUFFER_FREE, 0 ); 38195584Sanholt } 38295584Sanholt} 38395584Sanholt#endif 38495584Sanholt 38595584Sanholtstatic drm_buf_t *mga_freelist_get( drm_device_t *dev ) 38695584Sanholt{ 38795584Sanholt drm_mga_private_t *dev_priv = dev->dev_private; 38895584Sanholt drm_mga_freelist_t *next; 38995584Sanholt drm_mga_freelist_t *prev; 39095584Sanholt drm_mga_freelist_t *tail = dev_priv->tail; 39195584Sanholt u32 head, wrap; 39295584Sanholt DRM_DEBUG( "%s:\n", __FUNCTION__ ); 39395584Sanholt 39495584Sanholt head = MGA_READ( MGA_PRIMADDRESS ); 39595584Sanholt wrap = dev_priv->sarea_priv->last_wrap; 39695584Sanholt 39795584Sanholt DRM_DEBUG( " tail=0x%06lx %d\n", 39895584Sanholt tail->age.head ? 39995584Sanholt tail->age.head - dev_priv->primary->offset : 0, 40095584Sanholt tail->age.wrap ); 40195584Sanholt DRM_DEBUG( " head=0x%06lx %d\n", 40295584Sanholt head - dev_priv->primary->offset, wrap ); 40395584Sanholt 40495584Sanholt if ( TEST_AGE( &tail->age, head, wrap ) ) { 40595584Sanholt prev = dev_priv->tail->prev; 40695584Sanholt next = dev_priv->tail; 40795584Sanholt prev->next = NULL; 40895584Sanholt next->prev = next->next = NULL; 40995584Sanholt dev_priv->tail = prev; 41095584Sanholt SET_AGE( &next->age, MGA_BUFFER_USED, 0 ); 41195584Sanholt return next->buf; 41295584Sanholt } 41395584Sanholt 41495584Sanholt DRM_DEBUG( "returning NULL!\n" ); 41595584Sanholt return NULL; 41695584Sanholt} 41795584Sanholt 41895584Sanholtint mga_freelist_put( drm_device_t *dev, drm_buf_t *buf ) 41995584Sanholt{ 42095584Sanholt drm_mga_private_t *dev_priv = dev->dev_private; 42195584Sanholt drm_mga_buf_priv_t *buf_priv = buf->dev_private; 42295584Sanholt drm_mga_freelist_t *head, *entry, *prev; 42395584Sanholt 42495584Sanholt DRM_DEBUG( "%s: age=0x%06lx wrap=%d\n", 42595584Sanholt __FUNCTION__, 42695584Sanholt buf_priv->list_entry->age.head - 42795584Sanholt dev_priv->primary->offset, 42895584Sanholt buf_priv->list_entry->age.wrap ); 42995584Sanholt 43095584Sanholt entry = buf_priv->list_entry; 43195584Sanholt head = dev_priv->head; 43295584Sanholt 43395584Sanholt if ( buf_priv->list_entry->age.head == MGA_BUFFER_USED ) { 43495584Sanholt SET_AGE( &entry->age, MGA_BUFFER_FREE, 0 ); 43595584Sanholt prev = dev_priv->tail; 43695584Sanholt prev->next = entry; 43795584Sanholt entry->prev = prev; 43895584Sanholt entry->next = NULL; 43995584Sanholt } else { 44095584Sanholt prev = head->next; 44195584Sanholt head->next = entry; 44295584Sanholt prev->prev = entry; 44395584Sanholt entry->prev = head; 44495584Sanholt entry->next = prev; 44595584Sanholt } 44695584Sanholt 44795584Sanholt return 0; 44895584Sanholt} 44995584Sanholt 45095584Sanholt 45195584Sanholt/* ================================================================ 45295584Sanholt * DMA initialization, cleanup 45395584Sanholt */ 45495584Sanholt 45595584Sanholtstatic int mga_do_init_dma( drm_device_t *dev, drm_mga_init_t *init ) 45695584Sanholt{ 45795584Sanholt drm_mga_private_t *dev_priv; 45895584Sanholt#ifdef __linux__ 45995584Sanholt struct list_head *list; 46095584Sanholt#endif /* __linux__ */ 46195584Sanholt#ifdef __FreeBSD__ 46295584Sanholt drm_map_list_entry_t *listentry; 46395584Sanholt#endif /* __FreeBSD__ */ 46495584Sanholt int ret; 46595584Sanholt DRM_DEBUG( "%s\n", __FUNCTION__ ); 46695584Sanholt 46795584Sanholt dev_priv = DRM(alloc)( sizeof(drm_mga_private_t), DRM_MEM_DRIVER ); 46895584Sanholt if ( !dev_priv ) 46995693Sanholt return DRM_OS_ERR(ENOMEM); 47095584Sanholt 47195584Sanholt memset( dev_priv, 0, sizeof(drm_mga_private_t) ); 47295584Sanholt 47395584Sanholt dev_priv->chipset = init->chipset; 47495584Sanholt 47595584Sanholt dev_priv->usec_timeout = MGA_DEFAULT_USEC_TIMEOUT; 47695584Sanholt 47795584Sanholt if ( init->sgram ) { 47895584Sanholt dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_BLK; 47995584Sanholt } else { 48095584Sanholt dev_priv->clear_cmd = MGA_DWGCTL_CLEAR | MGA_ATYPE_RSTR; 48195584Sanholt } 48295584Sanholt dev_priv->maccess = init->maccess; 48395584Sanholt 48495584Sanholt dev_priv->fb_cpp = init->fb_cpp; 48595584Sanholt dev_priv->front_offset = init->front_offset; 48695584Sanholt dev_priv->front_pitch = init->front_pitch; 48795584Sanholt dev_priv->back_offset = init->back_offset; 48895584Sanholt dev_priv->back_pitch = init->back_pitch; 48995584Sanholt 49095584Sanholt dev_priv->depth_cpp = init->depth_cpp; 49195584Sanholt dev_priv->depth_offset = init->depth_offset; 49295584Sanholt dev_priv->depth_pitch = init->depth_pitch; 49395584Sanholt 49495584Sanholt /* FIXME: Need to support AGP textures... 49595584Sanholt */ 49695584Sanholt dev_priv->texture_offset = init->texture_offset[0]; 49795584Sanholt dev_priv->texture_size = init->texture_size[0]; 49895584Sanholt 49995584Sanholt#ifdef __linux__ 50095584Sanholt list_for_each( list, &dev->maplist->head ) { 50195584Sanholt drm_map_list_t *entry = (drm_map_list_t *)list; 50295584Sanholt if ( entry->map && 50395584Sanholt entry->map->type == _DRM_SHM && 50495584Sanholt (entry->map->flags & _DRM_CONTAINS_LOCK) ) { 50595584Sanholt dev_priv->sarea = entry->map; 50695584Sanholt break; 50795584Sanholt } 50895584Sanholt } 50995584Sanholt#endif /* __linux__ */ 51095584Sanholt#ifdef __FreeBSD__ 51195584Sanholt TAILQ_FOREACH(listentry, dev->maplist, link) { 51295584Sanholt drm_map_t *map = listentry->map; 51395584Sanholt if (map->type == _DRM_SHM && 51495584Sanholt map->flags & _DRM_CONTAINS_LOCK) { 51595584Sanholt dev_priv->sarea = map; 51695584Sanholt break; 51795584Sanholt } 51895584Sanholt } 51995584Sanholt#endif /* __FreeBSD__ */ 52095584Sanholt 52195584Sanholt if(!dev_priv->sarea) { 52295584Sanholt DRM_ERROR( "failed to find sarea!\n" ); 52395584Sanholt /* Assign dev_private so we can do cleanup. */ 52495584Sanholt dev->dev_private = (void *)dev_priv; 52595584Sanholt mga_do_cleanup_dma( dev ); 52695693Sanholt return DRM_OS_ERR(EINVAL); 52795584Sanholt } 52895584Sanholt 52995584Sanholt 53095584Sanholt DRM_FIND_MAP( dev_priv->fb, init->fb_offset ); 53195584Sanholt if(!dev_priv->fb) { 53295584Sanholt DRM_ERROR( "failed to find framebuffer!\n" ); 53395584Sanholt /* Assign dev_private so we can do cleanup. */ 53495584Sanholt dev->dev_private = (void *)dev_priv; 53595584Sanholt mga_do_cleanup_dma( dev ); 53695693Sanholt return DRM_OS_ERR(EINVAL); 53795584Sanholt } 53895584Sanholt DRM_FIND_MAP( dev_priv->mmio, init->mmio_offset ); 53995584Sanholt if(!dev_priv->mmio) { 54095584Sanholt DRM_ERROR( "failed to find mmio region!\n" ); 54195584Sanholt /* Assign dev_private so we can do cleanup. */ 54295584Sanholt dev->dev_private = (void *)dev_priv; 54395584Sanholt mga_do_cleanup_dma( dev ); 54495693Sanholt return DRM_OS_ERR(EINVAL); 54595584Sanholt } 54695584Sanholt DRM_FIND_MAP( dev_priv->status, init->status_offset ); 54795584Sanholt if(!dev_priv->status) { 54895584Sanholt DRM_ERROR( "failed to find status page!\n" ); 54995584Sanholt /* Assign dev_private so we can do cleanup. */ 55095584Sanholt dev->dev_private = (void *)dev_priv; 55195584Sanholt mga_do_cleanup_dma( dev ); 55295693Sanholt return DRM_OS_ERR(EINVAL); 55395584Sanholt } 55495584Sanholt DRM_FIND_MAP( dev_priv->warp, init->warp_offset ); 55595584Sanholt if(!dev_priv->warp) { 55695584Sanholt DRM_ERROR( "failed to find warp microcode region!\n" ); 55795584Sanholt /* Assign dev_private so we can do cleanup. */ 55895584Sanholt dev->dev_private = (void *)dev_priv; 55995584Sanholt mga_do_cleanup_dma( dev ); 56095693Sanholt return DRM_OS_ERR(EINVAL); 56195584Sanholt } 56295584Sanholt DRM_FIND_MAP( dev_priv->primary, init->primary_offset ); 56395584Sanholt if(!dev_priv->primary) { 56495584Sanholt DRM_ERROR( "failed to find primary dma region!\n" ); 56595584Sanholt /* Assign dev_private so we can do cleanup. */ 56695584Sanholt dev->dev_private = (void *)dev_priv; 56795584Sanholt mga_do_cleanup_dma( dev ); 56895693Sanholt return DRM_OS_ERR(EINVAL); 56995584Sanholt } 57095584Sanholt DRM_FIND_MAP( dev_priv->buffers, init->buffers_offset ); 57195584Sanholt if(!dev_priv->buffers) { 57295584Sanholt DRM_ERROR( "failed to find dma buffer region!\n" ); 57395584Sanholt /* Assign dev_private so we can do cleanup. */ 57495584Sanholt dev->dev_private = (void *)dev_priv; 57595584Sanholt mga_do_cleanup_dma( dev ); 57695693Sanholt return DRM_OS_ERR(EINVAL); 57795584Sanholt } 57895584Sanholt 57995584Sanholt dev_priv->sarea_priv = 58095584Sanholt (drm_mga_sarea_t *)((u8 *)dev_priv->sarea->handle + 58195584Sanholt init->sarea_priv_offset); 58295584Sanholt 58395584Sanholt DRM_IOREMAP( dev_priv->warp ); 58495584Sanholt DRM_IOREMAP( dev_priv->primary ); 58595584Sanholt DRM_IOREMAP( dev_priv->buffers ); 58695584Sanholt 58795584Sanholt if(!dev_priv->warp->handle || 58895584Sanholt !dev_priv->primary->handle || 58995584Sanholt !dev_priv->buffers->handle ) { 59095584Sanholt DRM_ERROR( "failed to ioremap agp regions!\n" ); 59195584Sanholt /* Assign dev_private so we can do cleanup. */ 59295584Sanholt dev->dev_private = (void *)dev_priv; 59395584Sanholt mga_do_cleanup_dma( dev ); 59495693Sanholt return DRM_OS_ERR(ENOMEM); 59595584Sanholt } 59695584Sanholt 59795584Sanholt ret = mga_warp_install_microcode( dev_priv ); 59895693Sanholt if ( ret ) { 59995584Sanholt DRM_ERROR( "failed to install WARP ucode!\n" ); 60095584Sanholt /* Assign dev_private so we can do cleanup. */ 60195584Sanholt dev->dev_private = (void *)dev_priv; 60295584Sanholt mga_do_cleanup_dma( dev ); 60395693Sanholt return DRM_OS_ERR(ret); 60495584Sanholt } 60595584Sanholt 60695584Sanholt ret = mga_warp_init( dev_priv ); 60795693Sanholt if ( ret ) { 60895584Sanholt DRM_ERROR( "failed to init WARP engine!\n" ); 60995584Sanholt /* Assign dev_private so we can do cleanup. */ 61095584Sanholt dev->dev_private = (void *)dev_priv; 61195584Sanholt mga_do_cleanup_dma( dev ); 61295693Sanholt return DRM_OS_ERR(ret); 61395584Sanholt } 61495584Sanholt 61595584Sanholt dev_priv->prim.status = (u32 *)dev_priv->status->handle; 61695584Sanholt 61795584Sanholt mga_do_wait_for_idle( dev_priv ); 61895584Sanholt 61995584Sanholt /* Init the primary DMA registers. 62095584Sanholt */ 62195584Sanholt MGA_WRITE( MGA_PRIMADDRESS, 62295584Sanholt dev_priv->primary->offset | MGA_DMA_GENERAL ); 62395584Sanholt#if 0 62495584Sanholt MGA_WRITE( MGA_PRIMPTR, 62595584Sanholt virt_to_bus((void *)dev_priv->prim.status) | 62695584Sanholt MGA_PRIMPTREN0 | /* Soft trap, SECEND, SETUPEND */ 62795584Sanholt MGA_PRIMPTREN1 ); /* DWGSYNC */ 62895584Sanholt#endif 62995584Sanholt 63095584Sanholt dev_priv->prim.start = (u8 *)dev_priv->primary->handle; 63195584Sanholt dev_priv->prim.end = ((u8 *)dev_priv->primary->handle 63295584Sanholt + dev_priv->primary->size); 63395584Sanholt dev_priv->prim.size = dev_priv->primary->size; 63495584Sanholt 63595584Sanholt dev_priv->prim.tail = 0; 63695584Sanholt dev_priv->prim.space = dev_priv->prim.size; 63795584Sanholt dev_priv->prim.wrapped = 0; 63895584Sanholt 63995584Sanholt dev_priv->prim.last_flush = 0; 64095584Sanholt dev_priv->prim.last_wrap = 0; 64195584Sanholt 64295584Sanholt dev_priv->prim.high_mark = 256 * DMA_BLOCK_SIZE; 64395584Sanholt 64495584Sanholt#ifdef __linux__ 64595584Sanholt spin_lock_init( &dev_priv->prim.list_lock ); 64695584Sanholt#endif /* __linux__ */ 64795584Sanholt 64895584Sanholt dev_priv->prim.status[0] = dev_priv->primary->offset; 64995584Sanholt dev_priv->prim.status[1] = 0; 65095584Sanholt 65195584Sanholt dev_priv->sarea_priv->last_wrap = 0; 65295584Sanholt dev_priv->sarea_priv->last_frame.head = 0; 65395584Sanholt dev_priv->sarea_priv->last_frame.wrap = 0; 65495584Sanholt 65595584Sanholt if ( mga_freelist_init( dev, dev_priv ) < 0 ) { 65695584Sanholt DRM_ERROR( "could not initialize freelist\n" ); 65795584Sanholt /* Assign dev_private so we can do cleanup. */ 65895584Sanholt dev->dev_private = (void *)dev_priv; 65995584Sanholt mga_do_cleanup_dma( dev ); 66095693Sanholt return DRM_OS_ERR(ENOMEM); 66195584Sanholt } 66295584Sanholt 66395584Sanholt /* Make dev_private visable to others. */ 66495584Sanholt dev->dev_private = (void *)dev_priv; 66595584Sanholt return 0; 66695584Sanholt} 66795584Sanholt 66895584Sanholtint mga_do_cleanup_dma( drm_device_t *dev ) 66995584Sanholt{ 67095584Sanholt DRM_DEBUG( "%s\n", __FUNCTION__ ); 67195584Sanholt 67295584Sanholt if ( dev->dev_private ) { 67395584Sanholt drm_mga_private_t *dev_priv = dev->dev_private; 67495584Sanholt 67595584Sanholt DRM_IOREMAPFREE( dev_priv->warp ); 67695584Sanholt DRM_IOREMAPFREE( dev_priv->primary ); 67795584Sanholt DRM_IOREMAPFREE( dev_priv->buffers ); 67895584Sanholt 67995584Sanholt if ( dev_priv->head != NULL ) { 68095584Sanholt mga_freelist_cleanup( dev ); 68195584Sanholt } 68295584Sanholt 68395584Sanholt DRM(free)( dev->dev_private, sizeof(drm_mga_private_t), 68495584Sanholt DRM_MEM_DRIVER ); 68595584Sanholt dev->dev_private = NULL; 68695584Sanholt } 68795584Sanholt 68895584Sanholt return 0; 68995584Sanholt} 69095584Sanholt 69195584Sanholtint mga_dma_init( DRM_OS_IOCTL ) 69295584Sanholt{ 69395584Sanholt DRM_OS_DEVICE; 69495584Sanholt drm_mga_init_t init; 69595584Sanholt 69695584Sanholt DRM_OS_KRNFROMUSR( init, (drm_mga_init_t *) data, sizeof(init) ); 69795584Sanholt 69895584Sanholt switch ( init.func ) { 69995584Sanholt case MGA_INIT_DMA: 70095584Sanholt return mga_do_init_dma( dev, &init ); 70195584Sanholt case MGA_CLEANUP_DMA: 70295584Sanholt return mga_do_cleanup_dma( dev ); 70395584Sanholt } 70495584Sanholt 70595693Sanholt return DRM_OS_ERR(EINVAL); 70695584Sanholt} 70795584Sanholt 70895584Sanholt 70995584Sanholt/* ================================================================ 71095584Sanholt * Primary DMA stream management 71195584Sanholt */ 71295584Sanholt 71395584Sanholtint mga_dma_flush( DRM_OS_IOCTL ) 71495584Sanholt{ 71595584Sanholt DRM_OS_DEVICE; 71695584Sanholt drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; 71795584Sanholt drm_lock_t lock; 71895584Sanholt 71995584Sanholt LOCK_TEST_WITH_RETURN( dev ); 72095584Sanholt 72195584Sanholt DRM_OS_KRNFROMUSR( lock, (drm_lock_t *) data, sizeof(lock) ); 72295584Sanholt 72395584Sanholt DRM_DEBUG( "%s: %s%s%s\n", 72495584Sanholt __FUNCTION__, 72595584Sanholt (lock.flags & _DRM_LOCK_FLUSH) ? "flush, " : "", 72695584Sanholt (lock.flags & _DRM_LOCK_FLUSH_ALL) ? "flush all, " : "", 72795584Sanholt (lock.flags & _DRM_LOCK_QUIESCENT) ? "idle, " : "" ); 72895584Sanholt 72995584Sanholt WRAP_WAIT_WITH_RETURN( dev_priv ); 73095584Sanholt 73195584Sanholt if ( lock.flags & (_DRM_LOCK_FLUSH | _DRM_LOCK_FLUSH_ALL) ) { 73295584Sanholt mga_do_dma_flush( dev_priv ); 73395584Sanholt } 73495584Sanholt 73595584Sanholt if ( lock.flags & _DRM_LOCK_QUIESCENT ) { 73695584Sanholt#if MGA_DMA_DEBUG 73795584Sanholt int ret = mga_do_wait_for_idle( dev_priv ); 73895584Sanholt if ( ret ) 73995584Sanholt DRM_INFO( __FUNCTION__": -EBUSY\n" ); 74095584Sanholt return ret; 74195584Sanholt#else 74295584Sanholt return mga_do_wait_for_idle( dev_priv ); 74395584Sanholt#endif 74495584Sanholt } else { 74595584Sanholt return 0; 74695584Sanholt } 74795584Sanholt} 74895584Sanholt 74995584Sanholtint mga_dma_reset( DRM_OS_IOCTL ) 75095584Sanholt{ 75195584Sanholt DRM_OS_DEVICE; 75295584Sanholt drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; 75395584Sanholt 75495584Sanholt LOCK_TEST_WITH_RETURN( dev ); 75595584Sanholt 75695584Sanholt return mga_do_dma_reset( dev_priv ); 75795584Sanholt} 75895584Sanholt 75995584Sanholt 76095584Sanholt/* ================================================================ 76195584Sanholt * DMA buffer management 76295584Sanholt */ 76395584Sanholt 76495584Sanholt#if 0 76595584Sanholtstatic int mga_dma_get_buffers( drm_device_t *dev, drm_dma_t *d ) 76695584Sanholt{ 76795584Sanholt drm_buf_t *buf; 76895584Sanholt int i; 76995584Sanholt 77095584Sanholt for ( i = d->granted_count ; i < d->request_count ; i++ ) { 77195584Sanholt buf = mga_freelist_get( dev ); 77295584Sanholt if ( !buf ) 77395693Sanholt return DRM_OS_ERR(EAGAIN); 77495584Sanholt 77595584Sanholt buf->pid = current->pid; 77695584Sanholt 77795584Sanholt if ( DRM_OS_COPYTOUSR( &d->request_indices[i], 77895584Sanholt &buf->idx, sizeof(buf->idx) ) ) 77995693Sanholt return DRM_OS_ERR(EFAULT); 78095584Sanholt if ( DRM_OS_COPYTOUSR( &d->request_sizes[i], 78195584Sanholt &buf->total, sizeof(buf->total) ) ) 78295693Sanholt return DRM_OS_ERR(EFAULT); 78395584Sanholt 78495584Sanholt d->granted_count++; 78595584Sanholt } 78695584Sanholt return 0; 78795584Sanholt} 78895584Sanholt#endif /* 0 */ 78995584Sanholt 79095584Sanholtint mga_dma_buffers( DRM_OS_IOCTL ) 79195584Sanholt{ 79295584Sanholt DRM_OS_DEVICE; 79395584Sanholt drm_device_dma_t *dma = dev->dma; 79495584Sanholt drm_mga_private_t *dev_priv = (drm_mga_private_t *)dev->dev_private; 79595584Sanholt drm_dma_t d; 79695584Sanholt drm_buf_t *buf; 79795584Sanholt int i; 79895584Sanholt int ret = 0; 79995584Sanholt 80095584Sanholt LOCK_TEST_WITH_RETURN( dev ); 80195584Sanholt 80295584Sanholt DRM_OS_KRNFROMUSR( d, (drm_dma_t *) data, sizeof(d) ); 80395584Sanholt 80495584Sanholt /* Please don't send us buffers. 80595584Sanholt */ 80695584Sanholt if ( d.send_count != 0 ) { 80795584Sanholt DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", 80895584Sanholt DRM_OS_CURRENTPID, d.send_count ); 80995693Sanholt return DRM_OS_ERR(EINVAL); 81095584Sanholt } 81195584Sanholt 81295584Sanholt /* We'll send you buffers. 81395584Sanholt */ 81495584Sanholt if ( d.request_count < 0 || d.request_count > dma->buf_count ) { 81595584Sanholt DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", 81695584Sanholt DRM_OS_CURRENTPID, d.request_count, dma->buf_count ); 81795693Sanholt return DRM_OS_ERR(EINVAL); 81895584Sanholt } 81995584Sanholt 82095584Sanholt WRAP_TEST_WITH_RETURN( dev_priv ); 82195584Sanholt 82295584Sanholt d.granted_count = 0; 82395584Sanholt 82495584Sanholt if ( d.request_count ) { 82595584Sanholt for ( i = d.granted_count ; i < d.request_count ; i++ ) { 82695584Sanholt buf = mga_freelist_get( dev ); 82795584Sanholt if ( !buf ) 82895693Sanholt return DRM_OS_ERR(EAGAIN); 82995584Sanholt 83095584Sanholt buf->pid = DRM_OS_CURRENTPID; 83195584Sanholt 83295584Sanholt if ( DRM_OS_COPYTOUSR( &d.request_indices[i], 83395584Sanholt &buf->idx, sizeof(buf->idx) ) ) 83495693Sanholt return DRM_OS_ERR(EFAULT); 83595584Sanholt if ( DRM_OS_COPYTOUSR( &d.request_sizes[i], 83695584Sanholt &buf->total, sizeof(buf->total) ) ) 83795693Sanholt return DRM_OS_ERR(EFAULT); 83895584Sanholt 83995584Sanholt d.granted_count++; 84095584Sanholt } 84195584Sanholt ret = 0; 84295584Sanholt } 84395584Sanholt 84495584Sanholt DRM_OS_KRNTOUSR( (drm_dma_t *) data, d, sizeof(d) ); 84595584Sanholt 84695584Sanholt return ret; 84795584Sanholt} 848