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