mach64_dma.c revision 145132
1145132Sanholt/* mach64_dma.c -- DMA support for mach64 (Rage Pro) driver -*- linux-c -*- */ 2145132Sanholt/** 3145132Sanholt * \file mach64_dma.c 4145132Sanholt * DMA support for mach64 (Rage Pro) driver 5145132Sanholt * 6145132Sanholt * \author Gareth Hughes <gareth@valinux.com> 7145132Sanholt * \author Frank C. Earl <fearl@airmail.net> 8145132Sanholt * \author Leif Delgass <ldelgass@retinalburn.net> 9145132Sanholt * \author Jose Fonseca <j_r_fonseca@yahoo.co.uk> 10145132Sanholt */ 11145132Sanholt 12145132Sanholt/* 13145132Sanholt * Copyright 2000 Gareth Hughes 14145132Sanholt * Copyright 2002 Frank C. Earl 15145132Sanholt * Copyright 2002-2003 Leif Delgass 16145132Sanholt * All Rights Reserved. 17145132Sanholt * 18145132Sanholt * Permission is hereby granted, free of charge, to any person obtaining a 19145132Sanholt * copy of this software and associated documentation files (the "Software"), 20145132Sanholt * to deal in the Software without restriction, including without limitation 21145132Sanholt * the rights to use, copy, modify, merge, publish, distribute, sublicense, 22145132Sanholt * and/or sell copies of the Software, and to permit persons to whom the 23145132Sanholt * Software is furnished to do so, subject to the following conditions: 24145132Sanholt * 25145132Sanholt * The above copyright notice and this permission notice (including the next 26145132Sanholt * paragraph) shall be included in all copies or substantial portions of the 27145132Sanholt * Software. 28145132Sanholt * 29145132Sanholt * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 30145132Sanholt * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 31145132Sanholt * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 32145132Sanholt * THE COPYRIGHT OWNER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 33145132Sanholt * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 34145132Sanholt * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 35145132Sanholt * 36145132Sanholt * $FreeBSD: head/sys/dev/drm/mach64_dma.c 145132 2005-04-16 03:44:47Z anholt $ 37145132Sanholt */ 38145132Sanholt 39145132Sanholt#include "dev/drm/drmP.h" 40145132Sanholt#include "dev/drm/drm.h" 41145132Sanholt#include "dev/drm/mach64_drm.h" 42145132Sanholt#include "dev/drm/mach64_drv.h" 43145132Sanholt 44145132Sanholt/*******************************************************************/ 45145132Sanholt/** \name Engine, FIFO control */ 46145132Sanholt/*@{*/ 47145132Sanholt 48145132Sanholt/** 49145132Sanholt * Waits for free entries in the FIFO. 50145132Sanholt * 51145132Sanholt * \note Most writes to Mach64 registers are automatically routed through 52145132Sanholt * command FIFO which is 16 entry deep. Prior to writing to any draw engine 53145132Sanholt * register one has to ensure that enough FIFO entries are available by calling 54145132Sanholt * this function. Failure to do so may cause the engine to lock. 55145132Sanholt * 56145132Sanholt * \param dev_priv pointer to device private data structure. 57145132Sanholt * \param entries number of free entries in the FIFO to wait for. 58145132Sanholt * 59145132Sanholt * \returns zero on success, or -EBUSY if the timeout (specificed by 60145132Sanholt * drm_mach64_private::usec_timeout) occurs. 61145132Sanholt */ 62145132Sanholtint mach64_do_wait_for_fifo(drm_mach64_private_t * dev_priv, int entries) 63145132Sanholt{ 64145132Sanholt int slots = 0, i; 65145132Sanholt 66145132Sanholt for (i = 0; i < dev_priv->usec_timeout; i++) { 67145132Sanholt slots = (MACH64_READ(MACH64_FIFO_STAT) & MACH64_FIFO_SLOT_MASK); 68145132Sanholt if (slots <= (0x8000 >> entries)) 69145132Sanholt return 0; 70145132Sanholt DRM_UDELAY(1); 71145132Sanholt } 72145132Sanholt 73145132Sanholt DRM_INFO("%s failed! slots=%d entries=%d\n", __FUNCTION__, slots, 74145132Sanholt entries); 75145132Sanholt return DRM_ERR(EBUSY); 76145132Sanholt} 77145132Sanholt 78145132Sanholt/** 79145132Sanholt * Wait for the draw engine to be idle. 80145132Sanholt */ 81145132Sanholtint mach64_do_wait_for_idle(drm_mach64_private_t * dev_priv) 82145132Sanholt{ 83145132Sanholt int i, ret; 84145132Sanholt 85145132Sanholt ret = mach64_do_wait_for_fifo(dev_priv, 16); 86145132Sanholt if (ret < 0) 87145132Sanholt return ret; 88145132Sanholt 89145132Sanholt for (i = 0; i < dev_priv->usec_timeout; i++) { 90145132Sanholt if (!(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) { 91145132Sanholt return 0; 92145132Sanholt } 93145132Sanholt DRM_UDELAY(1); 94145132Sanholt } 95145132Sanholt 96145132Sanholt DRM_INFO("%s failed! GUI_STAT=0x%08x\n", __FUNCTION__, 97145132Sanholt MACH64_READ(MACH64_GUI_STAT)); 98145132Sanholt mach64_dump_ring_info(dev_priv); 99145132Sanholt return DRM_ERR(EBUSY); 100145132Sanholt} 101145132Sanholt 102145132Sanholt/** 103145132Sanholt * Wait for free entries in the ring buffer. 104145132Sanholt * 105145132Sanholt * The Mach64 bus master can be configured to act as a virtual FIFO, using a 106145132Sanholt * circular buffer (commonly referred as "ring buffer" in other drivers) with 107145132Sanholt * pointers to engine commands. This allows the CPU to do other things while 108145132Sanholt * the graphics engine is busy, i.e., DMA mode. 109145132Sanholt * 110145132Sanholt * This function should be called before writing new entries to the ring 111145132Sanholt * buffer. 112145132Sanholt * 113145132Sanholt * \param dev_priv pointer to device private data structure. 114145132Sanholt * \param n number of free entries in the ring buffer to wait for. 115145132Sanholt * 116145132Sanholt * \returns zero on success, or -EBUSY if the timeout (specificed by 117145132Sanholt * drm_mach64_private_t::usec_timeout) occurs. 118145132Sanholt * 119145132Sanholt * \sa mach64_dump_ring_info() 120145132Sanholt */ 121145132Sanholtint mach64_wait_ring(drm_mach64_private_t * dev_priv, int n) 122145132Sanholt{ 123145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 124145132Sanholt int i; 125145132Sanholt 126145132Sanholt for (i = 0; i < dev_priv->usec_timeout; i++) { 127145132Sanholt mach64_update_ring_snapshot(dev_priv); 128145132Sanholt if (ring->space >= n) { 129145132Sanholt if (i > 0) { 130145132Sanholt DRM_DEBUG("%s: %d usecs\n", __FUNCTION__, i); 131145132Sanholt } 132145132Sanholt return 0; 133145132Sanholt } 134145132Sanholt DRM_UDELAY(1); 135145132Sanholt } 136145132Sanholt 137145132Sanholt /* FIXME: This is being ignored... */ 138145132Sanholt DRM_ERROR("failed!\n"); 139145132Sanholt mach64_dump_ring_info(dev_priv); 140145132Sanholt return DRM_ERR(EBUSY); 141145132Sanholt} 142145132Sanholt 143145132Sanholt/** 144145132Sanholt * Wait until all DMA requests have been processed... 145145132Sanholt * 146145132Sanholt * \sa mach64_wait_ring() 147145132Sanholt */ 148145132Sanholtstatic int mach64_ring_idle(drm_mach64_private_t * dev_priv) 149145132Sanholt{ 150145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 151145132Sanholt u32 head; 152145132Sanholt int i; 153145132Sanholt 154145132Sanholt head = ring->head; 155145132Sanholt i = 0; 156145132Sanholt while (i < dev_priv->usec_timeout) { 157145132Sanholt mach64_update_ring_snapshot(dev_priv); 158145132Sanholt if (ring->head == ring->tail && 159145132Sanholt !(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) { 160145132Sanholt if (i > 0) { 161145132Sanholt DRM_DEBUG("%s: %d usecs\n", __FUNCTION__, i); 162145132Sanholt } 163145132Sanholt return 0; 164145132Sanholt } 165145132Sanholt if (ring->head == head) { 166145132Sanholt ++i; 167145132Sanholt } else { 168145132Sanholt head = ring->head; 169145132Sanholt i = 0; 170145132Sanholt } 171145132Sanholt DRM_UDELAY(1); 172145132Sanholt } 173145132Sanholt 174145132Sanholt DRM_INFO("%s failed! GUI_STAT=0x%08x\n", __FUNCTION__, 175145132Sanholt MACH64_READ(MACH64_GUI_STAT)); 176145132Sanholt mach64_dump_ring_info(dev_priv); 177145132Sanholt return DRM_ERR(EBUSY); 178145132Sanholt} 179145132Sanholt 180145132Sanholt/** 181145132Sanholt * Reset the the ring buffer descriptors. 182145132Sanholt * 183145132Sanholt * \sa mach64_do_engine_reset() 184145132Sanholt */ 185145132Sanholtstatic void mach64_ring_reset(drm_mach64_private_t * dev_priv) 186145132Sanholt{ 187145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 188145132Sanholt 189145132Sanholt mach64_do_release_used_buffers(dev_priv); 190145132Sanholt ring->head_addr = ring->start_addr; 191145132Sanholt ring->head = ring->tail = 0; 192145132Sanholt ring->space = ring->size; 193145132Sanholt 194145132Sanholt MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, 195145132Sanholt ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); 196145132Sanholt 197145132Sanholt dev_priv->ring_running = 0; 198145132Sanholt} 199145132Sanholt 200145132Sanholt/** 201145132Sanholt * Ensure the all the queued commands will be processed. 202145132Sanholt */ 203145132Sanholtint mach64_do_dma_flush(drm_mach64_private_t * dev_priv) 204145132Sanholt{ 205145132Sanholt /* FIXME: It's not necessary to wait for idle when flushing 206145132Sanholt * we just need to ensure the ring will be completely processed 207145132Sanholt * in finite time without another ioctl 208145132Sanholt */ 209145132Sanholt return mach64_ring_idle(dev_priv); 210145132Sanholt} 211145132Sanholt 212145132Sanholt/** 213145132Sanholt * Stop all DMA activity. 214145132Sanholt */ 215145132Sanholtint mach64_do_dma_idle(drm_mach64_private_t * dev_priv) 216145132Sanholt{ 217145132Sanholt int ret; 218145132Sanholt 219145132Sanholt /* wait for completion */ 220145132Sanholt if ((ret = mach64_ring_idle(dev_priv)) < 0) { 221145132Sanholt DRM_ERROR("%s failed BM_GUI_TABLE=0x%08x tail: %u\n", 222145132Sanholt __FUNCTION__, MACH64_READ(MACH64_BM_GUI_TABLE), 223145132Sanholt dev_priv->ring.tail); 224145132Sanholt return ret; 225145132Sanholt } 226145132Sanholt 227145132Sanholt mach64_ring_stop(dev_priv); 228145132Sanholt 229145132Sanholt /* clean up after pass */ 230145132Sanholt mach64_do_release_used_buffers(dev_priv); 231145132Sanholt return 0; 232145132Sanholt} 233145132Sanholt 234145132Sanholt/** 235145132Sanholt * Reset the engine. This will stop the DMA if it is running. 236145132Sanholt */ 237145132Sanholtint mach64_do_engine_reset(drm_mach64_private_t * dev_priv) 238145132Sanholt{ 239145132Sanholt u32 tmp; 240145132Sanholt 241145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 242145132Sanholt 243145132Sanholt /* Kill off any outstanding DMA transfers. 244145132Sanholt */ 245145132Sanholt tmp = MACH64_READ(MACH64_BUS_CNTL); 246145132Sanholt MACH64_WRITE(MACH64_BUS_CNTL, tmp | MACH64_BUS_MASTER_DIS); 247145132Sanholt 248145132Sanholt /* Reset the GUI engine (high to low transition). 249145132Sanholt */ 250145132Sanholt tmp = MACH64_READ(MACH64_GEN_TEST_CNTL); 251145132Sanholt MACH64_WRITE(MACH64_GEN_TEST_CNTL, tmp & ~MACH64_GUI_ENGINE_ENABLE); 252145132Sanholt /* Enable the GUI engine 253145132Sanholt */ 254145132Sanholt tmp = MACH64_READ(MACH64_GEN_TEST_CNTL); 255145132Sanholt MACH64_WRITE(MACH64_GEN_TEST_CNTL, tmp | MACH64_GUI_ENGINE_ENABLE); 256145132Sanholt 257145132Sanholt /* ensure engine is not locked up by clearing any FIFO or HOST errors 258145132Sanholt */ 259145132Sanholt tmp = MACH64_READ(MACH64_BUS_CNTL); 260145132Sanholt MACH64_WRITE(MACH64_BUS_CNTL, tmp | 0x00a00000); 261145132Sanholt 262145132Sanholt /* Once GUI engine is restored, disable bus mastering */ 263145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, 0); 264145132Sanholt 265145132Sanholt /* Reset descriptor ring */ 266145132Sanholt mach64_ring_reset(dev_priv); 267145132Sanholt 268145132Sanholt return 0; 269145132Sanholt} 270145132Sanholt 271145132Sanholt/*@}*/ 272145132Sanholt 273145132Sanholt 274145132Sanholt/*******************************************************************/ 275145132Sanholt/** \name Debugging output */ 276145132Sanholt/*@{*/ 277145132Sanholt 278145132Sanholt/** 279145132Sanholt * Dump engine registers values. 280145132Sanholt */ 281145132Sanholtvoid mach64_dump_engine_info(drm_mach64_private_t * dev_priv) 282145132Sanholt{ 283145132Sanholt DRM_INFO("\n"); 284145132Sanholt if (!dev_priv->is_pci) { 285145132Sanholt DRM_INFO(" AGP_BASE = 0x%08x\n", 286145132Sanholt MACH64_READ(MACH64_AGP_BASE)); 287145132Sanholt DRM_INFO(" AGP_CNTL = 0x%08x\n", 288145132Sanholt MACH64_READ(MACH64_AGP_CNTL)); 289145132Sanholt } 290145132Sanholt DRM_INFO(" ALPHA_TST_CNTL = 0x%08x\n", 291145132Sanholt MACH64_READ(MACH64_ALPHA_TST_CNTL)); 292145132Sanholt DRM_INFO("\n"); 293145132Sanholt DRM_INFO(" BM_COMMAND = 0x%08x\n", 294145132Sanholt MACH64_READ(MACH64_BM_COMMAND)); 295145132Sanholt DRM_INFO("BM_FRAME_BUF_OFFSET = 0x%08x\n", 296145132Sanholt MACH64_READ(MACH64_BM_FRAME_BUF_OFFSET)); 297145132Sanholt DRM_INFO(" BM_GUI_TABLE = 0x%08x\n", 298145132Sanholt MACH64_READ(MACH64_BM_GUI_TABLE)); 299145132Sanholt DRM_INFO(" BM_STATUS = 0x%08x\n", 300145132Sanholt MACH64_READ(MACH64_BM_STATUS)); 301145132Sanholt DRM_INFO(" BM_SYSTEM_MEM_ADDR = 0x%08x\n", 302145132Sanholt MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR)); 303145132Sanholt DRM_INFO(" BM_SYSTEM_TABLE = 0x%08x\n", 304145132Sanholt MACH64_READ(MACH64_BM_SYSTEM_TABLE)); 305145132Sanholt DRM_INFO(" BUS_CNTL = 0x%08x\n", 306145132Sanholt MACH64_READ(MACH64_BUS_CNTL)); 307145132Sanholt DRM_INFO("\n"); 308145132Sanholt /* DRM_INFO( " CLOCK_CNTL = 0x%08x\n", MACH64_READ( MACH64_CLOCK_CNTL ) ); */ 309145132Sanholt DRM_INFO(" CLR_CMP_CLR = 0x%08x\n", 310145132Sanholt MACH64_READ(MACH64_CLR_CMP_CLR)); 311145132Sanholt DRM_INFO(" CLR_CMP_CNTL = 0x%08x\n", 312145132Sanholt MACH64_READ(MACH64_CLR_CMP_CNTL)); 313145132Sanholt /* DRM_INFO( " CLR_CMP_MSK = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_MSK ) ); */ 314145132Sanholt DRM_INFO(" CONFIG_CHIP_ID = 0x%08x\n", 315145132Sanholt MACH64_READ(MACH64_CONFIG_CHIP_ID)); 316145132Sanholt DRM_INFO(" CONFIG_CNTL = 0x%08x\n", 317145132Sanholt MACH64_READ(MACH64_CONFIG_CNTL)); 318145132Sanholt DRM_INFO(" CONFIG_STAT0 = 0x%08x\n", 319145132Sanholt MACH64_READ(MACH64_CONFIG_STAT0)); 320145132Sanholt DRM_INFO(" CONFIG_STAT1 = 0x%08x\n", 321145132Sanholt MACH64_READ(MACH64_CONFIG_STAT1)); 322145132Sanholt DRM_INFO(" CONFIG_STAT2 = 0x%08x\n", 323145132Sanholt MACH64_READ(MACH64_CONFIG_STAT2)); 324145132Sanholt DRM_INFO(" CRC_SIG = 0x%08x\n", MACH64_READ(MACH64_CRC_SIG)); 325145132Sanholt DRM_INFO(" CUSTOM_MACRO_CNTL = 0x%08x\n", 326145132Sanholt MACH64_READ(MACH64_CUSTOM_MACRO_CNTL)); 327145132Sanholt DRM_INFO("\n"); 328145132Sanholt /* DRM_INFO( " DAC_CNTL = 0x%08x\n", MACH64_READ( MACH64_DAC_CNTL ) ); */ 329145132Sanholt /* DRM_INFO( " DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_DAC_REGS ) ); */ 330145132Sanholt DRM_INFO(" DP_BKGD_CLR = 0x%08x\n", 331145132Sanholt MACH64_READ(MACH64_DP_BKGD_CLR)); 332145132Sanholt DRM_INFO(" DP_FRGD_CLR = 0x%08x\n", 333145132Sanholt MACH64_READ(MACH64_DP_FRGD_CLR)); 334145132Sanholt DRM_INFO(" DP_MIX = 0x%08x\n", MACH64_READ(MACH64_DP_MIX)); 335145132Sanholt DRM_INFO(" DP_PIX_WIDTH = 0x%08x\n", 336145132Sanholt MACH64_READ(MACH64_DP_PIX_WIDTH)); 337145132Sanholt DRM_INFO(" DP_SRC = 0x%08x\n", MACH64_READ(MACH64_DP_SRC)); 338145132Sanholt DRM_INFO(" DP_WRITE_MASK = 0x%08x\n", 339145132Sanholt MACH64_READ(MACH64_DP_WRITE_MASK)); 340145132Sanholt DRM_INFO(" DSP_CONFIG = 0x%08x\n", 341145132Sanholt MACH64_READ(MACH64_DSP_CONFIG)); 342145132Sanholt DRM_INFO(" DSP_ON_OFF = 0x%08x\n", 343145132Sanholt MACH64_READ(MACH64_DSP_ON_OFF)); 344145132Sanholt DRM_INFO(" DST_CNTL = 0x%08x\n", 345145132Sanholt MACH64_READ(MACH64_DST_CNTL)); 346145132Sanholt DRM_INFO(" DST_OFF_PITCH = 0x%08x\n", 347145132Sanholt MACH64_READ(MACH64_DST_OFF_PITCH)); 348145132Sanholt DRM_INFO("\n"); 349145132Sanholt /* DRM_INFO( " EXT_DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_EXT_DAC_REGS ) ); */ 350145132Sanholt DRM_INFO(" EXT_MEM_CNTL = 0x%08x\n", 351145132Sanholt MACH64_READ(MACH64_EXT_MEM_CNTL)); 352145132Sanholt DRM_INFO("\n"); 353145132Sanholt DRM_INFO(" FIFO_STAT = 0x%08x\n", 354145132Sanholt MACH64_READ(MACH64_FIFO_STAT)); 355145132Sanholt DRM_INFO("\n"); 356145132Sanholt DRM_INFO(" GEN_TEST_CNTL = 0x%08x\n", 357145132Sanholt MACH64_READ(MACH64_GEN_TEST_CNTL)); 358145132Sanholt /* DRM_INFO( " GP_IO = 0x%08x\n", MACH64_READ( MACH64_GP_IO ) ); */ 359145132Sanholt DRM_INFO(" GUI_CMDFIFO_DATA = 0x%08x\n", 360145132Sanholt MACH64_READ(MACH64_GUI_CMDFIFO_DATA)); 361145132Sanholt DRM_INFO(" GUI_CMDFIFO_DEBUG = 0x%08x\n", 362145132Sanholt MACH64_READ(MACH64_GUI_CMDFIFO_DEBUG)); 363145132Sanholt DRM_INFO(" GUI_CNTL = 0x%08x\n", 364145132Sanholt MACH64_READ(MACH64_GUI_CNTL)); 365145132Sanholt DRM_INFO(" GUI_STAT = 0x%08x\n", 366145132Sanholt MACH64_READ(MACH64_GUI_STAT)); 367145132Sanholt DRM_INFO(" GUI_TRAJ_CNTL = 0x%08x\n", 368145132Sanholt MACH64_READ(MACH64_GUI_TRAJ_CNTL)); 369145132Sanholt DRM_INFO("\n"); 370145132Sanholt DRM_INFO(" HOST_CNTL = 0x%08x\n", 371145132Sanholt MACH64_READ(MACH64_HOST_CNTL)); 372145132Sanholt DRM_INFO(" HW_DEBUG = 0x%08x\n", 373145132Sanholt MACH64_READ(MACH64_HW_DEBUG)); 374145132Sanholt DRM_INFO("\n"); 375145132Sanholt DRM_INFO(" MEM_ADDR_CONFIG = 0x%08x\n", 376145132Sanholt MACH64_READ(MACH64_MEM_ADDR_CONFIG)); 377145132Sanholt DRM_INFO(" MEM_BUF_CNTL = 0x%08x\n", 378145132Sanholt MACH64_READ(MACH64_MEM_BUF_CNTL)); 379145132Sanholt DRM_INFO("\n"); 380145132Sanholt DRM_INFO(" PAT_REG0 = 0x%08x\n", 381145132Sanholt MACH64_READ(MACH64_PAT_REG0)); 382145132Sanholt DRM_INFO(" PAT_REG1 = 0x%08x\n", 383145132Sanholt MACH64_READ(MACH64_PAT_REG1)); 384145132Sanholt DRM_INFO("\n"); 385145132Sanholt DRM_INFO(" SC_LEFT = 0x%08x\n", MACH64_READ(MACH64_SC_LEFT)); 386145132Sanholt DRM_INFO(" SC_RIGHT = 0x%08x\n", 387145132Sanholt MACH64_READ(MACH64_SC_RIGHT)); 388145132Sanholt DRM_INFO(" SC_TOP = 0x%08x\n", MACH64_READ(MACH64_SC_TOP)); 389145132Sanholt DRM_INFO(" SC_BOTTOM = 0x%08x\n", 390145132Sanholt MACH64_READ(MACH64_SC_BOTTOM)); 391145132Sanholt DRM_INFO("\n"); 392145132Sanholt DRM_INFO(" SCALE_3D_CNTL = 0x%08x\n", 393145132Sanholt MACH64_READ(MACH64_SCALE_3D_CNTL)); 394145132Sanholt DRM_INFO(" SCRATCH_REG0 = 0x%08x\n", 395145132Sanholt MACH64_READ(MACH64_SCRATCH_REG0)); 396145132Sanholt DRM_INFO(" SCRATCH_REG1 = 0x%08x\n", 397145132Sanholt MACH64_READ(MACH64_SCRATCH_REG1)); 398145132Sanholt DRM_INFO(" SETUP_CNTL = 0x%08x\n", 399145132Sanholt MACH64_READ(MACH64_SETUP_CNTL)); 400145132Sanholt DRM_INFO(" SRC_CNTL = 0x%08x\n", 401145132Sanholt MACH64_READ(MACH64_SRC_CNTL)); 402145132Sanholt DRM_INFO("\n"); 403145132Sanholt DRM_INFO(" TEX_CNTL = 0x%08x\n", 404145132Sanholt MACH64_READ(MACH64_TEX_CNTL)); 405145132Sanholt DRM_INFO(" TEX_SIZE_PITCH = 0x%08x\n", 406145132Sanholt MACH64_READ(MACH64_TEX_SIZE_PITCH)); 407145132Sanholt DRM_INFO(" TIMER_CONFIG = 0x%08x\n", 408145132Sanholt MACH64_READ(MACH64_TIMER_CONFIG)); 409145132Sanholt DRM_INFO("\n"); 410145132Sanholt DRM_INFO(" Z_CNTL = 0x%08x\n", MACH64_READ(MACH64_Z_CNTL)); 411145132Sanholt DRM_INFO(" Z_OFF_PITCH = 0x%08x\n", 412145132Sanholt MACH64_READ(MACH64_Z_OFF_PITCH)); 413145132Sanholt DRM_INFO("\n"); 414145132Sanholt} 415145132Sanholt 416145132Sanholt#define MACH64_DUMP_CONTEXT 3 417145132Sanholt 418145132Sanholt/** 419145132Sanholt * Used by mach64_dump_ring_info() to dump the contents of the current buffer 420145132Sanholt * pointed by the ring head. 421145132Sanholt */ 422145132Sanholtstatic void mach64_dump_buf_info(drm_mach64_private_t * dev_priv, 423145132Sanholt drm_buf_t * buf) 424145132Sanholt{ 425145132Sanholt u32 addr = GETBUFADDR(buf); 426145132Sanholt u32 used = buf->used >> 2; 427145132Sanholt u32 sys_addr = MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR); 428145132Sanholt u32 *p = GETBUFPTR(buf); 429145132Sanholt int skipped = 0; 430145132Sanholt 431145132Sanholt DRM_INFO("buffer contents:\n"); 432145132Sanholt 433145132Sanholt while (used) { 434145132Sanholt u32 reg, count; 435145132Sanholt 436145132Sanholt reg = le32_to_cpu(*p++); 437145132Sanholt if (addr <= GETBUFADDR(buf) + MACH64_DUMP_CONTEXT * 4 || 438145132Sanholt (addr >= sys_addr - MACH64_DUMP_CONTEXT * 4 && 439145132Sanholt addr <= sys_addr + MACH64_DUMP_CONTEXT * 4) || 440145132Sanholt addr >= 441145132Sanholt GETBUFADDR(buf) + buf->used - MACH64_DUMP_CONTEXT * 4) { 442145132Sanholt DRM_INFO("%08x: 0x%08x\n", addr, reg); 443145132Sanholt } 444145132Sanholt addr += 4; 445145132Sanholt used--; 446145132Sanholt 447145132Sanholt count = (reg >> 16) + 1; 448145132Sanholt reg = reg & 0xffff; 449145132Sanholt reg = MMSELECT(reg); 450145132Sanholt while (count && used) { 451145132Sanholt if (addr <= GETBUFADDR(buf) + MACH64_DUMP_CONTEXT * 4 || 452145132Sanholt (addr >= sys_addr - MACH64_DUMP_CONTEXT * 4 && 453145132Sanholt addr <= sys_addr + MACH64_DUMP_CONTEXT * 4) || 454145132Sanholt addr >= 455145132Sanholt GETBUFADDR(buf) + buf->used - 456145132Sanholt MACH64_DUMP_CONTEXT * 4) { 457145132Sanholt DRM_INFO("%08x: 0x%04x = 0x%08x\n", addr, 458145132Sanholt reg, le32_to_cpu(*p)); 459145132Sanholt skipped = 0; 460145132Sanholt } else { 461145132Sanholt if (!skipped) { 462145132Sanholt DRM_INFO(" ...\n"); 463145132Sanholt skipped = 1; 464145132Sanholt } 465145132Sanholt } 466145132Sanholt p++; 467145132Sanholt addr += 4; 468145132Sanholt used--; 469145132Sanholt 470145132Sanholt reg += 4; 471145132Sanholt count--; 472145132Sanholt } 473145132Sanholt } 474145132Sanholt 475145132Sanholt DRM_INFO("\n"); 476145132Sanholt} 477145132Sanholt 478145132Sanholt/** 479145132Sanholt * Dump the ring state and contents, including the contents of the buffer being 480145132Sanholt * processed by the graphics engine. 481145132Sanholt */ 482145132Sanholtvoid mach64_dump_ring_info(drm_mach64_private_t * dev_priv) 483145132Sanholt{ 484145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 485145132Sanholt int i, skipped; 486145132Sanholt 487145132Sanholt DRM_INFO("\n"); 488145132Sanholt 489145132Sanholt DRM_INFO("ring contents:\n"); 490145132Sanholt DRM_INFO(" head_addr: 0x%08x head: %u tail: %u\n\n", 491145132Sanholt ring->head_addr, ring->head, ring->tail); 492145132Sanholt 493145132Sanholt skipped = 0; 494145132Sanholt for (i = 0; i < ring->size / sizeof(u32); i += 4) { 495145132Sanholt if (i <= MACH64_DUMP_CONTEXT * 4 || 496145132Sanholt i >= ring->size / sizeof(u32) - MACH64_DUMP_CONTEXT * 4 || 497145132Sanholt (i >= ring->tail - MACH64_DUMP_CONTEXT * 4 && 498145132Sanholt i <= ring->tail + MACH64_DUMP_CONTEXT * 4) || 499145132Sanholt (i >= ring->head - MACH64_DUMP_CONTEXT * 4 && 500145132Sanholt i <= ring->head + MACH64_DUMP_CONTEXT * 4)) { 501145132Sanholt DRM_INFO(" 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x%s%s\n", 502145132Sanholt (u32)(ring->start_addr + i * sizeof(u32)), 503145132Sanholt le32_to_cpu(((u32 *) ring->start)[i + 0]), 504145132Sanholt le32_to_cpu(((u32 *) ring->start)[i + 1]), 505145132Sanholt le32_to_cpu(((u32 *) ring->start)[i + 2]), 506145132Sanholt le32_to_cpu(((u32 *) ring->start)[i + 3]), 507145132Sanholt i == ring->head ? " (head)" : "", 508145132Sanholt i == ring->tail ? " (tail)" : ""); 509145132Sanholt skipped = 0; 510145132Sanholt } else { 511145132Sanholt if (!skipped) { 512145132Sanholt DRM_INFO(" ...\n"); 513145132Sanholt skipped = 1; 514145132Sanholt } 515145132Sanholt } 516145132Sanholt } 517145132Sanholt 518145132Sanholt DRM_INFO("\n"); 519145132Sanholt 520145132Sanholt if (ring->head >= 0 && ring->head < ring->size / sizeof(u32)) { 521145132Sanholt struct list_head *ptr; 522145132Sanholt u32 addr = le32_to_cpu(((u32 *) ring->start)[ring->head + 1]); 523145132Sanholt 524145132Sanholt list_for_each(ptr, &dev_priv->pending) { 525145132Sanholt drm_mach64_freelist_t *entry = 526145132Sanholt list_entry(ptr, drm_mach64_freelist_t, list); 527145132Sanholt drm_buf_t *buf = entry->buf; 528145132Sanholt 529145132Sanholt u32 buf_addr = GETBUFADDR(buf); 530145132Sanholt 531145132Sanholt if (buf_addr <= addr && addr < buf_addr + buf->used) { 532145132Sanholt mach64_dump_buf_info(dev_priv, buf); 533145132Sanholt } 534145132Sanholt } 535145132Sanholt } 536145132Sanholt 537145132Sanholt DRM_INFO("\n"); 538145132Sanholt DRM_INFO(" BM_GUI_TABLE = 0x%08x\n", 539145132Sanholt MACH64_READ(MACH64_BM_GUI_TABLE)); 540145132Sanholt DRM_INFO("\n"); 541145132Sanholt DRM_INFO("BM_FRAME_BUF_OFFSET = 0x%08x\n", 542145132Sanholt MACH64_READ(MACH64_BM_FRAME_BUF_OFFSET)); 543145132Sanholt DRM_INFO(" BM_SYSTEM_MEM_ADDR = 0x%08x\n", 544145132Sanholt MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR)); 545145132Sanholt DRM_INFO(" BM_COMMAND = 0x%08x\n", 546145132Sanholt MACH64_READ(MACH64_BM_COMMAND)); 547145132Sanholt DRM_INFO("\n"); 548145132Sanholt DRM_INFO(" BM_STATUS = 0x%08x\n", 549145132Sanholt MACH64_READ(MACH64_BM_STATUS)); 550145132Sanholt DRM_INFO(" BUS_CNTL = 0x%08x\n", 551145132Sanholt MACH64_READ(MACH64_BUS_CNTL)); 552145132Sanholt DRM_INFO(" FIFO_STAT = 0x%08x\n", 553145132Sanholt MACH64_READ(MACH64_FIFO_STAT)); 554145132Sanholt DRM_INFO(" GUI_STAT = 0x%08x\n", 555145132Sanholt MACH64_READ(MACH64_GUI_STAT)); 556145132Sanholt DRM_INFO(" SRC_CNTL = 0x%08x\n", 557145132Sanholt MACH64_READ(MACH64_SRC_CNTL)); 558145132Sanholt} 559145132Sanholt 560145132Sanholt/*@}*/ 561145132Sanholt 562145132Sanholt 563145132Sanholt/*******************************************************************/ 564145132Sanholt/** \name DMA test and initialization */ 565145132Sanholt/*@{*/ 566145132Sanholt 567145132Sanholt/** 568145132Sanholt * Perform a simple DMA operation using the pattern registers to test whether 569145132Sanholt * DMA works. 570145132Sanholt * 571145132Sanholt * \return zero if successful. 572145132Sanholt * 573145132Sanholt * \note This function was the testbed for many experiences regarding Mach64 574145132Sanholt * DMA operation. It is left here since it so tricky to get DMA operating 575145132Sanholt * properly in some architectures and hardware. 576145132Sanholt */ 577145132Sanholtstatic int mach64_bm_dma_test(drm_device_t * dev) 578145132Sanholt{ 579145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 580145132Sanholt dma_addr_t data_handle; 581145132Sanholt void *cpu_addr_data; 582145132Sanholt u32 data_addr; 583145132Sanholt u32 *table, *data; 584145132Sanholt u32 expected[2]; 585145132Sanholt u32 src_cntl, pat_reg0, pat_reg1; 586145132Sanholt int i, count, failed; 587145132Sanholt 588145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 589145132Sanholt 590145132Sanholt table = (u32 *) dev_priv->ring.start; 591145132Sanholt 592145132Sanholt /* FIXME: get a dma buffer from the freelist here */ 593145132Sanholt DRM_DEBUG("Allocating data memory ...\n"); 594145132Sanholt cpu_addr_data = 595145132Sanholt drm_pci_alloc(dev, 0x1000, 0x1000, 0xfffffffful, &data_handle); 596145132Sanholt if (!cpu_addr_data || !data_handle) { 597145132Sanholt DRM_INFO("data-memory allocation failed!\n"); 598145132Sanholt return DRM_ERR(ENOMEM); 599145132Sanholt } else { 600145132Sanholt data = (u32 *) cpu_addr_data; 601145132Sanholt data_addr = (u32) data_handle; 602145132Sanholt } 603145132Sanholt 604145132Sanholt /* Save the X server's value for SRC_CNTL and restore it 605145132Sanholt * in case our test fails. This prevents the X server 606145132Sanholt * from disabling it's cache for this register 607145132Sanholt */ 608145132Sanholt src_cntl = MACH64_READ(MACH64_SRC_CNTL); 609145132Sanholt pat_reg0 = MACH64_READ(MACH64_PAT_REG0); 610145132Sanholt pat_reg1 = MACH64_READ(MACH64_PAT_REG1); 611145132Sanholt 612145132Sanholt mach64_do_wait_for_fifo(dev_priv, 3); 613145132Sanholt 614145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, 0); 615145132Sanholt MACH64_WRITE(MACH64_PAT_REG0, 0x11111111); 616145132Sanholt MACH64_WRITE(MACH64_PAT_REG1, 0x11111111); 617145132Sanholt 618145132Sanholt mach64_do_wait_for_idle(dev_priv); 619145132Sanholt 620145132Sanholt for (i = 0; i < 2; i++) { 621145132Sanholt u32 reg; 622145132Sanholt reg = MACH64_READ((MACH64_PAT_REG0 + i * 4)); 623145132Sanholt DRM_DEBUG("(Before DMA Transfer) reg %d = 0x%08x\n", i, reg); 624145132Sanholt if (reg != 0x11111111) { 625145132Sanholt DRM_INFO("Error initializing test registers\n"); 626145132Sanholt DRM_INFO("resetting engine ...\n"); 627145132Sanholt mach64_do_engine_reset(dev_priv); 628145132Sanholt DRM_INFO("freeing data buffer memory.\n"); 629145132Sanholt drm_pci_free(dev, 0x1000, cpu_addr_data, data_handle); 630145132Sanholt return DRM_ERR(EIO); 631145132Sanholt } 632145132Sanholt } 633145132Sanholt 634145132Sanholt /* fill up a buffer with sets of 2 consecutive writes starting with PAT_REG0 */ 635145132Sanholt count = 0; 636145132Sanholt 637145132Sanholt data[count++] = cpu_to_le32(DMAREG(MACH64_PAT_REG0) | (1 << 16)); 638145132Sanholt data[count++] = expected[0] = 0x22222222; 639145132Sanholt data[count++] = expected[1] = 0xaaaaaaaa; 640145132Sanholt 641145132Sanholt while (count < 1020) { 642145132Sanholt data[count++] = 643145132Sanholt cpu_to_le32(DMAREG(MACH64_PAT_REG0) | (1 << 16)); 644145132Sanholt data[count++] = 0x22222222; 645145132Sanholt data[count++] = 0xaaaaaaaa; 646145132Sanholt } 647145132Sanholt data[count++] = cpu_to_le32(DMAREG(MACH64_SRC_CNTL) | (0 << 16)); 648145132Sanholt data[count++] = 0; 649145132Sanholt 650145132Sanholt DRM_DEBUG("Preparing table ...\n"); 651145132Sanholt table[MACH64_DMA_FRAME_BUF_OFFSET] = cpu_to_le32(MACH64_BM_ADDR + 652145132Sanholt MACH64_APERTURE_OFFSET); 653145132Sanholt table[MACH64_DMA_SYS_MEM_ADDR] = cpu_to_le32(data_addr); 654145132Sanholt table[MACH64_DMA_COMMAND] = cpu_to_le32(count * sizeof(u32) 655145132Sanholt | MACH64_DMA_HOLD_OFFSET 656145132Sanholt | MACH64_DMA_EOL); 657145132Sanholt table[MACH64_DMA_RESERVED] = 0; 658145132Sanholt 659145132Sanholt DRM_DEBUG("table[0] = 0x%08x\n", table[0]); 660145132Sanholt DRM_DEBUG("table[1] = 0x%08x\n", table[1]); 661145132Sanholt DRM_DEBUG("table[2] = 0x%08x\n", table[2]); 662145132Sanholt DRM_DEBUG("table[3] = 0x%08x\n", table[3]); 663145132Sanholt 664145132Sanholt for (i = 0; i < 6; i++) { 665145132Sanholt DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]); 666145132Sanholt } 667145132Sanholt DRM_DEBUG(" ...\n"); 668145132Sanholt for (i = count - 5; i < count; i++) { 669145132Sanholt DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]); 670145132Sanholt } 671145132Sanholt 672145132Sanholt DRM_MEMORYBARRIER(); 673145132Sanholt 674145132Sanholt DRM_DEBUG("waiting for idle...\n"); 675145132Sanholt if ((i = mach64_do_wait_for_idle(dev_priv))) { 676145132Sanholt DRM_INFO("mach64_do_wait_for_idle failed (result=%d)\n", i); 677145132Sanholt DRM_INFO("resetting engine ...\n"); 678145132Sanholt mach64_do_engine_reset(dev_priv); 679145132Sanholt mach64_do_wait_for_fifo(dev_priv, 3); 680145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); 681145132Sanholt MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); 682145132Sanholt MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); 683145132Sanholt DRM_INFO("freeing data buffer memory.\n"); 684145132Sanholt drm_pci_free(dev, 0x1000, cpu_addr_data, data_handle); 685145132Sanholt return i; 686145132Sanholt } 687145132Sanholt DRM_DEBUG("waiting for idle...done\n"); 688145132Sanholt 689145132Sanholt DRM_DEBUG("BUS_CNTL = 0x%08x\n", MACH64_READ(MACH64_BUS_CNTL)); 690145132Sanholt DRM_DEBUG("SRC_CNTL = 0x%08x\n", MACH64_READ(MACH64_SRC_CNTL)); 691145132Sanholt DRM_DEBUG("\n"); 692145132Sanholt DRM_DEBUG("data bus addr = 0x%08x\n", data_addr); 693145132Sanholt DRM_DEBUG("table bus addr = 0x%08x\n", dev_priv->ring.start_addr); 694145132Sanholt 695145132Sanholt DRM_DEBUG("starting DMA transfer...\n"); 696145132Sanholt MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, 697145132Sanholt dev_priv->ring.start_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); 698145132Sanholt 699145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, 700145132Sanholt MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC | 701145132Sanholt MACH64_SRC_BM_OP_SYSTEM_TO_REG); 702145132Sanholt 703145132Sanholt /* Kick off the transfer */ 704145132Sanholt DRM_DEBUG("starting DMA transfer... done.\n"); 705145132Sanholt MACH64_WRITE(MACH64_DST_HEIGHT_WIDTH, 0); 706145132Sanholt 707145132Sanholt DRM_DEBUG("waiting for idle...\n"); 708145132Sanholt 709145132Sanholt if ((i = mach64_do_wait_for_idle(dev_priv))) { 710145132Sanholt /* engine locked up, dump register state and reset */ 711145132Sanholt DRM_INFO("mach64_do_wait_for_idle failed (result=%d)\n", i); 712145132Sanholt mach64_dump_engine_info(dev_priv); 713145132Sanholt DRM_INFO("resetting engine ...\n"); 714145132Sanholt mach64_do_engine_reset(dev_priv); 715145132Sanholt mach64_do_wait_for_fifo(dev_priv, 3); 716145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); 717145132Sanholt MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); 718145132Sanholt MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); 719145132Sanholt DRM_INFO("freeing data buffer memory.\n"); 720145132Sanholt drm_pci_free(dev, 0x1000, cpu_addr_data, data_handle); 721145132Sanholt return i; 722145132Sanholt } 723145132Sanholt 724145132Sanholt DRM_DEBUG("waiting for idle...done\n"); 725145132Sanholt 726145132Sanholt /* restore SRC_CNTL */ 727145132Sanholt mach64_do_wait_for_fifo(dev_priv, 1); 728145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); 729145132Sanholt 730145132Sanholt failed = 0; 731145132Sanholt 732145132Sanholt /* Check register values to see if the GUI master operation succeeded */ 733145132Sanholt for (i = 0; i < 2; i++) { 734145132Sanholt u32 reg; 735145132Sanholt reg = MACH64_READ((MACH64_PAT_REG0 + i * 4)); 736145132Sanholt DRM_DEBUG("(After DMA Transfer) reg %d = 0x%08x\n", i, reg); 737145132Sanholt if (reg != expected[i]) { 738145132Sanholt failed = -1; 739145132Sanholt } 740145132Sanholt } 741145132Sanholt 742145132Sanholt /* restore pattern registers */ 743145132Sanholt mach64_do_wait_for_fifo(dev_priv, 2); 744145132Sanholt MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); 745145132Sanholt MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); 746145132Sanholt 747145132Sanholt DRM_DEBUG("freeing data buffer memory.\n"); 748145132Sanholt drm_pci_free(dev, 0x1000, cpu_addr_data, data_handle); 749145132Sanholt DRM_DEBUG("returning ...\n"); 750145132Sanholt 751145132Sanholt return failed; 752145132Sanholt} 753145132Sanholt 754145132Sanholt/** 755145132Sanholt * Called during the DMA initialization ioctl to initialize all the necessary 756145132Sanholt * software and hardware state for DMA operation. 757145132Sanholt */ 758145132Sanholtstatic int mach64_do_dma_init(drm_device_t * dev, drm_mach64_init_t * init) 759145132Sanholt{ 760145132Sanholt drm_mach64_private_t *dev_priv; 761145132Sanholt u32 tmp; 762145132Sanholt int i, ret; 763145132Sanholt 764145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 765145132Sanholt 766145132Sanholt dev_priv = drm_alloc(sizeof(drm_mach64_private_t), DRM_MEM_DRIVER); 767145132Sanholt if (dev_priv == NULL) 768145132Sanholt return DRM_ERR(ENOMEM); 769145132Sanholt 770145132Sanholt memset(dev_priv, 0, sizeof(drm_mach64_private_t)); 771145132Sanholt 772145132Sanholt dev_priv->is_pci = init->is_pci; 773145132Sanholt 774145132Sanholt dev_priv->fb_bpp = init->fb_bpp; 775145132Sanholt dev_priv->front_offset = init->front_offset; 776145132Sanholt dev_priv->front_pitch = init->front_pitch; 777145132Sanholt dev_priv->back_offset = init->back_offset; 778145132Sanholt dev_priv->back_pitch = init->back_pitch; 779145132Sanholt 780145132Sanholt dev_priv->depth_bpp = init->depth_bpp; 781145132Sanholt dev_priv->depth_offset = init->depth_offset; 782145132Sanholt dev_priv->depth_pitch = init->depth_pitch; 783145132Sanholt 784145132Sanholt dev_priv->front_offset_pitch = (((dev_priv->front_pitch / 8) << 22) | 785145132Sanholt (dev_priv->front_offset >> 3)); 786145132Sanholt dev_priv->back_offset_pitch = (((dev_priv->back_pitch / 8) << 22) | 787145132Sanholt (dev_priv->back_offset >> 3)); 788145132Sanholt dev_priv->depth_offset_pitch = (((dev_priv->depth_pitch / 8) << 22) | 789145132Sanholt (dev_priv->depth_offset >> 3)); 790145132Sanholt 791145132Sanholt dev_priv->usec_timeout = 1000000; 792145132Sanholt 793145132Sanholt /* Set up the freelist, placeholder list and pending list */ 794145132Sanholt INIT_LIST_HEAD(&dev_priv->free_list); 795145132Sanholt INIT_LIST_HEAD(&dev_priv->placeholders); 796145132Sanholt INIT_LIST_HEAD(&dev_priv->pending); 797145132Sanholt 798145132Sanholt DRM_GETSAREA(); 799145132Sanholt 800145132Sanholt if (!dev_priv->sarea) { 801145132Sanholt DRM_ERROR("can not find sarea!\n"); 802145132Sanholt dev->dev_private = (void *)dev_priv; 803145132Sanholt mach64_do_cleanup_dma(dev); 804145132Sanholt return DRM_ERR(EINVAL); 805145132Sanholt } 806145132Sanholt dev_priv->fb = drm_core_findmap(dev, init->fb_offset); 807145132Sanholt if (!dev_priv->fb) { 808145132Sanholt DRM_ERROR("can not find frame buffer map!\n"); 809145132Sanholt dev->dev_private = (void *)dev_priv; 810145132Sanholt mach64_do_cleanup_dma(dev); 811145132Sanholt return DRM_ERR(EINVAL); 812145132Sanholt } 813145132Sanholt dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); 814145132Sanholt if (!dev_priv->mmio) { 815145132Sanholt DRM_ERROR("can not find mmio map!\n"); 816145132Sanholt dev->dev_private = (void *)dev_priv; 817145132Sanholt mach64_do_cleanup_dma(dev); 818145132Sanholt return DRM_ERR(EINVAL); 819145132Sanholt } 820145132Sanholt 821145132Sanholt dev_priv->sarea_priv = (drm_mach64_sarea_t *) 822145132Sanholt ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); 823145132Sanholt 824145132Sanholt if (!dev_priv->is_pci) { 825145132Sanholt dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset); 826145132Sanholt if (!dev_priv->ring_map) { 827145132Sanholt DRM_ERROR("can not find ring map!\n"); 828145132Sanholt dev->dev_private = (void *)dev_priv; 829145132Sanholt mach64_do_cleanup_dma(dev); 830145132Sanholt return DRM_ERR(EINVAL); 831145132Sanholt } 832145132Sanholt drm_core_ioremap(dev_priv->ring_map, dev); 833145132Sanholt if (!dev_priv->ring_map->handle) { 834145132Sanholt DRM_ERROR("can not ioremap virtual address for" 835145132Sanholt " descriptor ring\n"); 836145132Sanholt dev->dev_private = (void *)dev_priv; 837145132Sanholt mach64_do_cleanup_dma(dev); 838145132Sanholt return DRM_ERR(ENOMEM); 839145132Sanholt } 840145132Sanholt dev->agp_buffer_map = 841145132Sanholt drm_core_findmap(dev, init->buffers_offset); 842145132Sanholt if (!dev->agp_buffer_map) { 843145132Sanholt DRM_ERROR("can not find dma buffer map!\n"); 844145132Sanholt dev->dev_private = (void *)dev_priv; 845145132Sanholt mach64_do_cleanup_dma(dev); 846145132Sanholt return DRM_ERR(EINVAL); 847145132Sanholt } 848145132Sanholt /* there might be a nicer way to do this - 849145132Sanholt dev isn't passed all the way though the mach64 - DA */ 850145132Sanholt dev_priv->dev_buffers = dev->agp_buffer_map; 851145132Sanholt 852145132Sanholt drm_core_ioremap(dev->agp_buffer_map, dev); 853145132Sanholt if (!dev->agp_buffer_map->handle) { 854145132Sanholt DRM_ERROR("can not ioremap virtual address for" 855145132Sanholt " dma buffer\n"); 856145132Sanholt dev->dev_private = (void *)dev_priv; 857145132Sanholt mach64_do_cleanup_dma(dev); 858145132Sanholt return DRM_ERR(ENOMEM); 859145132Sanholt } 860145132Sanholt dev_priv->agp_textures = 861145132Sanholt drm_core_findmap(dev, init->agp_textures_offset); 862145132Sanholt if (!dev_priv->agp_textures) { 863145132Sanholt DRM_ERROR("can not find agp texture region!\n"); 864145132Sanholt dev->dev_private = (void *)dev_priv; 865145132Sanholt mach64_do_cleanup_dma(dev); 866145132Sanholt return DRM_ERR(EINVAL); 867145132Sanholt } 868145132Sanholt } 869145132Sanholt 870145132Sanholt dev->dev_private = (void *)dev_priv; 871145132Sanholt 872145132Sanholt dev_priv->driver_mode = init->dma_mode; 873145132Sanholt 874145132Sanholt /* changing the FIFO size from the default causes problems with DMA */ 875145132Sanholt tmp = MACH64_READ(MACH64_GUI_CNTL); 876145132Sanholt if ((tmp & MACH64_CMDFIFO_SIZE_MASK) != MACH64_CMDFIFO_SIZE_128) { 877145132Sanholt DRM_INFO("Setting FIFO size to 128 entries\n"); 878145132Sanholt /* FIFO must be empty to change the FIFO depth */ 879145132Sanholt if ((ret = mach64_do_wait_for_idle(dev_priv))) { 880145132Sanholt DRM_ERROR 881145132Sanholt ("wait for idle failed before changing FIFO depth!\n"); 882145132Sanholt mach64_do_cleanup_dma(dev); 883145132Sanholt return ret; 884145132Sanholt } 885145132Sanholt MACH64_WRITE(MACH64_GUI_CNTL, ((tmp & ~MACH64_CMDFIFO_SIZE_MASK) 886145132Sanholt | MACH64_CMDFIFO_SIZE_128)); 887145132Sanholt /* need to read GUI_STAT for proper sync according to docs */ 888145132Sanholt if ((ret = mach64_do_wait_for_idle(dev_priv))) { 889145132Sanholt DRM_ERROR 890145132Sanholt ("wait for idle failed when changing FIFO depth!\n"); 891145132Sanholt mach64_do_cleanup_dma(dev); 892145132Sanholt return ret; 893145132Sanholt } 894145132Sanholt } 895145132Sanholt 896145132Sanholt /* allocate descriptor memory from pci pool */ 897145132Sanholt DRM_DEBUG("Allocating dma descriptor ring\n"); 898145132Sanholt dev_priv->ring.size = 0x4000; /* 16KB */ 899145132Sanholt 900145132Sanholt if (dev_priv->is_pci) { 901145132Sanholt dev_priv->ring.start = drm_pci_alloc(dev, dev_priv->ring.size, 902145132Sanholt dev_priv->ring.size, 903145132Sanholt 0xfffffffful, 904145132Sanholt &dev_priv->ring.handle); 905145132Sanholt 906145132Sanholt if (!dev_priv->ring.start || !dev_priv->ring.handle) { 907145132Sanholt DRM_ERROR("Allocating dma descriptor ring failed\n"); 908145132Sanholt return DRM_ERR(ENOMEM); 909145132Sanholt } else { 910145132Sanholt dev_priv->ring.start_addr = (u32) dev_priv->ring.handle; 911145132Sanholt } 912145132Sanholt } else { 913145132Sanholt dev_priv->ring.start = dev_priv->ring_map->handle; 914145132Sanholt dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset; 915145132Sanholt } 916145132Sanholt 917145132Sanholt memset(dev_priv->ring.start, 0, dev_priv->ring.size); 918145132Sanholt DRM_INFO("descriptor ring: cpu addr %p, bus addr: 0x%08x\n", 919145132Sanholt dev_priv->ring.start, dev_priv->ring.start_addr); 920145132Sanholt 921145132Sanholt ret = 0; 922145132Sanholt if (dev_priv->driver_mode != MACH64_MODE_MMIO) { 923145132Sanholt 924145132Sanholt /* enable block 1 registers and bus mastering */ 925145132Sanholt MACH64_WRITE(MACH64_BUS_CNTL, ((MACH64_READ(MACH64_BUS_CNTL) 926145132Sanholt | MACH64_BUS_EXT_REG_EN) 927145132Sanholt & ~MACH64_BUS_MASTER_DIS)); 928145132Sanholt 929145132Sanholt /* try a DMA GUI-mastering pass and fall back to MMIO if it fails */ 930145132Sanholt DRM_DEBUG("Starting DMA test...\n"); 931145132Sanholt if ((ret = mach64_bm_dma_test(dev))) { 932145132Sanholt dev_priv->driver_mode = MACH64_MODE_MMIO; 933145132Sanholt } 934145132Sanholt } 935145132Sanholt 936145132Sanholt switch (dev_priv->driver_mode) { 937145132Sanholt case MACH64_MODE_MMIO: 938145132Sanholt MACH64_WRITE(MACH64_BUS_CNTL, (MACH64_READ(MACH64_BUS_CNTL) 939145132Sanholt | MACH64_BUS_EXT_REG_EN 940145132Sanholt | MACH64_BUS_MASTER_DIS)); 941145132Sanholt if (init->dma_mode == MACH64_MODE_MMIO) 942145132Sanholt DRM_INFO("Forcing pseudo-DMA mode\n"); 943145132Sanholt else 944145132Sanholt DRM_INFO 945145132Sanholt ("DMA test failed (ret=%d), using pseudo-DMA mode\n", 946145132Sanholt ret); 947145132Sanholt break; 948145132Sanholt case MACH64_MODE_DMA_SYNC: 949145132Sanholt DRM_INFO("DMA test succeeded, using synchronous DMA mode\n"); 950145132Sanholt break; 951145132Sanholt case MACH64_MODE_DMA_ASYNC: 952145132Sanholt default: 953145132Sanholt DRM_INFO("DMA test succeeded, using asynchronous DMA mode\n"); 954145132Sanholt } 955145132Sanholt 956145132Sanholt dev_priv->ring_running = 0; 957145132Sanholt 958145132Sanholt /* setup offsets for physical address of table start and end */ 959145132Sanholt dev_priv->ring.head_addr = dev_priv->ring.start_addr; 960145132Sanholt dev_priv->ring.head = dev_priv->ring.tail = 0; 961145132Sanholt dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; 962145132Sanholt dev_priv->ring.space = dev_priv->ring.size; 963145132Sanholt 964145132Sanholt /* setup physical address and size of descriptor table */ 965145132Sanholt mach64_do_wait_for_fifo(dev_priv, 1); 966145132Sanholt MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, 967145132Sanholt (dev_priv->ring. 968145132Sanholt head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB)); 969145132Sanholt 970145132Sanholt /* init frame counter */ 971145132Sanholt dev_priv->sarea_priv->frames_queued = 0; 972145132Sanholt for (i = 0; i < MACH64_MAX_QUEUED_FRAMES; i++) { 973145132Sanholt dev_priv->frame_ofs[i] = ~0; /* All ones indicates placeholder */ 974145132Sanholt } 975145132Sanholt 976145132Sanholt /* Allocate the DMA buffer freelist */ 977145132Sanholt if ((ret = mach64_init_freelist(dev))) { 978145132Sanholt DRM_ERROR("Freelist allocation failed\n"); 979145132Sanholt mach64_do_cleanup_dma(dev); 980145132Sanholt return ret; 981145132Sanholt } 982145132Sanholt 983145132Sanholt return 0; 984145132Sanholt} 985145132Sanholt 986145132Sanholt/*******************************************************************/ 987145132Sanholt/** MMIO Pseudo-DMA (intended primarily for debugging, not performance) 988145132Sanholt */ 989145132Sanholt 990145132Sanholtint mach64_do_dispatch_pseudo_dma(drm_mach64_private_t * dev_priv) 991145132Sanholt{ 992145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 993145132Sanholt volatile u32 *ring_read; 994145132Sanholt struct list_head *ptr; 995145132Sanholt drm_mach64_freelist_t *entry; 996145132Sanholt drm_buf_t *buf = NULL; 997145132Sanholt u32 *buf_ptr; 998145132Sanholt u32 used, reg, target; 999145132Sanholt int fifo, count, found, ret, no_idle_wait; 1000145132Sanholt 1001145132Sanholt fifo = count = reg = no_idle_wait = 0; 1002145132Sanholt target = MACH64_BM_ADDR; 1003145132Sanholt 1004145132Sanholt if ((ret = mach64_do_wait_for_idle(dev_priv)) < 0) { 1005145132Sanholt DRM_INFO 1006145132Sanholt ("%s: idle failed before pseudo-dma dispatch, resetting engine\n", 1007145132Sanholt __FUNCTION__); 1008145132Sanholt mach64_dump_engine_info(dev_priv); 1009145132Sanholt mach64_do_engine_reset(dev_priv); 1010145132Sanholt return ret; 1011145132Sanholt } 1012145132Sanholt 1013145132Sanholt ring_read = (u32 *) ring->start; 1014145132Sanholt 1015145132Sanholt while (ring->tail != ring->head) { 1016145132Sanholt u32 buf_addr, new_target, offset; 1017145132Sanholt u32 bytes, remaining, head, eol; 1018145132Sanholt 1019145132Sanholt head = ring->head; 1020145132Sanholt 1021145132Sanholt new_target = 1022145132Sanholt le32_to_cpu(ring_read[head++]) - MACH64_APERTURE_OFFSET; 1023145132Sanholt buf_addr = le32_to_cpu(ring_read[head++]); 1024145132Sanholt eol = le32_to_cpu(ring_read[head]) & MACH64_DMA_EOL; 1025145132Sanholt bytes = le32_to_cpu(ring_read[head++]) 1026145132Sanholt & ~(MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL); 1027145132Sanholt head++; 1028145132Sanholt head &= ring->tail_mask; 1029145132Sanholt 1030145132Sanholt /* can't wait for idle between a blit setup descriptor 1031145132Sanholt * and a HOSTDATA descriptor or the engine will lock 1032145132Sanholt */ 1033145132Sanholt if (new_target == MACH64_BM_HOSTDATA 1034145132Sanholt && target == MACH64_BM_ADDR) 1035145132Sanholt no_idle_wait = 1; 1036145132Sanholt 1037145132Sanholt target = new_target; 1038145132Sanholt 1039145132Sanholt found = 0; 1040145132Sanholt offset = 0; 1041145132Sanholt list_for_each(ptr, &dev_priv->pending) { 1042145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1043145132Sanholt buf = entry->buf; 1044145132Sanholt offset = buf_addr - GETBUFADDR(buf); 1045145132Sanholt if (offset >= 0 && offset < MACH64_BUFFER_SIZE) { 1046145132Sanholt found = 1; 1047145132Sanholt break; 1048145132Sanholt } 1049145132Sanholt } 1050145132Sanholt 1051145132Sanholt if (!found || buf == NULL) { 1052145132Sanholt DRM_ERROR 1053145132Sanholt ("Couldn't find pending buffer: head: %u tail: %u buf_addr: 0x%08x %s\n", 1054145132Sanholt head, ring->tail, buf_addr, (eol ? "eol" : "")); 1055145132Sanholt mach64_dump_ring_info(dev_priv); 1056145132Sanholt mach64_do_engine_reset(dev_priv); 1057145132Sanholt return DRM_ERR(EINVAL); 1058145132Sanholt } 1059145132Sanholt 1060145132Sanholt /* Hand feed the buffer to the card via MMIO, waiting for the fifo 1061145132Sanholt * every 16 writes 1062145132Sanholt */ 1063145132Sanholt DRM_DEBUG("target: (0x%08x) %s\n", target, 1064145132Sanholt (target == 1065145132Sanholt MACH64_BM_HOSTDATA ? "BM_HOSTDATA" : "BM_ADDR")); 1066145132Sanholt DRM_DEBUG("offset: %u bytes: %u used: %u\n", offset, bytes, 1067145132Sanholt buf->used); 1068145132Sanholt 1069145132Sanholt remaining = (buf->used - offset) >> 2; /* dwords remaining in buffer */ 1070145132Sanholt used = bytes >> 2; /* dwords in buffer for this descriptor */ 1071145132Sanholt buf_ptr = (u32 *) ((char *)GETBUFPTR(buf) + offset); 1072145132Sanholt 1073145132Sanholt while (used) { 1074145132Sanholt 1075145132Sanholt if (count == 0) { 1076145132Sanholt if (target == MACH64_BM_HOSTDATA) { 1077145132Sanholt reg = DMAREG(MACH64_HOST_DATA0); 1078145132Sanholt count = 1079145132Sanholt (remaining > 16) ? 16 : remaining; 1080145132Sanholt fifo = 0; 1081145132Sanholt } else { 1082145132Sanholt reg = le32_to_cpu(*buf_ptr++); 1083145132Sanholt used--; 1084145132Sanholt count = (reg >> 16) + 1; 1085145132Sanholt } 1086145132Sanholt 1087145132Sanholt reg = reg & 0xffff; 1088145132Sanholt reg = MMSELECT(reg); 1089145132Sanholt } 1090145132Sanholt while (count && used) { 1091145132Sanholt if (!fifo) { 1092145132Sanholt if (no_idle_wait) { 1093145132Sanholt if ((ret = 1094145132Sanholt mach64_do_wait_for_fifo 1095145132Sanholt (dev_priv, 16)) < 0) { 1096145132Sanholt no_idle_wait = 0; 1097145132Sanholt return ret; 1098145132Sanholt } 1099145132Sanholt } else { 1100145132Sanholt if ((ret = 1101145132Sanholt mach64_do_wait_for_idle 1102145132Sanholt (dev_priv)) < 0) { 1103145132Sanholt return ret; 1104145132Sanholt } 1105145132Sanholt } 1106145132Sanholt fifo = 16; 1107145132Sanholt } 1108145132Sanholt --fifo; 1109145132Sanholt MACH64_WRITE(reg, le32_to_cpu(*buf_ptr++)); 1110145132Sanholt used--; 1111145132Sanholt remaining--; 1112145132Sanholt 1113145132Sanholt reg += 4; 1114145132Sanholt count--; 1115145132Sanholt } 1116145132Sanholt } 1117145132Sanholt ring->head = head; 1118145132Sanholt ring->head_addr = ring->start_addr + (ring->head * sizeof(u32)); 1119145132Sanholt ring->space += (4 * sizeof(u32)); 1120145132Sanholt } 1121145132Sanholt 1122145132Sanholt if ((ret = mach64_do_wait_for_idle(dev_priv)) < 0) { 1123145132Sanholt return ret; 1124145132Sanholt } 1125145132Sanholt MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, 1126145132Sanholt ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); 1127145132Sanholt 1128145132Sanholt DRM_DEBUG("%s completed\n", __FUNCTION__); 1129145132Sanholt return 0; 1130145132Sanholt} 1131145132Sanholt 1132145132Sanholt/*@}*/ 1133145132Sanholt 1134145132Sanholt 1135145132Sanholt/*******************************************************************/ 1136145132Sanholt/** \name DMA cleanup */ 1137145132Sanholt/*@{*/ 1138145132Sanholt 1139145132Sanholtint mach64_do_cleanup_dma(drm_device_t * dev) 1140145132Sanholt{ 1141145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 1142145132Sanholt 1143145132Sanholt /* Make sure interrupts are disabled here because the uninstall ioctl 1144145132Sanholt * may not have been called from userspace and after dev_private 1145145132Sanholt * is freed, it's too late. 1146145132Sanholt */ 1147145132Sanholt if (dev->irq) 1148145132Sanholt drm_irq_uninstall(dev); 1149145132Sanholt 1150145132Sanholt if (dev->dev_private) { 1151145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1152145132Sanholt 1153145132Sanholt if (dev_priv->is_pci) { 1154145132Sanholt if ((dev_priv->ring.start != NULL) 1155145132Sanholt && dev_priv->ring.handle) { 1156145132Sanholt drm_pci_free(dev, dev_priv->ring.size, 1157145132Sanholt dev_priv->ring.start, 1158145132Sanholt dev_priv->ring.handle); 1159145132Sanholt } 1160145132Sanholt } else { 1161145132Sanholt if (dev_priv->ring_map) 1162145132Sanholt drm_core_ioremapfree(dev_priv->ring_map, dev); 1163145132Sanholt } 1164145132Sanholt 1165145132Sanholt if (dev->agp_buffer_map) { 1166145132Sanholt drm_core_ioremapfree(dev->agp_buffer_map, dev); 1167145132Sanholt dev->agp_buffer_map = NULL; 1168145132Sanholt } 1169145132Sanholt 1170145132Sanholt mach64_destroy_freelist(dev); 1171145132Sanholt 1172145132Sanholt drm_free(dev_priv, sizeof(drm_mach64_private_t), 1173145132Sanholt DRM_MEM_DRIVER); 1174145132Sanholt dev->dev_private = NULL; 1175145132Sanholt } 1176145132Sanholt 1177145132Sanholt return 0; 1178145132Sanholt} 1179145132Sanholt 1180145132Sanholt/*@}*/ 1181145132Sanholt 1182145132Sanholt 1183145132Sanholt/*******************************************************************/ 1184145132Sanholt/** \name IOCTL handlers */ 1185145132Sanholt/*@{*/ 1186145132Sanholt 1187145132Sanholtint mach64_dma_init(DRM_IOCTL_ARGS) 1188145132Sanholt{ 1189145132Sanholt DRM_DEVICE; 1190145132Sanholt drm_mach64_init_t init; 1191145132Sanholt 1192145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 1193145132Sanholt 1194145132Sanholt LOCK_TEST_WITH_RETURN(dev, filp); 1195145132Sanholt 1196145132Sanholt DRM_COPY_FROM_USER_IOCTL(init, (drm_mach64_init_t *) data, 1197145132Sanholt sizeof(init)); 1198145132Sanholt 1199145132Sanholt switch (init.func) { 1200145132Sanholt case DRM_MACH64_INIT_DMA: 1201145132Sanholt return mach64_do_dma_init(dev, &init); 1202145132Sanholt case DRM_MACH64_CLEANUP_DMA: 1203145132Sanholt return mach64_do_cleanup_dma(dev); 1204145132Sanholt } 1205145132Sanholt 1206145132Sanholt return DRM_ERR(EINVAL); 1207145132Sanholt} 1208145132Sanholt 1209145132Sanholtint mach64_dma_idle(DRM_IOCTL_ARGS) 1210145132Sanholt{ 1211145132Sanholt DRM_DEVICE; 1212145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1213145132Sanholt 1214145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 1215145132Sanholt 1216145132Sanholt LOCK_TEST_WITH_RETURN(dev, filp); 1217145132Sanholt 1218145132Sanholt return mach64_do_dma_idle(dev_priv); 1219145132Sanholt} 1220145132Sanholt 1221145132Sanholtint mach64_dma_flush(DRM_IOCTL_ARGS) 1222145132Sanholt{ 1223145132Sanholt DRM_DEVICE; 1224145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1225145132Sanholt 1226145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 1227145132Sanholt 1228145132Sanholt LOCK_TEST_WITH_RETURN(dev, filp); 1229145132Sanholt 1230145132Sanholt return mach64_do_dma_flush(dev_priv); 1231145132Sanholt} 1232145132Sanholt 1233145132Sanholtint mach64_engine_reset(DRM_IOCTL_ARGS) 1234145132Sanholt{ 1235145132Sanholt DRM_DEVICE; 1236145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1237145132Sanholt 1238145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 1239145132Sanholt 1240145132Sanholt LOCK_TEST_WITH_RETURN(dev, filp); 1241145132Sanholt 1242145132Sanholt return mach64_do_engine_reset(dev_priv); 1243145132Sanholt} 1244145132Sanholt 1245145132Sanholt/*@}*/ 1246145132Sanholt 1247145132Sanholt 1248145132Sanholt/*******************************************************************/ 1249145132Sanholt/** \name Freelist management */ 1250145132Sanholt/*@{*/ 1251145132Sanholt 1252145132Sanholtint mach64_init_freelist(drm_device_t * dev) 1253145132Sanholt{ 1254145132Sanholt drm_device_dma_t *dma = dev->dma; 1255145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1256145132Sanholt drm_mach64_freelist_t *entry; 1257145132Sanholt struct list_head *ptr; 1258145132Sanholt int i; 1259145132Sanholt 1260145132Sanholt DRM_DEBUG("%s: adding %d buffers to freelist\n", __FUNCTION__, 1261145132Sanholt dma->buf_count); 1262145132Sanholt 1263145132Sanholt for (i = 0; i < dma->buf_count; i++) { 1264145132Sanholt if ((entry = 1265145132Sanholt (drm_mach64_freelist_t *) 1266145132Sanholt drm_alloc(sizeof(drm_mach64_freelist_t), 1267145132Sanholt DRM_MEM_BUFLISTS)) == NULL) 1268145132Sanholt return DRM_ERR(ENOMEM); 1269145132Sanholt memset(entry, 0, sizeof(drm_mach64_freelist_t)); 1270145132Sanholt entry->buf = dma->buflist[i]; 1271145132Sanholt ptr = &entry->list; 1272145132Sanholt list_add_tail(ptr, &dev_priv->free_list); 1273145132Sanholt } 1274145132Sanholt 1275145132Sanholt return 0; 1276145132Sanholt} 1277145132Sanholt 1278145132Sanholtvoid mach64_destroy_freelist(drm_device_t * dev) 1279145132Sanholt{ 1280145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1281145132Sanholt drm_mach64_freelist_t *entry; 1282145132Sanholt struct list_head *ptr; 1283145132Sanholt struct list_head *tmp; 1284145132Sanholt 1285145132Sanholt DRM_DEBUG("%s\n", __FUNCTION__); 1286145132Sanholt 1287145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->pending) { 1288145132Sanholt list_del(ptr); 1289145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1290145132Sanholt drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); 1291145132Sanholt } 1292145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->placeholders) { 1293145132Sanholt list_del(ptr); 1294145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1295145132Sanholt drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); 1296145132Sanholt } 1297145132Sanholt 1298145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->free_list) { 1299145132Sanholt list_del(ptr); 1300145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1301145132Sanholt drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); 1302145132Sanholt } 1303145132Sanholt} 1304145132Sanholt 1305145132Sanholt/* IMPORTANT: This function should only be called when the engine is idle or locked up, 1306145132Sanholt * as it assumes all buffers in the pending list have been completed by the hardware. 1307145132Sanholt */ 1308145132Sanholtint mach64_do_release_used_buffers(drm_mach64_private_t * dev_priv) 1309145132Sanholt{ 1310145132Sanholt struct list_head *ptr; 1311145132Sanholt struct list_head *tmp; 1312145132Sanholt drm_mach64_freelist_t *entry; 1313145132Sanholt int i; 1314145132Sanholt 1315145132Sanholt if (list_empty(&dev_priv->pending)) 1316145132Sanholt return 0; 1317145132Sanholt 1318145132Sanholt /* Iterate the pending list and move all buffers into the freelist... */ 1319145132Sanholt i = 0; 1320145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->pending) { 1321145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1322145132Sanholt if (entry->discard) { 1323145132Sanholt entry->buf->pending = 0; 1324145132Sanholt list_del(ptr); 1325145132Sanholt list_add_tail(ptr, &dev_priv->free_list); 1326145132Sanholt i++; 1327145132Sanholt } 1328145132Sanholt } 1329145132Sanholt 1330145132Sanholt DRM_DEBUG("%s: released %d buffers from pending list\n", __FUNCTION__, 1331145132Sanholt i); 1332145132Sanholt 1333145132Sanholt return 0; 1334145132Sanholt} 1335145132Sanholt 1336145132Sanholtdrm_buf_t *mach64_freelist_get(drm_mach64_private_t * dev_priv) 1337145132Sanholt{ 1338145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 1339145132Sanholt drm_mach64_freelist_t *entry; 1340145132Sanholt struct list_head *ptr; 1341145132Sanholt struct list_head *tmp; 1342145132Sanholt int t; 1343145132Sanholt 1344145132Sanholt if (list_empty(&dev_priv->free_list)) { 1345145132Sanholt u32 head, tail, ofs; 1346145132Sanholt 1347145132Sanholt if (list_empty(&dev_priv->pending)) { 1348145132Sanholt DRM_ERROR 1349145132Sanholt ("Couldn't get buffer - pending and free lists empty\n"); 1350145132Sanholt t = 0; 1351145132Sanholt list_for_each(ptr, &dev_priv->placeholders) { 1352145132Sanholt t++; 1353145132Sanholt } 1354145132Sanholt DRM_INFO("Placeholders: %d\n", t); 1355145132Sanholt return NULL; 1356145132Sanholt } 1357145132Sanholt 1358145132Sanholt tail = ring->tail; 1359145132Sanholt for (t = 0; t < dev_priv->usec_timeout; t++) { 1360145132Sanholt mach64_ring_tick(dev_priv, ring); 1361145132Sanholt head = ring->head; 1362145132Sanholt 1363145132Sanholt if (head == tail) { 1364145132Sanholt#if MACH64_EXTRA_CHECKING 1365145132Sanholt if (MACH64_READ(MACH64_GUI_STAT) & 1366145132Sanholt MACH64_GUI_ACTIVE) { 1367145132Sanholt DRM_ERROR 1368145132Sanholt ("Empty ring with non-idle engine!\n"); 1369145132Sanholt mach64_dump_ring_info(dev_priv); 1370145132Sanholt return NULL; 1371145132Sanholt } 1372145132Sanholt#endif 1373145132Sanholt /* last pass is complete, so release everything */ 1374145132Sanholt mach64_do_release_used_buffers(dev_priv); 1375145132Sanholt DRM_DEBUG 1376145132Sanholt ("%s: idle engine, freed all buffers.\n", 1377145132Sanholt __FUNCTION__); 1378145132Sanholt if (list_empty(&dev_priv->free_list)) { 1379145132Sanholt DRM_ERROR 1380145132Sanholt ("Freelist empty with idle engine\n"); 1381145132Sanholt return NULL; 1382145132Sanholt } 1383145132Sanholt goto _freelist_entry_found; 1384145132Sanholt } 1385145132Sanholt /* Look for a completed buffer and bail out of the loop 1386145132Sanholt * as soon as we find one -- don't waste time trying 1387145132Sanholt * to free extra bufs here, leave that to do_release_used_buffers 1388145132Sanholt */ 1389145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->pending) { 1390145132Sanholt entry = 1391145132Sanholt list_entry(ptr, drm_mach64_freelist_t, 1392145132Sanholt list); 1393145132Sanholt ofs = entry->ring_ofs; 1394145132Sanholt if (entry->discard && 1395145132Sanholt ((head < tail 1396145132Sanholt && (ofs < head || ofs >= tail)) 1397145132Sanholt || (head > tail 1398145132Sanholt && (ofs < head && ofs >= tail)))) { 1399145132Sanholt#if MACH64_EXTRA_CHECKING 1400145132Sanholt int i; 1401145132Sanholt 1402145132Sanholt for (i = head; i != tail; 1403145132Sanholt i = (i + 4) & ring->tail_mask) { 1404145132Sanholt u32 o1 = 1405145132Sanholt le32_to_cpu(((u32 *) ring-> 1406145132Sanholt start)[i + 1]); 1407145132Sanholt u32 o2 = GETBUFADDR(entry->buf); 1408145132Sanholt 1409145132Sanholt if (o1 == o2) { 1410145132Sanholt DRM_ERROR 1411145132Sanholt ("Attempting to free used buffer: " 1412145132Sanholt "i=%d buf=0x%08x\n", 1413145132Sanholt i, o1); 1414145132Sanholt mach64_dump_ring_info 1415145132Sanholt (dev_priv); 1416145132Sanholt return NULL; 1417145132Sanholt } 1418145132Sanholt } 1419145132Sanholt#endif 1420145132Sanholt /* found a processed buffer */ 1421145132Sanholt entry->buf->pending = 0; 1422145132Sanholt list_del(ptr); 1423145132Sanholt entry->buf->used = 0; 1424145132Sanholt list_add_tail(ptr, 1425145132Sanholt &dev_priv->placeholders); 1426145132Sanholt DRM_DEBUG 1427145132Sanholt ("%s: freed processed buffer (head=%d tail=%d " 1428145132Sanholt "buf ring ofs=%d).\n", 1429145132Sanholt __FUNCTION__, head, tail, ofs); 1430145132Sanholt return entry->buf; 1431145132Sanholt } 1432145132Sanholt } 1433145132Sanholt DRM_UDELAY(1); 1434145132Sanholt } 1435145132Sanholt mach64_dump_ring_info(dev_priv); 1436145132Sanholt DRM_ERROR 1437145132Sanholt ("timeout waiting for buffers: ring head_addr: 0x%08x head: %d tail: %d\n", 1438145132Sanholt ring->head_addr, ring->head, ring->tail); 1439145132Sanholt return NULL; 1440145132Sanholt } 1441145132Sanholt 1442145132Sanholt _freelist_entry_found: 1443145132Sanholt ptr = dev_priv->free_list.next; 1444145132Sanholt list_del(ptr); 1445145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1446145132Sanholt entry->buf->used = 0; 1447145132Sanholt list_add_tail(ptr, &dev_priv->placeholders); 1448145132Sanholt return entry->buf; 1449145132Sanholt} 1450145132Sanholt 1451145132Sanholt/*@}*/ 1452145132Sanholt 1453145132Sanholt 1454145132Sanholt/*******************************************************************/ 1455145132Sanholt/** \name DMA buffer request and submission IOCTL handler */ 1456145132Sanholt/*@{*/ 1457145132Sanholt 1458145132Sanholtstatic int mach64_dma_get_buffers(DRMFILE filp, drm_device_t * dev, 1459145132Sanholt drm_dma_t * d) 1460145132Sanholt{ 1461145132Sanholt int i; 1462145132Sanholt drm_buf_t *buf; 1463145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1464145132Sanholt 1465145132Sanholt for (i = d->granted_count; i < d->request_count; i++) { 1466145132Sanholt buf = mach64_freelist_get(dev_priv); 1467145132Sanholt#if MACH64_EXTRA_CHECKING 1468145132Sanholt if (!buf) 1469145132Sanholt return DRM_ERR(EFAULT); 1470145132Sanholt#else 1471145132Sanholt if (!buf) 1472145132Sanholt return DRM_ERR(EAGAIN); 1473145132Sanholt#endif 1474145132Sanholt 1475145132Sanholt buf->filp = filp; 1476145132Sanholt 1477145132Sanholt if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, 1478145132Sanholt sizeof(buf->idx))) 1479145132Sanholt return DRM_ERR(EFAULT); 1480145132Sanholt if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, 1481145132Sanholt sizeof(buf->total))) 1482145132Sanholt return DRM_ERR(EFAULT); 1483145132Sanholt 1484145132Sanholt d->granted_count++; 1485145132Sanholt } 1486145132Sanholt return 0; 1487145132Sanholt} 1488145132Sanholt 1489145132Sanholtint mach64_dma_buffers(DRM_IOCTL_ARGS) 1490145132Sanholt{ 1491145132Sanholt DRM_DEVICE; 1492145132Sanholt drm_device_dma_t *dma = dev->dma; 1493145132Sanholt drm_dma_t d; 1494145132Sanholt int ret = 0; 1495145132Sanholt 1496145132Sanholt LOCK_TEST_WITH_RETURN(dev, filp); 1497145132Sanholt 1498145132Sanholt DRM_COPY_FROM_USER_IOCTL(d, (drm_dma_t *) data, sizeof(d)); 1499145132Sanholt 1500145132Sanholt /* Please don't send us buffers. 1501145132Sanholt */ 1502145132Sanholt if (d.send_count != 0) { 1503145132Sanholt DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", 1504145132Sanholt DRM_CURRENTPID, d.send_count); 1505145132Sanholt return DRM_ERR(EINVAL); 1506145132Sanholt } 1507145132Sanholt 1508145132Sanholt /* We'll send you buffers. 1509145132Sanholt */ 1510145132Sanholt if (d.request_count < 0 || d.request_count > dma->buf_count) { 1511145132Sanholt DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", 1512145132Sanholt DRM_CURRENTPID, d.request_count, dma->buf_count); 1513145132Sanholt ret = DRM_ERR(EINVAL); 1514145132Sanholt } 1515145132Sanholt 1516145132Sanholt d.granted_count = 0; 1517145132Sanholt 1518145132Sanholt if (d.request_count) { 1519145132Sanholt ret = mach64_dma_get_buffers(filp, dev, &d); 1520145132Sanholt } 1521145132Sanholt 1522145132Sanholt DRM_COPY_TO_USER_IOCTL((drm_dma_t *) data, d, sizeof(d)); 1523145132Sanholt 1524145132Sanholt return ret; 1525145132Sanholt} 1526145132Sanholt 1527145132Sanholtvoid mach64_driver_pretakedown(drm_device_t * dev) 1528145132Sanholt{ 1529145132Sanholt mach64_do_cleanup_dma(dev); 1530145132Sanholt} 1531145132Sanholt 1532145132Sanholt/*@}*/ 1533