mach64_dma.c revision 182080
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> 9182080Srnoland * \author Jos�� Fonseca <j_r_fonseca@yahoo.co.uk> 10145132Sanholt */ 11145132Sanholt 12152909Sanholt/*- 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 37152909Sanholt#include <sys/cdefs.h> 38152909Sanholt__FBSDID("$FreeBSD: head/sys/dev/drm/mach64_dma.c 182080 2008-08-23 20:59:12Z rnoland $"); 39152909Sanholt 40145132Sanholt#include "dev/drm/drmP.h" 41145132Sanholt#include "dev/drm/drm.h" 42145132Sanholt#include "dev/drm/mach64_drm.h" 43145132Sanholt#include "dev/drm/mach64_drv.h" 44145132Sanholt 45145132Sanholt/*******************************************************************/ 46145132Sanholt/** \name Engine, FIFO control */ 47145132Sanholt/*@{*/ 48145132Sanholt 49145132Sanholt/** 50145132Sanholt * Waits for free entries in the FIFO. 51145132Sanholt * 52145132Sanholt * \note Most writes to Mach64 registers are automatically routed through 53145132Sanholt * command FIFO which is 16 entry deep. Prior to writing to any draw engine 54145132Sanholt * register one has to ensure that enough FIFO entries are available by calling 55145132Sanholt * this function. Failure to do so may cause the engine to lock. 56145132Sanholt * 57145132Sanholt * \param dev_priv pointer to device private data structure. 58145132Sanholt * \param entries number of free entries in the FIFO to wait for. 59182080Srnoland * 60145132Sanholt * \returns zero on success, or -EBUSY if the timeout (specificed by 61145132Sanholt * drm_mach64_private::usec_timeout) occurs. 62145132Sanholt */ 63182080Srnolandint mach64_do_wait_for_fifo(drm_mach64_private_t *dev_priv, int entries) 64145132Sanholt{ 65145132Sanholt int slots = 0, i; 66145132Sanholt 67145132Sanholt for (i = 0; i < dev_priv->usec_timeout; i++) { 68145132Sanholt slots = (MACH64_READ(MACH64_FIFO_STAT) & MACH64_FIFO_SLOT_MASK); 69145132Sanholt if (slots <= (0x8000 >> entries)) 70145132Sanholt return 0; 71145132Sanholt DRM_UDELAY(1); 72145132Sanholt } 73145132Sanholt 74182080Srnoland DRM_INFO("failed! slots=%d entries=%d\n", slots, entries); 75182080Srnoland return -EBUSY; 76145132Sanholt} 77145132Sanholt 78145132Sanholt/** 79145132Sanholt * Wait for the draw engine to be idle. 80145132Sanholt */ 81182080Srnolandint 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++) { 90182080Srnoland if (!(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) 91145132Sanholt return 0; 92145132Sanholt DRM_UDELAY(1); 93145132Sanholt } 94145132Sanholt 95182080Srnoland DRM_INFO("failed! GUI_STAT=0x%08x\n", MACH64_READ(MACH64_GUI_STAT)); 96145132Sanholt mach64_dump_ring_info(dev_priv); 97182080Srnoland return -EBUSY; 98145132Sanholt} 99145132Sanholt 100145132Sanholt/** 101145132Sanholt * Wait for free entries in the ring buffer. 102145132Sanholt * 103145132Sanholt * The Mach64 bus master can be configured to act as a virtual FIFO, using a 104145132Sanholt * circular buffer (commonly referred as "ring buffer" in other drivers) with 105145132Sanholt * pointers to engine commands. This allows the CPU to do other things while 106145132Sanholt * the graphics engine is busy, i.e., DMA mode. 107145132Sanholt * 108145132Sanholt * This function should be called before writing new entries to the ring 109145132Sanholt * buffer. 110182080Srnoland * 111145132Sanholt * \param dev_priv pointer to device private data structure. 112145132Sanholt * \param n number of free entries in the ring buffer to wait for. 113182080Srnoland * 114145132Sanholt * \returns zero on success, or -EBUSY if the timeout (specificed by 115145132Sanholt * drm_mach64_private_t::usec_timeout) occurs. 116145132Sanholt * 117145132Sanholt * \sa mach64_dump_ring_info() 118145132Sanholt */ 119182080Srnolandint mach64_wait_ring(drm_mach64_private_t *dev_priv, int n) 120145132Sanholt{ 121145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 122145132Sanholt int i; 123145132Sanholt 124145132Sanholt for (i = 0; i < dev_priv->usec_timeout; i++) { 125145132Sanholt mach64_update_ring_snapshot(dev_priv); 126145132Sanholt if (ring->space >= n) { 127182080Srnoland if (i > 0) 128182080Srnoland DRM_DEBUG("%d usecs\n", i); 129145132Sanholt return 0; 130145132Sanholt } 131145132Sanholt DRM_UDELAY(1); 132145132Sanholt } 133145132Sanholt 134145132Sanholt /* FIXME: This is being ignored... */ 135145132Sanholt DRM_ERROR("failed!\n"); 136145132Sanholt mach64_dump_ring_info(dev_priv); 137182080Srnoland return -EBUSY; 138145132Sanholt} 139145132Sanholt 140145132Sanholt/** 141182080Srnoland * Wait until all DMA requests have been processed... 142145132Sanholt * 143145132Sanholt * \sa mach64_wait_ring() 144145132Sanholt */ 145182080Srnolandstatic int mach64_ring_idle(drm_mach64_private_t *dev_priv) 146145132Sanholt{ 147145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 148145132Sanholt u32 head; 149145132Sanholt int i; 150145132Sanholt 151145132Sanholt head = ring->head; 152145132Sanholt i = 0; 153145132Sanholt while (i < dev_priv->usec_timeout) { 154145132Sanholt mach64_update_ring_snapshot(dev_priv); 155145132Sanholt if (ring->head == ring->tail && 156145132Sanholt !(MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE)) { 157182080Srnoland if (i > 0) 158182080Srnoland DRM_DEBUG("%d usecs\n", i); 159145132Sanholt return 0; 160145132Sanholt } 161145132Sanholt if (ring->head == head) { 162145132Sanholt ++i; 163145132Sanholt } else { 164145132Sanholt head = ring->head; 165145132Sanholt i = 0; 166145132Sanholt } 167145132Sanholt DRM_UDELAY(1); 168145132Sanholt } 169145132Sanholt 170182080Srnoland DRM_INFO("failed! GUI_STAT=0x%08x\n", MACH64_READ(MACH64_GUI_STAT)); 171145132Sanholt mach64_dump_ring_info(dev_priv); 172182080Srnoland return -EBUSY; 173145132Sanholt} 174145132Sanholt 175145132Sanholt/** 176145132Sanholt * Reset the the ring buffer descriptors. 177145132Sanholt * 178145132Sanholt * \sa mach64_do_engine_reset() 179145132Sanholt */ 180182080Srnolandstatic void mach64_ring_reset(drm_mach64_private_t *dev_priv) 181145132Sanholt{ 182145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 183145132Sanholt 184145132Sanholt mach64_do_release_used_buffers(dev_priv); 185145132Sanholt ring->head_addr = ring->start_addr; 186145132Sanholt ring->head = ring->tail = 0; 187145132Sanholt ring->space = ring->size; 188145132Sanholt 189145132Sanholt MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, 190145132Sanholt ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); 191145132Sanholt 192145132Sanholt dev_priv->ring_running = 0; 193145132Sanholt} 194145132Sanholt 195145132Sanholt/** 196145132Sanholt * Ensure the all the queued commands will be processed. 197145132Sanholt */ 198182080Srnolandint mach64_do_dma_flush(drm_mach64_private_t *dev_priv) 199145132Sanholt{ 200145132Sanholt /* FIXME: It's not necessary to wait for idle when flushing 201145132Sanholt * we just need to ensure the ring will be completely processed 202145132Sanholt * in finite time without another ioctl 203145132Sanholt */ 204145132Sanholt return mach64_ring_idle(dev_priv); 205145132Sanholt} 206145132Sanholt 207145132Sanholt/** 208145132Sanholt * Stop all DMA activity. 209145132Sanholt */ 210182080Srnolandint mach64_do_dma_idle(drm_mach64_private_t *dev_priv) 211145132Sanholt{ 212145132Sanholt int ret; 213145132Sanholt 214145132Sanholt /* wait for completion */ 215145132Sanholt if ((ret = mach64_ring_idle(dev_priv)) < 0) { 216182080Srnoland DRM_ERROR("failed BM_GUI_TABLE=0x%08x tail: %u\n", 217182080Srnoland MACH64_READ(MACH64_BM_GUI_TABLE), 218145132Sanholt dev_priv->ring.tail); 219145132Sanholt return ret; 220145132Sanholt } 221145132Sanholt 222145132Sanholt mach64_ring_stop(dev_priv); 223145132Sanholt 224145132Sanholt /* clean up after pass */ 225145132Sanholt mach64_do_release_used_buffers(dev_priv); 226145132Sanholt return 0; 227145132Sanholt} 228145132Sanholt 229145132Sanholt/** 230145132Sanholt * Reset the engine. This will stop the DMA if it is running. 231145132Sanholt */ 232182080Srnolandint mach64_do_engine_reset(drm_mach64_private_t *dev_priv) 233145132Sanholt{ 234145132Sanholt u32 tmp; 235145132Sanholt 236182080Srnoland DRM_DEBUG("\n"); 237145132Sanholt 238145132Sanholt /* Kill off any outstanding DMA transfers. 239145132Sanholt */ 240145132Sanholt tmp = MACH64_READ(MACH64_BUS_CNTL); 241145132Sanholt MACH64_WRITE(MACH64_BUS_CNTL, tmp | MACH64_BUS_MASTER_DIS); 242145132Sanholt 243145132Sanholt /* Reset the GUI engine (high to low transition). 244145132Sanholt */ 245145132Sanholt tmp = MACH64_READ(MACH64_GEN_TEST_CNTL); 246145132Sanholt MACH64_WRITE(MACH64_GEN_TEST_CNTL, tmp & ~MACH64_GUI_ENGINE_ENABLE); 247145132Sanholt /* Enable the GUI engine 248145132Sanholt */ 249145132Sanholt tmp = MACH64_READ(MACH64_GEN_TEST_CNTL); 250145132Sanholt MACH64_WRITE(MACH64_GEN_TEST_CNTL, tmp | MACH64_GUI_ENGINE_ENABLE); 251145132Sanholt 252145132Sanholt /* ensure engine is not locked up by clearing any FIFO or HOST errors 253145132Sanholt */ 254145132Sanholt tmp = MACH64_READ(MACH64_BUS_CNTL); 255145132Sanholt MACH64_WRITE(MACH64_BUS_CNTL, tmp | 0x00a00000); 256145132Sanholt 257145132Sanholt /* Once GUI engine is restored, disable bus mastering */ 258145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, 0); 259145132Sanholt 260145132Sanholt /* Reset descriptor ring */ 261145132Sanholt mach64_ring_reset(dev_priv); 262145132Sanholt 263145132Sanholt return 0; 264145132Sanholt} 265145132Sanholt 266145132Sanholt/*@}*/ 267145132Sanholt 268145132Sanholt 269145132Sanholt/*******************************************************************/ 270145132Sanholt/** \name Debugging output */ 271145132Sanholt/*@{*/ 272145132Sanholt 273145132Sanholt/** 274145132Sanholt * Dump engine registers values. 275145132Sanholt */ 276182080Srnolandvoid mach64_dump_engine_info(drm_mach64_private_t *dev_priv) 277145132Sanholt{ 278145132Sanholt DRM_INFO("\n"); 279145132Sanholt if (!dev_priv->is_pci) { 280145132Sanholt DRM_INFO(" AGP_BASE = 0x%08x\n", 281145132Sanholt MACH64_READ(MACH64_AGP_BASE)); 282145132Sanholt DRM_INFO(" AGP_CNTL = 0x%08x\n", 283145132Sanholt MACH64_READ(MACH64_AGP_CNTL)); 284145132Sanholt } 285145132Sanholt DRM_INFO(" ALPHA_TST_CNTL = 0x%08x\n", 286145132Sanholt MACH64_READ(MACH64_ALPHA_TST_CNTL)); 287145132Sanholt DRM_INFO("\n"); 288145132Sanholt DRM_INFO(" BM_COMMAND = 0x%08x\n", 289145132Sanholt MACH64_READ(MACH64_BM_COMMAND)); 290145132Sanholt DRM_INFO("BM_FRAME_BUF_OFFSET = 0x%08x\n", 291145132Sanholt MACH64_READ(MACH64_BM_FRAME_BUF_OFFSET)); 292145132Sanholt DRM_INFO(" BM_GUI_TABLE = 0x%08x\n", 293145132Sanholt MACH64_READ(MACH64_BM_GUI_TABLE)); 294145132Sanholt DRM_INFO(" BM_STATUS = 0x%08x\n", 295145132Sanholt MACH64_READ(MACH64_BM_STATUS)); 296145132Sanholt DRM_INFO(" BM_SYSTEM_MEM_ADDR = 0x%08x\n", 297145132Sanholt MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR)); 298145132Sanholt DRM_INFO(" BM_SYSTEM_TABLE = 0x%08x\n", 299145132Sanholt MACH64_READ(MACH64_BM_SYSTEM_TABLE)); 300145132Sanholt DRM_INFO(" BUS_CNTL = 0x%08x\n", 301145132Sanholt MACH64_READ(MACH64_BUS_CNTL)); 302145132Sanholt DRM_INFO("\n"); 303145132Sanholt /* DRM_INFO( " CLOCK_CNTL = 0x%08x\n", MACH64_READ( MACH64_CLOCK_CNTL ) ); */ 304145132Sanholt DRM_INFO(" CLR_CMP_CLR = 0x%08x\n", 305145132Sanholt MACH64_READ(MACH64_CLR_CMP_CLR)); 306145132Sanholt DRM_INFO(" CLR_CMP_CNTL = 0x%08x\n", 307145132Sanholt MACH64_READ(MACH64_CLR_CMP_CNTL)); 308145132Sanholt /* DRM_INFO( " CLR_CMP_MSK = 0x%08x\n", MACH64_READ( MACH64_CLR_CMP_MSK ) ); */ 309145132Sanholt DRM_INFO(" CONFIG_CHIP_ID = 0x%08x\n", 310145132Sanholt MACH64_READ(MACH64_CONFIG_CHIP_ID)); 311145132Sanholt DRM_INFO(" CONFIG_CNTL = 0x%08x\n", 312145132Sanholt MACH64_READ(MACH64_CONFIG_CNTL)); 313145132Sanholt DRM_INFO(" CONFIG_STAT0 = 0x%08x\n", 314145132Sanholt MACH64_READ(MACH64_CONFIG_STAT0)); 315145132Sanholt DRM_INFO(" CONFIG_STAT1 = 0x%08x\n", 316145132Sanholt MACH64_READ(MACH64_CONFIG_STAT1)); 317145132Sanholt DRM_INFO(" CONFIG_STAT2 = 0x%08x\n", 318145132Sanholt MACH64_READ(MACH64_CONFIG_STAT2)); 319145132Sanholt DRM_INFO(" CRC_SIG = 0x%08x\n", MACH64_READ(MACH64_CRC_SIG)); 320145132Sanholt DRM_INFO(" CUSTOM_MACRO_CNTL = 0x%08x\n", 321145132Sanholt MACH64_READ(MACH64_CUSTOM_MACRO_CNTL)); 322145132Sanholt DRM_INFO("\n"); 323145132Sanholt /* DRM_INFO( " DAC_CNTL = 0x%08x\n", MACH64_READ( MACH64_DAC_CNTL ) ); */ 324145132Sanholt /* DRM_INFO( " DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_DAC_REGS ) ); */ 325145132Sanholt DRM_INFO(" DP_BKGD_CLR = 0x%08x\n", 326145132Sanholt MACH64_READ(MACH64_DP_BKGD_CLR)); 327145132Sanholt DRM_INFO(" DP_FRGD_CLR = 0x%08x\n", 328145132Sanholt MACH64_READ(MACH64_DP_FRGD_CLR)); 329145132Sanholt DRM_INFO(" DP_MIX = 0x%08x\n", MACH64_READ(MACH64_DP_MIX)); 330145132Sanholt DRM_INFO(" DP_PIX_WIDTH = 0x%08x\n", 331145132Sanholt MACH64_READ(MACH64_DP_PIX_WIDTH)); 332145132Sanholt DRM_INFO(" DP_SRC = 0x%08x\n", MACH64_READ(MACH64_DP_SRC)); 333145132Sanholt DRM_INFO(" DP_WRITE_MASK = 0x%08x\n", 334145132Sanholt MACH64_READ(MACH64_DP_WRITE_MASK)); 335145132Sanholt DRM_INFO(" DSP_CONFIG = 0x%08x\n", 336145132Sanholt MACH64_READ(MACH64_DSP_CONFIG)); 337145132Sanholt DRM_INFO(" DSP_ON_OFF = 0x%08x\n", 338145132Sanholt MACH64_READ(MACH64_DSP_ON_OFF)); 339145132Sanholt DRM_INFO(" DST_CNTL = 0x%08x\n", 340145132Sanholt MACH64_READ(MACH64_DST_CNTL)); 341145132Sanholt DRM_INFO(" DST_OFF_PITCH = 0x%08x\n", 342145132Sanholt MACH64_READ(MACH64_DST_OFF_PITCH)); 343145132Sanholt DRM_INFO("\n"); 344145132Sanholt /* DRM_INFO( " EXT_DAC_REGS = 0x%08x\n", MACH64_READ( MACH64_EXT_DAC_REGS ) ); */ 345145132Sanholt DRM_INFO(" EXT_MEM_CNTL = 0x%08x\n", 346145132Sanholt MACH64_READ(MACH64_EXT_MEM_CNTL)); 347145132Sanholt DRM_INFO("\n"); 348145132Sanholt DRM_INFO(" FIFO_STAT = 0x%08x\n", 349145132Sanholt MACH64_READ(MACH64_FIFO_STAT)); 350145132Sanholt DRM_INFO("\n"); 351145132Sanholt DRM_INFO(" GEN_TEST_CNTL = 0x%08x\n", 352145132Sanholt MACH64_READ(MACH64_GEN_TEST_CNTL)); 353145132Sanholt /* DRM_INFO( " GP_IO = 0x%08x\n", MACH64_READ( MACH64_GP_IO ) ); */ 354145132Sanholt DRM_INFO(" GUI_CMDFIFO_DATA = 0x%08x\n", 355145132Sanholt MACH64_READ(MACH64_GUI_CMDFIFO_DATA)); 356145132Sanholt DRM_INFO(" GUI_CMDFIFO_DEBUG = 0x%08x\n", 357145132Sanholt MACH64_READ(MACH64_GUI_CMDFIFO_DEBUG)); 358145132Sanholt DRM_INFO(" GUI_CNTL = 0x%08x\n", 359145132Sanholt MACH64_READ(MACH64_GUI_CNTL)); 360145132Sanholt DRM_INFO(" GUI_STAT = 0x%08x\n", 361145132Sanholt MACH64_READ(MACH64_GUI_STAT)); 362145132Sanholt DRM_INFO(" GUI_TRAJ_CNTL = 0x%08x\n", 363145132Sanholt MACH64_READ(MACH64_GUI_TRAJ_CNTL)); 364145132Sanholt DRM_INFO("\n"); 365145132Sanholt DRM_INFO(" HOST_CNTL = 0x%08x\n", 366145132Sanholt MACH64_READ(MACH64_HOST_CNTL)); 367145132Sanholt DRM_INFO(" HW_DEBUG = 0x%08x\n", 368145132Sanholt MACH64_READ(MACH64_HW_DEBUG)); 369145132Sanholt DRM_INFO("\n"); 370145132Sanholt DRM_INFO(" MEM_ADDR_CONFIG = 0x%08x\n", 371145132Sanholt MACH64_READ(MACH64_MEM_ADDR_CONFIG)); 372145132Sanholt DRM_INFO(" MEM_BUF_CNTL = 0x%08x\n", 373145132Sanholt MACH64_READ(MACH64_MEM_BUF_CNTL)); 374145132Sanholt DRM_INFO("\n"); 375145132Sanholt DRM_INFO(" PAT_REG0 = 0x%08x\n", 376145132Sanholt MACH64_READ(MACH64_PAT_REG0)); 377145132Sanholt DRM_INFO(" PAT_REG1 = 0x%08x\n", 378145132Sanholt MACH64_READ(MACH64_PAT_REG1)); 379145132Sanholt DRM_INFO("\n"); 380145132Sanholt DRM_INFO(" SC_LEFT = 0x%08x\n", MACH64_READ(MACH64_SC_LEFT)); 381145132Sanholt DRM_INFO(" SC_RIGHT = 0x%08x\n", 382145132Sanholt MACH64_READ(MACH64_SC_RIGHT)); 383145132Sanholt DRM_INFO(" SC_TOP = 0x%08x\n", MACH64_READ(MACH64_SC_TOP)); 384145132Sanholt DRM_INFO(" SC_BOTTOM = 0x%08x\n", 385145132Sanholt MACH64_READ(MACH64_SC_BOTTOM)); 386145132Sanholt DRM_INFO("\n"); 387145132Sanholt DRM_INFO(" SCALE_3D_CNTL = 0x%08x\n", 388145132Sanholt MACH64_READ(MACH64_SCALE_3D_CNTL)); 389145132Sanholt DRM_INFO(" SCRATCH_REG0 = 0x%08x\n", 390145132Sanholt MACH64_READ(MACH64_SCRATCH_REG0)); 391145132Sanholt DRM_INFO(" SCRATCH_REG1 = 0x%08x\n", 392145132Sanholt MACH64_READ(MACH64_SCRATCH_REG1)); 393145132Sanholt DRM_INFO(" SETUP_CNTL = 0x%08x\n", 394145132Sanholt MACH64_READ(MACH64_SETUP_CNTL)); 395145132Sanholt DRM_INFO(" SRC_CNTL = 0x%08x\n", 396145132Sanholt MACH64_READ(MACH64_SRC_CNTL)); 397145132Sanholt DRM_INFO("\n"); 398145132Sanholt DRM_INFO(" TEX_CNTL = 0x%08x\n", 399145132Sanholt MACH64_READ(MACH64_TEX_CNTL)); 400145132Sanholt DRM_INFO(" TEX_SIZE_PITCH = 0x%08x\n", 401145132Sanholt MACH64_READ(MACH64_TEX_SIZE_PITCH)); 402145132Sanholt DRM_INFO(" TIMER_CONFIG = 0x%08x\n", 403145132Sanholt MACH64_READ(MACH64_TIMER_CONFIG)); 404145132Sanholt DRM_INFO("\n"); 405145132Sanholt DRM_INFO(" Z_CNTL = 0x%08x\n", MACH64_READ(MACH64_Z_CNTL)); 406145132Sanholt DRM_INFO(" Z_OFF_PITCH = 0x%08x\n", 407145132Sanholt MACH64_READ(MACH64_Z_OFF_PITCH)); 408145132Sanholt DRM_INFO("\n"); 409145132Sanholt} 410145132Sanholt 411145132Sanholt#define MACH64_DUMP_CONTEXT 3 412145132Sanholt 413145132Sanholt/** 414145132Sanholt * Used by mach64_dump_ring_info() to dump the contents of the current buffer 415145132Sanholt * pointed by the ring head. 416145132Sanholt */ 417182080Srnolandstatic void mach64_dump_buf_info(drm_mach64_private_t *dev_priv, 418182080Srnoland struct drm_buf *buf) 419145132Sanholt{ 420145132Sanholt u32 addr = GETBUFADDR(buf); 421145132Sanholt u32 used = buf->used >> 2; 422145132Sanholt u32 sys_addr = MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR); 423145132Sanholt u32 *p = GETBUFPTR(buf); 424145132Sanholt int skipped = 0; 425145132Sanholt 426145132Sanholt DRM_INFO("buffer contents:\n"); 427145132Sanholt 428145132Sanholt while (used) { 429145132Sanholt u32 reg, count; 430145132Sanholt 431145132Sanholt reg = le32_to_cpu(*p++); 432145132Sanholt if (addr <= GETBUFADDR(buf) + MACH64_DUMP_CONTEXT * 4 || 433145132Sanholt (addr >= sys_addr - MACH64_DUMP_CONTEXT * 4 && 434145132Sanholt addr <= sys_addr + MACH64_DUMP_CONTEXT * 4) || 435145132Sanholt addr >= 436145132Sanholt GETBUFADDR(buf) + buf->used - MACH64_DUMP_CONTEXT * 4) { 437145132Sanholt DRM_INFO("%08x: 0x%08x\n", addr, reg); 438145132Sanholt } 439145132Sanholt addr += 4; 440145132Sanholt used--; 441145132Sanholt 442145132Sanholt count = (reg >> 16) + 1; 443145132Sanholt reg = reg & 0xffff; 444145132Sanholt reg = MMSELECT(reg); 445145132Sanholt while (count && used) { 446145132Sanholt if (addr <= GETBUFADDR(buf) + MACH64_DUMP_CONTEXT * 4 || 447145132Sanholt (addr >= sys_addr - MACH64_DUMP_CONTEXT * 4 && 448145132Sanholt addr <= sys_addr + MACH64_DUMP_CONTEXT * 4) || 449145132Sanholt addr >= 450145132Sanholt GETBUFADDR(buf) + buf->used - 451145132Sanholt MACH64_DUMP_CONTEXT * 4) { 452145132Sanholt DRM_INFO("%08x: 0x%04x = 0x%08x\n", addr, 453145132Sanholt reg, le32_to_cpu(*p)); 454145132Sanholt skipped = 0; 455145132Sanholt } else { 456145132Sanholt if (!skipped) { 457145132Sanholt DRM_INFO(" ...\n"); 458145132Sanholt skipped = 1; 459145132Sanholt } 460145132Sanholt } 461145132Sanholt p++; 462145132Sanholt addr += 4; 463145132Sanholt used--; 464145132Sanholt 465145132Sanholt reg += 4; 466145132Sanholt count--; 467145132Sanholt } 468145132Sanholt } 469145132Sanholt 470145132Sanholt DRM_INFO("\n"); 471145132Sanholt} 472145132Sanholt 473145132Sanholt/** 474145132Sanholt * Dump the ring state and contents, including the contents of the buffer being 475145132Sanholt * processed by the graphics engine. 476145132Sanholt */ 477182080Srnolandvoid mach64_dump_ring_info(drm_mach64_private_t *dev_priv) 478145132Sanholt{ 479145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 480145132Sanholt int i, skipped; 481145132Sanholt 482145132Sanholt DRM_INFO("\n"); 483145132Sanholt 484145132Sanholt DRM_INFO("ring contents:\n"); 485145132Sanholt DRM_INFO(" head_addr: 0x%08x head: %u tail: %u\n\n", 486145132Sanholt ring->head_addr, ring->head, ring->tail); 487145132Sanholt 488145132Sanholt skipped = 0; 489145132Sanholt for (i = 0; i < ring->size / sizeof(u32); i += 4) { 490145132Sanholt if (i <= MACH64_DUMP_CONTEXT * 4 || 491145132Sanholt i >= ring->size / sizeof(u32) - MACH64_DUMP_CONTEXT * 4 || 492145132Sanholt (i >= ring->tail - MACH64_DUMP_CONTEXT * 4 && 493145132Sanholt i <= ring->tail + MACH64_DUMP_CONTEXT * 4) || 494145132Sanholt (i >= ring->head - MACH64_DUMP_CONTEXT * 4 && 495145132Sanholt i <= ring->head + MACH64_DUMP_CONTEXT * 4)) { 496145132Sanholt DRM_INFO(" 0x%08x: 0x%08x 0x%08x 0x%08x 0x%08x%s%s\n", 497145132Sanholt (u32)(ring->start_addr + i * sizeof(u32)), 498145132Sanholt le32_to_cpu(((u32 *) ring->start)[i + 0]), 499145132Sanholt le32_to_cpu(((u32 *) ring->start)[i + 1]), 500145132Sanholt le32_to_cpu(((u32 *) ring->start)[i + 2]), 501145132Sanholt le32_to_cpu(((u32 *) ring->start)[i + 3]), 502145132Sanholt i == ring->head ? " (head)" : "", 503145132Sanholt i == ring->tail ? " (tail)" : ""); 504145132Sanholt skipped = 0; 505145132Sanholt } else { 506145132Sanholt if (!skipped) { 507145132Sanholt DRM_INFO(" ...\n"); 508145132Sanholt skipped = 1; 509145132Sanholt } 510145132Sanholt } 511145132Sanholt } 512145132Sanholt 513145132Sanholt DRM_INFO("\n"); 514145132Sanholt 515145132Sanholt if (ring->head >= 0 && ring->head < ring->size / sizeof(u32)) { 516145132Sanholt struct list_head *ptr; 517145132Sanholt u32 addr = le32_to_cpu(((u32 *) ring->start)[ring->head + 1]); 518145132Sanholt 519145132Sanholt list_for_each(ptr, &dev_priv->pending) { 520145132Sanholt drm_mach64_freelist_t *entry = 521145132Sanholt list_entry(ptr, drm_mach64_freelist_t, list); 522182080Srnoland struct drm_buf *buf = entry->buf; 523145132Sanholt 524145132Sanholt u32 buf_addr = GETBUFADDR(buf); 525145132Sanholt 526182080Srnoland if (buf_addr <= addr && addr < buf_addr + buf->used) 527145132Sanholt mach64_dump_buf_info(dev_priv, buf); 528145132Sanholt } 529145132Sanholt } 530145132Sanholt 531145132Sanholt DRM_INFO("\n"); 532145132Sanholt DRM_INFO(" BM_GUI_TABLE = 0x%08x\n", 533145132Sanholt MACH64_READ(MACH64_BM_GUI_TABLE)); 534145132Sanholt DRM_INFO("\n"); 535145132Sanholt DRM_INFO("BM_FRAME_BUF_OFFSET = 0x%08x\n", 536145132Sanholt MACH64_READ(MACH64_BM_FRAME_BUF_OFFSET)); 537145132Sanholt DRM_INFO(" BM_SYSTEM_MEM_ADDR = 0x%08x\n", 538145132Sanholt MACH64_READ(MACH64_BM_SYSTEM_MEM_ADDR)); 539145132Sanholt DRM_INFO(" BM_COMMAND = 0x%08x\n", 540145132Sanholt MACH64_READ(MACH64_BM_COMMAND)); 541145132Sanholt DRM_INFO("\n"); 542145132Sanholt DRM_INFO(" BM_STATUS = 0x%08x\n", 543145132Sanholt MACH64_READ(MACH64_BM_STATUS)); 544145132Sanholt DRM_INFO(" BUS_CNTL = 0x%08x\n", 545145132Sanholt MACH64_READ(MACH64_BUS_CNTL)); 546145132Sanholt DRM_INFO(" FIFO_STAT = 0x%08x\n", 547145132Sanholt MACH64_READ(MACH64_FIFO_STAT)); 548145132Sanholt DRM_INFO(" GUI_STAT = 0x%08x\n", 549145132Sanholt MACH64_READ(MACH64_GUI_STAT)); 550145132Sanholt DRM_INFO(" SRC_CNTL = 0x%08x\n", 551145132Sanholt MACH64_READ(MACH64_SRC_CNTL)); 552145132Sanholt} 553145132Sanholt 554145132Sanholt/*@}*/ 555145132Sanholt 556145132Sanholt 557145132Sanholt/*******************************************************************/ 558182080Srnoland/** \name DMA descriptor ring macros */ 559182080Srnoland/*@{*/ 560182080Srnoland 561182080Srnoland/** 562182080Srnoland * Add the end mark to the ring's new tail position. 563182080Srnoland * 564182080Srnoland * The bus master engine will keep processing the DMA buffers listed in the ring 565182080Srnoland * until it finds this mark, making it stop. 566182080Srnoland * 567182080Srnoland * \sa mach64_clear_dma_eol 568182080Srnoland */ 569182080Srnolandstatic __inline__ void mach64_set_dma_eol(volatile u32 *addr) 570182080Srnoland{ 571182080Srnoland#if defined(__i386__) 572182080Srnoland int nr = 31; 573182080Srnoland 574182080Srnoland /* Taken from include/asm-i386/bitops.h linux header */ 575182080Srnoland __asm__ __volatile__("lock;" "btsl %1,%0":"=m"(*addr) 576182080Srnoland :"Ir"(nr)); 577182080Srnoland#elif defined(__powerpc__) 578182080Srnoland u32 old; 579182080Srnoland u32 mask = cpu_to_le32(MACH64_DMA_EOL); 580182080Srnoland 581182080Srnoland /* Taken from the include/asm-ppc/bitops.h linux header */ 582182080Srnoland __asm__ __volatile__("\n\ 583182080Srnoland1: lwarx %0,0,%3 \n\ 584182080Srnoland or %0,%0,%2 \n\ 585182080Srnoland stwcx. %0,0,%3 \n\ 586182080Srnoland bne- 1b":"=&r"(old), "=m"(*addr) 587182080Srnoland :"r"(mask), "r"(addr), "m"(*addr) 588182080Srnoland :"cc"); 589182080Srnoland#elif defined(__alpha__) 590182080Srnoland u32 temp; 591182080Srnoland u32 mask = MACH64_DMA_EOL; 592182080Srnoland 593182080Srnoland /* Taken from the include/asm-alpha/bitops.h linux header */ 594182080Srnoland __asm__ __volatile__("1: ldl_l %0,%3\n" 595182080Srnoland " bis %0,%2,%0\n" 596182080Srnoland " stl_c %0,%1\n" 597182080Srnoland " beq %0,2f\n" 598182080Srnoland ".subsection 2\n" 599182080Srnoland "2: br 1b\n" 600182080Srnoland ".previous":"=&r"(temp), "=m"(*addr) 601182080Srnoland :"Ir"(mask), "m"(*addr)); 602182080Srnoland#else 603182080Srnoland u32 mask = cpu_to_le32(MACH64_DMA_EOL); 604182080Srnoland 605182080Srnoland *addr |= mask; 606182080Srnoland#endif 607182080Srnoland} 608182080Srnoland 609182080Srnoland/** 610182080Srnoland * Remove the end mark from the ring's old tail position. 611182080Srnoland * 612182080Srnoland * It should be called after calling mach64_set_dma_eol to mark the ring's new 613182080Srnoland * tail position. 614182080Srnoland * 615182080Srnoland * We update the end marks while the bus master engine is in operation. Since 616182080Srnoland * the bus master engine may potentially be reading from the same position 617182080Srnoland * that we write, we must change atomically to avoid having intermediary bad 618182080Srnoland * data. 619182080Srnoland */ 620182080Srnolandstatic __inline__ void mach64_clear_dma_eol(volatile u32 *addr) 621182080Srnoland{ 622182080Srnoland#if defined(__i386__) 623182080Srnoland int nr = 31; 624182080Srnoland 625182080Srnoland /* Taken from include/asm-i386/bitops.h linux header */ 626182080Srnoland __asm__ __volatile__("lock;" "btrl %1,%0":"=m"(*addr) 627182080Srnoland :"Ir"(nr)); 628182080Srnoland#elif defined(__powerpc__) 629182080Srnoland u32 old; 630182080Srnoland u32 mask = cpu_to_le32(MACH64_DMA_EOL); 631182080Srnoland 632182080Srnoland /* Taken from the include/asm-ppc/bitops.h linux header */ 633182080Srnoland __asm__ __volatile__("\n\ 634182080Srnoland1: lwarx %0,0,%3 \n\ 635182080Srnoland andc %0,%0,%2 \n\ 636182080Srnoland stwcx. %0,0,%3 \n\ 637182080Srnoland bne- 1b":"=&r"(old), "=m"(*addr) 638182080Srnoland :"r"(mask), "r"(addr), "m"(*addr) 639182080Srnoland :"cc"); 640182080Srnoland#elif defined(__alpha__) 641182080Srnoland u32 temp; 642182080Srnoland u32 mask = ~MACH64_DMA_EOL; 643182080Srnoland 644182080Srnoland /* Taken from the include/asm-alpha/bitops.h linux header */ 645182080Srnoland __asm__ __volatile__("1: ldl_l %0,%3\n" 646182080Srnoland " and %0,%2,%0\n" 647182080Srnoland " stl_c %0,%1\n" 648182080Srnoland " beq %0,2f\n" 649182080Srnoland ".subsection 2\n" 650182080Srnoland "2: br 1b\n" 651182080Srnoland ".previous":"=&r"(temp), "=m"(*addr) 652182080Srnoland :"Ir"(mask), "m"(*addr)); 653182080Srnoland#else 654182080Srnoland u32 mask = cpu_to_le32(~MACH64_DMA_EOL); 655182080Srnoland 656182080Srnoland *addr &= mask; 657182080Srnoland#endif 658182080Srnoland} 659182080Srnoland 660182080Srnoland#define RING_LOCALS \ 661182080Srnoland int _ring_tail, _ring_write; unsigned int _ring_mask; volatile u32 *_ring 662182080Srnoland 663182080Srnoland#define RING_WRITE_OFS _ring_write 664182080Srnoland 665182080Srnoland#define BEGIN_RING(n) \ 666182080Srnoland do { \ 667182080Srnoland if (MACH64_VERBOSE) { \ 668182080Srnoland DRM_INFO( "BEGIN_RING( %d ) \n", \ 669182080Srnoland (n) ); \ 670182080Srnoland } \ 671182080Srnoland if (dev_priv->ring.space <= (n) * sizeof(u32)) { \ 672182080Srnoland int ret; \ 673182080Srnoland if ((ret = mach64_wait_ring( dev_priv, (n) * sizeof(u32))) < 0 ) { \ 674182080Srnoland DRM_ERROR( "wait_ring failed, resetting engine\n"); \ 675182080Srnoland mach64_dump_engine_info( dev_priv ); \ 676182080Srnoland mach64_do_engine_reset( dev_priv ); \ 677182080Srnoland return ret; \ 678182080Srnoland } \ 679182080Srnoland } \ 680182080Srnoland dev_priv->ring.space -= (n) * sizeof(u32); \ 681182080Srnoland _ring = (u32 *) dev_priv->ring.start; \ 682182080Srnoland _ring_tail = _ring_write = dev_priv->ring.tail; \ 683182080Srnoland _ring_mask = dev_priv->ring.tail_mask; \ 684182080Srnoland } while (0) 685182080Srnoland 686182080Srnoland#define OUT_RING( x ) \ 687182080Srnolanddo { \ 688182080Srnoland if (MACH64_VERBOSE) { \ 689182080Srnoland DRM_INFO( " OUT_RING( 0x%08x ) at 0x%x\n", \ 690182080Srnoland (unsigned int)(x), _ring_write ); \ 691182080Srnoland } \ 692182080Srnoland _ring[_ring_write++] = cpu_to_le32( x ); \ 693182080Srnoland _ring_write &= _ring_mask; \ 694182080Srnoland} while (0) 695182080Srnoland 696182080Srnoland#define ADVANCE_RING() \ 697182080Srnolanddo { \ 698182080Srnoland if (MACH64_VERBOSE) { \ 699182080Srnoland DRM_INFO( "ADVANCE_RING() wr=0x%06x tail=0x%06x\n", \ 700182080Srnoland _ring_write, _ring_tail ); \ 701182080Srnoland } \ 702182080Srnoland DRM_MEMORYBARRIER(); \ 703182080Srnoland mach64_clear_dma_eol( &_ring[(_ring_tail - 2) & _ring_mask] ); \ 704182080Srnoland DRM_MEMORYBARRIER(); \ 705182080Srnoland dev_priv->ring.tail = _ring_write; \ 706182080Srnoland mach64_ring_tick( dev_priv, &(dev_priv)->ring ); \ 707182080Srnoland} while (0) 708182080Srnoland 709182080Srnoland/** 710182080Srnoland * Queue a DMA buffer of registers writes into the ring buffer. 711182080Srnoland */ 712182080Srnolandint mach64_add_buf_to_ring(drm_mach64_private_t *dev_priv, 713182080Srnoland drm_mach64_freelist_t *entry) 714182080Srnoland{ 715182080Srnoland int bytes, pages, remainder; 716182080Srnoland u32 address, page; 717182080Srnoland int i; 718182080Srnoland struct drm_buf *buf = entry->buf; 719182080Srnoland RING_LOCALS; 720182080Srnoland 721182080Srnoland bytes = buf->used; 722182080Srnoland address = GETBUFADDR( buf ); 723182080Srnoland pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE; 724182080Srnoland 725182080Srnoland BEGIN_RING( pages * 4 ); 726182080Srnoland 727182080Srnoland for ( i = 0 ; i < pages-1 ; i++ ) { 728182080Srnoland page = address + i * MACH64_DMA_CHUNKSIZE; 729182080Srnoland OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); 730182080Srnoland OUT_RING( page ); 731182080Srnoland OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET ); 732182080Srnoland OUT_RING( 0 ); 733182080Srnoland } 734182080Srnoland 735182080Srnoland /* generate the final descriptor for any remaining commands in this buffer */ 736182080Srnoland page = address + i * MACH64_DMA_CHUNKSIZE; 737182080Srnoland remainder = bytes - i * MACH64_DMA_CHUNKSIZE; 738182080Srnoland 739182080Srnoland /* Save dword offset of last descriptor for this buffer. 740182080Srnoland * This is needed to check for completion of the buffer in freelist_get 741182080Srnoland */ 742182080Srnoland entry->ring_ofs = RING_WRITE_OFS; 743182080Srnoland 744182080Srnoland OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); 745182080Srnoland OUT_RING( page ); 746182080Srnoland OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL ); 747182080Srnoland OUT_RING( 0 ); 748182080Srnoland 749182080Srnoland ADVANCE_RING(); 750182080Srnoland 751182080Srnoland return 0; 752182080Srnoland} 753182080Srnoland 754182080Srnoland/** 755182080Srnoland * Queue DMA buffer controlling host data tranfers (e.g., blit). 756182080Srnoland * 757182080Srnoland * Almost identical to mach64_add_buf_to_ring. 758182080Srnoland */ 759182080Srnolandint mach64_add_hostdata_buf_to_ring(drm_mach64_private_t *dev_priv, 760182080Srnoland drm_mach64_freelist_t *entry) 761182080Srnoland{ 762182080Srnoland int bytes, pages, remainder; 763182080Srnoland u32 address, page; 764182080Srnoland int i; 765182080Srnoland struct drm_buf *buf = entry->buf; 766182080Srnoland RING_LOCALS; 767182080Srnoland 768182080Srnoland bytes = buf->used - MACH64_HOSTDATA_BLIT_OFFSET; 769182080Srnoland pages = (bytes + MACH64_DMA_CHUNKSIZE - 1) / MACH64_DMA_CHUNKSIZE; 770182080Srnoland address = GETBUFADDR( buf ); 771182080Srnoland 772182080Srnoland BEGIN_RING( 4 + pages * 4 ); 773182080Srnoland 774182080Srnoland OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_ADDR ); 775182080Srnoland OUT_RING( address ); 776182080Srnoland OUT_RING( MACH64_HOSTDATA_BLIT_OFFSET | MACH64_DMA_HOLD_OFFSET ); 777182080Srnoland OUT_RING( 0 ); 778182080Srnoland address += MACH64_HOSTDATA_BLIT_OFFSET; 779182080Srnoland 780182080Srnoland for ( i = 0 ; i < pages-1 ; i++ ) { 781182080Srnoland page = address + i * MACH64_DMA_CHUNKSIZE; 782182080Srnoland OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA ); 783182080Srnoland OUT_RING( page ); 784182080Srnoland OUT_RING( MACH64_DMA_CHUNKSIZE | MACH64_DMA_HOLD_OFFSET ); 785182080Srnoland OUT_RING( 0 ); 786182080Srnoland } 787182080Srnoland 788182080Srnoland /* generate the final descriptor for any remaining commands in this buffer */ 789182080Srnoland page = address + i * MACH64_DMA_CHUNKSIZE; 790182080Srnoland remainder = bytes - i * MACH64_DMA_CHUNKSIZE; 791182080Srnoland 792182080Srnoland /* Save dword offset of last descriptor for this buffer. 793182080Srnoland * This is needed to check for completion of the buffer in freelist_get 794182080Srnoland */ 795182080Srnoland entry->ring_ofs = RING_WRITE_OFS; 796182080Srnoland 797182080Srnoland OUT_RING( MACH64_APERTURE_OFFSET + MACH64_BM_HOSTDATA ); 798182080Srnoland OUT_RING( page ); 799182080Srnoland OUT_RING( remainder | MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL ); 800182080Srnoland OUT_RING( 0 ); 801182080Srnoland 802182080Srnoland ADVANCE_RING(); 803182080Srnoland 804182080Srnoland return 0; 805182080Srnoland} 806182080Srnoland 807182080Srnoland/*@}*/ 808182080Srnoland 809182080Srnoland 810182080Srnoland/*******************************************************************/ 811145132Sanholt/** \name DMA test and initialization */ 812145132Sanholt/*@{*/ 813145132Sanholt 814145132Sanholt/** 815145132Sanholt * Perform a simple DMA operation using the pattern registers to test whether 816145132Sanholt * DMA works. 817145132Sanholt * 818145132Sanholt * \return zero if successful. 819145132Sanholt * 820145132Sanholt * \note This function was the testbed for many experiences regarding Mach64 821145132Sanholt * DMA operation. It is left here since it so tricky to get DMA operating 822145132Sanholt * properly in some architectures and hardware. 823145132Sanholt */ 824182080Srnolandstatic int mach64_bm_dma_test(struct drm_device * dev) 825145132Sanholt{ 826145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 827152909Sanholt drm_dma_handle_t *cpu_addr_dmah; 828145132Sanholt u32 data_addr; 829145132Sanholt u32 *table, *data; 830145132Sanholt u32 expected[2]; 831145132Sanholt u32 src_cntl, pat_reg0, pat_reg1; 832145132Sanholt int i, count, failed; 833145132Sanholt 834182080Srnoland DRM_DEBUG("\n"); 835145132Sanholt 836145132Sanholt table = (u32 *) dev_priv->ring.start; 837145132Sanholt 838145132Sanholt /* FIXME: get a dma buffer from the freelist here */ 839145132Sanholt DRM_DEBUG("Allocating data memory ...\n"); 840152909Sanholt cpu_addr_dmah = 841152909Sanholt drm_pci_alloc(dev, 0x1000, 0x1000, 0xfffffffful); 842152909Sanholt if (!cpu_addr_dmah) { 843145132Sanholt DRM_INFO("data-memory allocation failed!\n"); 844182080Srnoland return -ENOMEM; 845145132Sanholt } else { 846152909Sanholt data = (u32 *) cpu_addr_dmah->vaddr; 847152909Sanholt data_addr = (u32) cpu_addr_dmah->busaddr; 848145132Sanholt } 849145132Sanholt 850145132Sanholt /* Save the X server's value for SRC_CNTL and restore it 851145132Sanholt * in case our test fails. This prevents the X server 852145132Sanholt * from disabling it's cache for this register 853145132Sanholt */ 854145132Sanholt src_cntl = MACH64_READ(MACH64_SRC_CNTL); 855145132Sanholt pat_reg0 = MACH64_READ(MACH64_PAT_REG0); 856145132Sanholt pat_reg1 = MACH64_READ(MACH64_PAT_REG1); 857145132Sanholt 858145132Sanholt mach64_do_wait_for_fifo(dev_priv, 3); 859145132Sanholt 860145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, 0); 861145132Sanholt MACH64_WRITE(MACH64_PAT_REG0, 0x11111111); 862145132Sanholt MACH64_WRITE(MACH64_PAT_REG1, 0x11111111); 863145132Sanholt 864145132Sanholt mach64_do_wait_for_idle(dev_priv); 865145132Sanholt 866145132Sanholt for (i = 0; i < 2; i++) { 867145132Sanholt u32 reg; 868145132Sanholt reg = MACH64_READ((MACH64_PAT_REG0 + i * 4)); 869145132Sanholt DRM_DEBUG("(Before DMA Transfer) reg %d = 0x%08x\n", i, reg); 870145132Sanholt if (reg != 0x11111111) { 871145132Sanholt DRM_INFO("Error initializing test registers\n"); 872145132Sanholt DRM_INFO("resetting engine ...\n"); 873145132Sanholt mach64_do_engine_reset(dev_priv); 874145132Sanholt DRM_INFO("freeing data buffer memory.\n"); 875152909Sanholt drm_pci_free(dev, cpu_addr_dmah); 876182080Srnoland return -EIO; 877145132Sanholt } 878145132Sanholt } 879145132Sanholt 880145132Sanholt /* fill up a buffer with sets of 2 consecutive writes starting with PAT_REG0 */ 881145132Sanholt count = 0; 882145132Sanholt 883145132Sanholt data[count++] = cpu_to_le32(DMAREG(MACH64_PAT_REG0) | (1 << 16)); 884145132Sanholt data[count++] = expected[0] = 0x22222222; 885145132Sanholt data[count++] = expected[1] = 0xaaaaaaaa; 886145132Sanholt 887145132Sanholt while (count < 1020) { 888145132Sanholt data[count++] = 889145132Sanholt cpu_to_le32(DMAREG(MACH64_PAT_REG0) | (1 << 16)); 890145132Sanholt data[count++] = 0x22222222; 891145132Sanholt data[count++] = 0xaaaaaaaa; 892145132Sanholt } 893145132Sanholt data[count++] = cpu_to_le32(DMAREG(MACH64_SRC_CNTL) | (0 << 16)); 894145132Sanholt data[count++] = 0; 895145132Sanholt 896145132Sanholt DRM_DEBUG("Preparing table ...\n"); 897145132Sanholt table[MACH64_DMA_FRAME_BUF_OFFSET] = cpu_to_le32(MACH64_BM_ADDR + 898145132Sanholt MACH64_APERTURE_OFFSET); 899145132Sanholt table[MACH64_DMA_SYS_MEM_ADDR] = cpu_to_le32(data_addr); 900145132Sanholt table[MACH64_DMA_COMMAND] = cpu_to_le32(count * sizeof(u32) 901145132Sanholt | MACH64_DMA_HOLD_OFFSET 902145132Sanholt | MACH64_DMA_EOL); 903145132Sanholt table[MACH64_DMA_RESERVED] = 0; 904145132Sanholt 905145132Sanholt DRM_DEBUG("table[0] = 0x%08x\n", table[0]); 906145132Sanholt DRM_DEBUG("table[1] = 0x%08x\n", table[1]); 907145132Sanholt DRM_DEBUG("table[2] = 0x%08x\n", table[2]); 908145132Sanholt DRM_DEBUG("table[3] = 0x%08x\n", table[3]); 909145132Sanholt 910145132Sanholt for (i = 0; i < 6; i++) { 911145132Sanholt DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]); 912145132Sanholt } 913145132Sanholt DRM_DEBUG(" ...\n"); 914145132Sanholt for (i = count - 5; i < count; i++) { 915145132Sanholt DRM_DEBUG(" data[%d] = 0x%08x\n", i, data[i]); 916145132Sanholt } 917145132Sanholt 918145132Sanholt DRM_MEMORYBARRIER(); 919145132Sanholt 920145132Sanholt DRM_DEBUG("waiting for idle...\n"); 921145132Sanholt if ((i = mach64_do_wait_for_idle(dev_priv))) { 922145132Sanholt DRM_INFO("mach64_do_wait_for_idle failed (result=%d)\n", i); 923145132Sanholt DRM_INFO("resetting engine ...\n"); 924145132Sanholt mach64_do_engine_reset(dev_priv); 925145132Sanholt mach64_do_wait_for_fifo(dev_priv, 3); 926145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); 927145132Sanholt MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); 928145132Sanholt MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); 929145132Sanholt DRM_INFO("freeing data buffer memory.\n"); 930152909Sanholt drm_pci_free(dev, cpu_addr_dmah); 931145132Sanholt return i; 932145132Sanholt } 933145132Sanholt DRM_DEBUG("waiting for idle...done\n"); 934145132Sanholt 935145132Sanholt DRM_DEBUG("BUS_CNTL = 0x%08x\n", MACH64_READ(MACH64_BUS_CNTL)); 936145132Sanholt DRM_DEBUG("SRC_CNTL = 0x%08x\n", MACH64_READ(MACH64_SRC_CNTL)); 937145132Sanholt DRM_DEBUG("\n"); 938145132Sanholt DRM_DEBUG("data bus addr = 0x%08x\n", data_addr); 939145132Sanholt DRM_DEBUG("table bus addr = 0x%08x\n", dev_priv->ring.start_addr); 940145132Sanholt 941145132Sanholt DRM_DEBUG("starting DMA transfer...\n"); 942145132Sanholt MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, 943145132Sanholt dev_priv->ring.start_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); 944145132Sanholt 945145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, 946145132Sanholt MACH64_SRC_BM_ENABLE | MACH64_SRC_BM_SYNC | 947145132Sanholt MACH64_SRC_BM_OP_SYSTEM_TO_REG); 948145132Sanholt 949145132Sanholt /* Kick off the transfer */ 950145132Sanholt DRM_DEBUG("starting DMA transfer... done.\n"); 951145132Sanholt MACH64_WRITE(MACH64_DST_HEIGHT_WIDTH, 0); 952145132Sanholt 953145132Sanholt DRM_DEBUG("waiting for idle...\n"); 954145132Sanholt 955145132Sanholt if ((i = mach64_do_wait_for_idle(dev_priv))) { 956145132Sanholt /* engine locked up, dump register state and reset */ 957145132Sanholt DRM_INFO("mach64_do_wait_for_idle failed (result=%d)\n", i); 958145132Sanholt mach64_dump_engine_info(dev_priv); 959145132Sanholt DRM_INFO("resetting engine ...\n"); 960145132Sanholt mach64_do_engine_reset(dev_priv); 961145132Sanholt mach64_do_wait_for_fifo(dev_priv, 3); 962145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); 963145132Sanholt MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); 964145132Sanholt MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); 965145132Sanholt DRM_INFO("freeing data buffer memory.\n"); 966152909Sanholt drm_pci_free(dev, cpu_addr_dmah); 967145132Sanholt return i; 968145132Sanholt } 969145132Sanholt 970145132Sanholt DRM_DEBUG("waiting for idle...done\n"); 971145132Sanholt 972145132Sanholt /* restore SRC_CNTL */ 973145132Sanholt mach64_do_wait_for_fifo(dev_priv, 1); 974145132Sanholt MACH64_WRITE(MACH64_SRC_CNTL, src_cntl); 975145132Sanholt 976145132Sanholt failed = 0; 977145132Sanholt 978145132Sanholt /* Check register values to see if the GUI master operation succeeded */ 979145132Sanholt for (i = 0; i < 2; i++) { 980145132Sanholt u32 reg; 981145132Sanholt reg = MACH64_READ((MACH64_PAT_REG0 + i * 4)); 982145132Sanholt DRM_DEBUG("(After DMA Transfer) reg %d = 0x%08x\n", i, reg); 983145132Sanholt if (reg != expected[i]) { 984145132Sanholt failed = -1; 985145132Sanholt } 986145132Sanholt } 987145132Sanholt 988145132Sanholt /* restore pattern registers */ 989145132Sanholt mach64_do_wait_for_fifo(dev_priv, 2); 990145132Sanholt MACH64_WRITE(MACH64_PAT_REG0, pat_reg0); 991145132Sanholt MACH64_WRITE(MACH64_PAT_REG1, pat_reg1); 992145132Sanholt 993145132Sanholt DRM_DEBUG("freeing data buffer memory.\n"); 994152909Sanholt drm_pci_free(dev, cpu_addr_dmah); 995145132Sanholt DRM_DEBUG("returning ...\n"); 996145132Sanholt 997145132Sanholt return failed; 998145132Sanholt} 999145132Sanholt 1000145132Sanholt/** 1001145132Sanholt * Called during the DMA initialization ioctl to initialize all the necessary 1002145132Sanholt * software and hardware state for DMA operation. 1003145132Sanholt */ 1004182080Srnolandstatic int mach64_do_dma_init(struct drm_device * dev, drm_mach64_init_t * init) 1005145132Sanholt{ 1006145132Sanholt drm_mach64_private_t *dev_priv; 1007145132Sanholt u32 tmp; 1008145132Sanholt int i, ret; 1009145132Sanholt 1010182080Srnoland DRM_DEBUG("\n"); 1011145132Sanholt 1012145132Sanholt dev_priv = drm_alloc(sizeof(drm_mach64_private_t), DRM_MEM_DRIVER); 1013145132Sanholt if (dev_priv == NULL) 1014182080Srnoland return -ENOMEM; 1015145132Sanholt 1016145132Sanholt memset(dev_priv, 0, sizeof(drm_mach64_private_t)); 1017145132Sanholt 1018145132Sanholt dev_priv->is_pci = init->is_pci; 1019145132Sanholt 1020145132Sanholt dev_priv->fb_bpp = init->fb_bpp; 1021145132Sanholt dev_priv->front_offset = init->front_offset; 1022145132Sanholt dev_priv->front_pitch = init->front_pitch; 1023145132Sanholt dev_priv->back_offset = init->back_offset; 1024145132Sanholt dev_priv->back_pitch = init->back_pitch; 1025145132Sanholt 1026145132Sanholt dev_priv->depth_bpp = init->depth_bpp; 1027145132Sanholt dev_priv->depth_offset = init->depth_offset; 1028145132Sanholt dev_priv->depth_pitch = init->depth_pitch; 1029145132Sanholt 1030145132Sanholt dev_priv->front_offset_pitch = (((dev_priv->front_pitch / 8) << 22) | 1031145132Sanholt (dev_priv->front_offset >> 3)); 1032145132Sanholt dev_priv->back_offset_pitch = (((dev_priv->back_pitch / 8) << 22) | 1033145132Sanholt (dev_priv->back_offset >> 3)); 1034145132Sanholt dev_priv->depth_offset_pitch = (((dev_priv->depth_pitch / 8) << 22) | 1035145132Sanholt (dev_priv->depth_offset >> 3)); 1036145132Sanholt 1037145132Sanholt dev_priv->usec_timeout = 1000000; 1038145132Sanholt 1039145132Sanholt /* Set up the freelist, placeholder list and pending list */ 1040145132Sanholt INIT_LIST_HEAD(&dev_priv->free_list); 1041145132Sanholt INIT_LIST_HEAD(&dev_priv->placeholders); 1042145132Sanholt INIT_LIST_HEAD(&dev_priv->pending); 1043145132Sanholt 1044182080Srnoland dev_priv->sarea = drm_getsarea(dev); 1045145132Sanholt if (!dev_priv->sarea) { 1046145132Sanholt DRM_ERROR("can not find sarea!\n"); 1047145132Sanholt dev->dev_private = (void *)dev_priv; 1048145132Sanholt mach64_do_cleanup_dma(dev); 1049182080Srnoland return -EINVAL; 1050145132Sanholt } 1051145132Sanholt dev_priv->fb = drm_core_findmap(dev, init->fb_offset); 1052145132Sanholt if (!dev_priv->fb) { 1053145132Sanholt DRM_ERROR("can not find frame buffer map!\n"); 1054145132Sanholt dev->dev_private = (void *)dev_priv; 1055145132Sanholt mach64_do_cleanup_dma(dev); 1056182080Srnoland return -EINVAL; 1057145132Sanholt } 1058145132Sanholt dev_priv->mmio = drm_core_findmap(dev, init->mmio_offset); 1059145132Sanholt if (!dev_priv->mmio) { 1060145132Sanholt DRM_ERROR("can not find mmio map!\n"); 1061145132Sanholt dev->dev_private = (void *)dev_priv; 1062145132Sanholt mach64_do_cleanup_dma(dev); 1063182080Srnoland return -EINVAL; 1064145132Sanholt } 1065145132Sanholt 1066182080Srnoland dev_priv->ring_map = drm_core_findmap(dev, init->ring_offset); 1067182080Srnoland if (!dev_priv->ring_map) { 1068182080Srnoland DRM_ERROR("can not find ring map!\n"); 1069182080Srnoland dev->dev_private = (void *)dev_priv; 1070182080Srnoland mach64_do_cleanup_dma(dev); 1071182080Srnoland return -EINVAL; 1072182080Srnoland } 1073182080Srnoland 1074145132Sanholt dev_priv->sarea_priv = (drm_mach64_sarea_t *) 1075145132Sanholt ((u8 *) dev_priv->sarea->handle + init->sarea_priv_offset); 1076145132Sanholt 1077145132Sanholt if (!dev_priv->is_pci) { 1078145132Sanholt drm_core_ioremap(dev_priv->ring_map, dev); 1079145132Sanholt if (!dev_priv->ring_map->handle) { 1080145132Sanholt DRM_ERROR("can not ioremap virtual address for" 1081145132Sanholt " descriptor ring\n"); 1082145132Sanholt dev->dev_private = (void *)dev_priv; 1083145132Sanholt mach64_do_cleanup_dma(dev); 1084182080Srnoland return -ENOMEM; 1085145132Sanholt } 1086182080Srnoland dev->agp_buffer_token = init->buffers_offset; 1087145132Sanholt dev->agp_buffer_map = 1088145132Sanholt drm_core_findmap(dev, init->buffers_offset); 1089145132Sanholt if (!dev->agp_buffer_map) { 1090145132Sanholt DRM_ERROR("can not find dma buffer map!\n"); 1091145132Sanholt dev->dev_private = (void *)dev_priv; 1092145132Sanholt mach64_do_cleanup_dma(dev); 1093182080Srnoland return -EINVAL; 1094145132Sanholt } 1095145132Sanholt /* there might be a nicer way to do this - 1096145132Sanholt dev isn't passed all the way though the mach64 - DA */ 1097145132Sanholt dev_priv->dev_buffers = dev->agp_buffer_map; 1098145132Sanholt 1099145132Sanholt drm_core_ioremap(dev->agp_buffer_map, dev); 1100145132Sanholt if (!dev->agp_buffer_map->handle) { 1101145132Sanholt DRM_ERROR("can not ioremap virtual address for" 1102145132Sanholt " dma buffer\n"); 1103145132Sanholt dev->dev_private = (void *)dev_priv; 1104145132Sanholt mach64_do_cleanup_dma(dev); 1105182080Srnoland return -ENOMEM; 1106145132Sanholt } 1107145132Sanholt dev_priv->agp_textures = 1108145132Sanholt drm_core_findmap(dev, init->agp_textures_offset); 1109145132Sanholt if (!dev_priv->agp_textures) { 1110145132Sanholt DRM_ERROR("can not find agp texture region!\n"); 1111145132Sanholt dev->dev_private = (void *)dev_priv; 1112145132Sanholt mach64_do_cleanup_dma(dev); 1113182080Srnoland return -EINVAL; 1114145132Sanholt } 1115145132Sanholt } 1116145132Sanholt 1117145132Sanholt dev->dev_private = (void *)dev_priv; 1118145132Sanholt 1119145132Sanholt dev_priv->driver_mode = init->dma_mode; 1120145132Sanholt 1121145132Sanholt /* changing the FIFO size from the default causes problems with DMA */ 1122145132Sanholt tmp = MACH64_READ(MACH64_GUI_CNTL); 1123145132Sanholt if ((tmp & MACH64_CMDFIFO_SIZE_MASK) != MACH64_CMDFIFO_SIZE_128) { 1124145132Sanholt DRM_INFO("Setting FIFO size to 128 entries\n"); 1125145132Sanholt /* FIFO must be empty to change the FIFO depth */ 1126145132Sanholt if ((ret = mach64_do_wait_for_idle(dev_priv))) { 1127145132Sanholt DRM_ERROR 1128145132Sanholt ("wait for idle failed before changing FIFO depth!\n"); 1129145132Sanholt mach64_do_cleanup_dma(dev); 1130145132Sanholt return ret; 1131145132Sanholt } 1132145132Sanholt MACH64_WRITE(MACH64_GUI_CNTL, ((tmp & ~MACH64_CMDFIFO_SIZE_MASK) 1133145132Sanholt | MACH64_CMDFIFO_SIZE_128)); 1134145132Sanholt /* need to read GUI_STAT for proper sync according to docs */ 1135145132Sanholt if ((ret = mach64_do_wait_for_idle(dev_priv))) { 1136145132Sanholt DRM_ERROR 1137145132Sanholt ("wait for idle failed when changing FIFO depth!\n"); 1138145132Sanholt mach64_do_cleanup_dma(dev); 1139145132Sanholt return ret; 1140145132Sanholt } 1141145132Sanholt } 1142145132Sanholt 1143145132Sanholt dev_priv->ring.size = 0x4000; /* 16KB */ 1144182080Srnoland dev_priv->ring.start = dev_priv->ring_map->handle; 1145182080Srnoland dev_priv->ring.start_addr = (u32) dev_priv->ring_map->offset; 1146145132Sanholt 1147145132Sanholt memset(dev_priv->ring.start, 0, dev_priv->ring.size); 1148145132Sanholt DRM_INFO("descriptor ring: cpu addr %p, bus addr: 0x%08x\n", 1149145132Sanholt dev_priv->ring.start, dev_priv->ring.start_addr); 1150145132Sanholt 1151145132Sanholt ret = 0; 1152145132Sanholt if (dev_priv->driver_mode != MACH64_MODE_MMIO) { 1153145132Sanholt 1154145132Sanholt /* enable block 1 registers and bus mastering */ 1155145132Sanholt MACH64_WRITE(MACH64_BUS_CNTL, ((MACH64_READ(MACH64_BUS_CNTL) 1156145132Sanholt | MACH64_BUS_EXT_REG_EN) 1157145132Sanholt & ~MACH64_BUS_MASTER_DIS)); 1158145132Sanholt 1159145132Sanholt /* try a DMA GUI-mastering pass and fall back to MMIO if it fails */ 1160145132Sanholt DRM_DEBUG("Starting DMA test...\n"); 1161145132Sanholt if ((ret = mach64_bm_dma_test(dev))) { 1162145132Sanholt dev_priv->driver_mode = MACH64_MODE_MMIO; 1163145132Sanholt } 1164145132Sanholt } 1165145132Sanholt 1166145132Sanholt switch (dev_priv->driver_mode) { 1167145132Sanholt case MACH64_MODE_MMIO: 1168145132Sanholt MACH64_WRITE(MACH64_BUS_CNTL, (MACH64_READ(MACH64_BUS_CNTL) 1169145132Sanholt | MACH64_BUS_EXT_REG_EN 1170145132Sanholt | MACH64_BUS_MASTER_DIS)); 1171145132Sanholt if (init->dma_mode == MACH64_MODE_MMIO) 1172145132Sanholt DRM_INFO("Forcing pseudo-DMA mode\n"); 1173145132Sanholt else 1174145132Sanholt DRM_INFO 1175145132Sanholt ("DMA test failed (ret=%d), using pseudo-DMA mode\n", 1176145132Sanholt ret); 1177145132Sanholt break; 1178145132Sanholt case MACH64_MODE_DMA_SYNC: 1179145132Sanholt DRM_INFO("DMA test succeeded, using synchronous DMA mode\n"); 1180145132Sanholt break; 1181145132Sanholt case MACH64_MODE_DMA_ASYNC: 1182145132Sanholt default: 1183145132Sanholt DRM_INFO("DMA test succeeded, using asynchronous DMA mode\n"); 1184145132Sanholt } 1185145132Sanholt 1186145132Sanholt dev_priv->ring_running = 0; 1187145132Sanholt 1188145132Sanholt /* setup offsets for physical address of table start and end */ 1189145132Sanholt dev_priv->ring.head_addr = dev_priv->ring.start_addr; 1190145132Sanholt dev_priv->ring.head = dev_priv->ring.tail = 0; 1191145132Sanholt dev_priv->ring.tail_mask = (dev_priv->ring.size / sizeof(u32)) - 1; 1192145132Sanholt dev_priv->ring.space = dev_priv->ring.size; 1193145132Sanholt 1194145132Sanholt /* setup physical address and size of descriptor table */ 1195145132Sanholt mach64_do_wait_for_fifo(dev_priv, 1); 1196145132Sanholt MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, 1197145132Sanholt (dev_priv->ring. 1198145132Sanholt head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB)); 1199145132Sanholt 1200145132Sanholt /* init frame counter */ 1201145132Sanholt dev_priv->sarea_priv->frames_queued = 0; 1202145132Sanholt for (i = 0; i < MACH64_MAX_QUEUED_FRAMES; i++) { 1203145132Sanholt dev_priv->frame_ofs[i] = ~0; /* All ones indicates placeholder */ 1204145132Sanholt } 1205145132Sanholt 1206145132Sanholt /* Allocate the DMA buffer freelist */ 1207145132Sanholt if ((ret = mach64_init_freelist(dev))) { 1208145132Sanholt DRM_ERROR("Freelist allocation failed\n"); 1209145132Sanholt mach64_do_cleanup_dma(dev); 1210145132Sanholt return ret; 1211145132Sanholt } 1212145132Sanholt 1213145132Sanholt return 0; 1214145132Sanholt} 1215145132Sanholt 1216145132Sanholt/*******************************************************************/ 1217145132Sanholt/** MMIO Pseudo-DMA (intended primarily for debugging, not performance) 1218145132Sanholt */ 1219145132Sanholt 1220182080Srnolandint mach64_do_dispatch_pseudo_dma(drm_mach64_private_t *dev_priv) 1221145132Sanholt{ 1222145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 1223145132Sanholt volatile u32 *ring_read; 1224145132Sanholt struct list_head *ptr; 1225145132Sanholt drm_mach64_freelist_t *entry; 1226182080Srnoland struct drm_buf *buf = NULL; 1227145132Sanholt u32 *buf_ptr; 1228145132Sanholt u32 used, reg, target; 1229145132Sanholt int fifo, count, found, ret, no_idle_wait; 1230145132Sanholt 1231145132Sanholt fifo = count = reg = no_idle_wait = 0; 1232145132Sanholt target = MACH64_BM_ADDR; 1233145132Sanholt 1234145132Sanholt if ((ret = mach64_do_wait_for_idle(dev_priv)) < 0) { 1235182080Srnoland DRM_INFO("idle failed before pseudo-dma dispatch, resetting engine\n"); 1236145132Sanholt mach64_dump_engine_info(dev_priv); 1237145132Sanholt mach64_do_engine_reset(dev_priv); 1238145132Sanholt return ret; 1239145132Sanholt } 1240145132Sanholt 1241145132Sanholt ring_read = (u32 *) ring->start; 1242145132Sanholt 1243145132Sanholt while (ring->tail != ring->head) { 1244145132Sanholt u32 buf_addr, new_target, offset; 1245145132Sanholt u32 bytes, remaining, head, eol; 1246145132Sanholt 1247145132Sanholt head = ring->head; 1248145132Sanholt 1249145132Sanholt new_target = 1250145132Sanholt le32_to_cpu(ring_read[head++]) - MACH64_APERTURE_OFFSET; 1251145132Sanholt buf_addr = le32_to_cpu(ring_read[head++]); 1252145132Sanholt eol = le32_to_cpu(ring_read[head]) & MACH64_DMA_EOL; 1253145132Sanholt bytes = le32_to_cpu(ring_read[head++]) 1254145132Sanholt & ~(MACH64_DMA_HOLD_OFFSET | MACH64_DMA_EOL); 1255145132Sanholt head++; 1256145132Sanholt head &= ring->tail_mask; 1257145132Sanholt 1258145132Sanholt /* can't wait for idle between a blit setup descriptor 1259145132Sanholt * and a HOSTDATA descriptor or the engine will lock 1260145132Sanholt */ 1261145132Sanholt if (new_target == MACH64_BM_HOSTDATA 1262145132Sanholt && target == MACH64_BM_ADDR) 1263145132Sanholt no_idle_wait = 1; 1264145132Sanholt 1265145132Sanholt target = new_target; 1266145132Sanholt 1267145132Sanholt found = 0; 1268145132Sanholt offset = 0; 1269145132Sanholt list_for_each(ptr, &dev_priv->pending) { 1270145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1271145132Sanholt buf = entry->buf; 1272145132Sanholt offset = buf_addr - GETBUFADDR(buf); 1273145132Sanholt if (offset >= 0 && offset < MACH64_BUFFER_SIZE) { 1274145132Sanholt found = 1; 1275145132Sanholt break; 1276145132Sanholt } 1277145132Sanholt } 1278145132Sanholt 1279145132Sanholt if (!found || buf == NULL) { 1280145132Sanholt DRM_ERROR 1281145132Sanholt ("Couldn't find pending buffer: head: %u tail: %u buf_addr: 0x%08x %s\n", 1282145132Sanholt head, ring->tail, buf_addr, (eol ? "eol" : "")); 1283145132Sanholt mach64_dump_ring_info(dev_priv); 1284145132Sanholt mach64_do_engine_reset(dev_priv); 1285182080Srnoland return -EINVAL; 1286145132Sanholt } 1287145132Sanholt 1288145132Sanholt /* Hand feed the buffer to the card via MMIO, waiting for the fifo 1289145132Sanholt * every 16 writes 1290145132Sanholt */ 1291145132Sanholt DRM_DEBUG("target: (0x%08x) %s\n", target, 1292145132Sanholt (target == 1293145132Sanholt MACH64_BM_HOSTDATA ? "BM_HOSTDATA" : "BM_ADDR")); 1294145132Sanholt DRM_DEBUG("offset: %u bytes: %u used: %u\n", offset, bytes, 1295145132Sanholt buf->used); 1296145132Sanholt 1297145132Sanholt remaining = (buf->used - offset) >> 2; /* dwords remaining in buffer */ 1298145132Sanholt used = bytes >> 2; /* dwords in buffer for this descriptor */ 1299145132Sanholt buf_ptr = (u32 *) ((char *)GETBUFPTR(buf) + offset); 1300145132Sanholt 1301145132Sanholt while (used) { 1302145132Sanholt 1303145132Sanholt if (count == 0) { 1304145132Sanholt if (target == MACH64_BM_HOSTDATA) { 1305145132Sanholt reg = DMAREG(MACH64_HOST_DATA0); 1306145132Sanholt count = 1307145132Sanholt (remaining > 16) ? 16 : remaining; 1308145132Sanholt fifo = 0; 1309145132Sanholt } else { 1310145132Sanholt reg = le32_to_cpu(*buf_ptr++); 1311145132Sanholt used--; 1312145132Sanholt count = (reg >> 16) + 1; 1313145132Sanholt } 1314145132Sanholt 1315145132Sanholt reg = reg & 0xffff; 1316145132Sanholt reg = MMSELECT(reg); 1317145132Sanholt } 1318145132Sanholt while (count && used) { 1319145132Sanholt if (!fifo) { 1320145132Sanholt if (no_idle_wait) { 1321145132Sanholt if ((ret = 1322145132Sanholt mach64_do_wait_for_fifo 1323145132Sanholt (dev_priv, 16)) < 0) { 1324145132Sanholt no_idle_wait = 0; 1325145132Sanholt return ret; 1326145132Sanholt } 1327145132Sanholt } else { 1328145132Sanholt if ((ret = 1329145132Sanholt mach64_do_wait_for_idle 1330145132Sanholt (dev_priv)) < 0) { 1331145132Sanholt return ret; 1332145132Sanholt } 1333145132Sanholt } 1334145132Sanholt fifo = 16; 1335145132Sanholt } 1336145132Sanholt --fifo; 1337145132Sanholt MACH64_WRITE(reg, le32_to_cpu(*buf_ptr++)); 1338145132Sanholt used--; 1339145132Sanholt remaining--; 1340145132Sanholt 1341145132Sanholt reg += 4; 1342145132Sanholt count--; 1343145132Sanholt } 1344145132Sanholt } 1345145132Sanholt ring->head = head; 1346145132Sanholt ring->head_addr = ring->start_addr + (ring->head * sizeof(u32)); 1347145132Sanholt ring->space += (4 * sizeof(u32)); 1348145132Sanholt } 1349145132Sanholt 1350145132Sanholt if ((ret = mach64_do_wait_for_idle(dev_priv)) < 0) { 1351145132Sanholt return ret; 1352145132Sanholt } 1353145132Sanholt MACH64_WRITE(MACH64_BM_GUI_TABLE_CMD, 1354145132Sanholt ring->head_addr | MACH64_CIRCULAR_BUF_SIZE_16KB); 1355145132Sanholt 1356182080Srnoland DRM_DEBUG("completed\n"); 1357145132Sanholt return 0; 1358145132Sanholt} 1359145132Sanholt 1360145132Sanholt/*@}*/ 1361145132Sanholt 1362145132Sanholt 1363145132Sanholt/*******************************************************************/ 1364145132Sanholt/** \name DMA cleanup */ 1365145132Sanholt/*@{*/ 1366145132Sanholt 1367182080Srnolandint mach64_do_cleanup_dma(struct drm_device * dev) 1368145132Sanholt{ 1369182080Srnoland DRM_DEBUG("\n"); 1370145132Sanholt 1371145132Sanholt /* Make sure interrupts are disabled here because the uninstall ioctl 1372145132Sanholt * may not have been called from userspace and after dev_private 1373145132Sanholt * is freed, it's too late. 1374145132Sanholt */ 1375145132Sanholt if (dev->irq) 1376145132Sanholt drm_irq_uninstall(dev); 1377145132Sanholt 1378145132Sanholt if (dev->dev_private) { 1379145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1380145132Sanholt 1381182080Srnoland if (!dev_priv->is_pci) { 1382145132Sanholt if (dev_priv->ring_map) 1383145132Sanholt drm_core_ioremapfree(dev_priv->ring_map, dev); 1384145132Sanholt 1385182080Srnoland if (dev->agp_buffer_map) { 1386182080Srnoland drm_core_ioremapfree(dev->agp_buffer_map, dev); 1387182080Srnoland dev->agp_buffer_map = NULL; 1388182080Srnoland } 1389145132Sanholt } 1390145132Sanholt 1391145132Sanholt mach64_destroy_freelist(dev); 1392145132Sanholt 1393145132Sanholt drm_free(dev_priv, sizeof(drm_mach64_private_t), 1394145132Sanholt DRM_MEM_DRIVER); 1395145132Sanholt dev->dev_private = NULL; 1396145132Sanholt } 1397145132Sanholt 1398145132Sanholt return 0; 1399145132Sanholt} 1400145132Sanholt 1401145132Sanholt/*@}*/ 1402145132Sanholt 1403145132Sanholt 1404145132Sanholt/*******************************************************************/ 1405145132Sanholt/** \name IOCTL handlers */ 1406145132Sanholt/*@{*/ 1407145132Sanholt 1408182080Srnolandint mach64_dma_init(struct drm_device *dev, void *data, 1409182080Srnoland struct drm_file *file_priv) 1410145132Sanholt{ 1411182080Srnoland drm_mach64_init_t *init = data; 1412145132Sanholt 1413182080Srnoland DRM_DEBUG("\n"); 1414145132Sanholt 1415182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 1416145132Sanholt 1417182080Srnoland switch (init->func) { 1418145132Sanholt case DRM_MACH64_INIT_DMA: 1419182080Srnoland return mach64_do_dma_init(dev, init); 1420145132Sanholt case DRM_MACH64_CLEANUP_DMA: 1421145132Sanholt return mach64_do_cleanup_dma(dev); 1422145132Sanholt } 1423145132Sanholt 1424182080Srnoland return -EINVAL; 1425145132Sanholt} 1426145132Sanholt 1427182080Srnolandint mach64_dma_idle(struct drm_device *dev, void *data, 1428182080Srnoland struct drm_file *file_priv) 1429145132Sanholt{ 1430145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1431145132Sanholt 1432182080Srnoland DRM_DEBUG("\n"); 1433145132Sanholt 1434182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 1435145132Sanholt 1436145132Sanholt return mach64_do_dma_idle(dev_priv); 1437145132Sanholt} 1438145132Sanholt 1439182080Srnolandint mach64_dma_flush(struct drm_device *dev, void *data, 1440182080Srnoland struct drm_file *file_priv) 1441145132Sanholt{ 1442145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1443145132Sanholt 1444182080Srnoland DRM_DEBUG("\n"); 1445145132Sanholt 1446182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 1447145132Sanholt 1448145132Sanholt return mach64_do_dma_flush(dev_priv); 1449145132Sanholt} 1450145132Sanholt 1451182080Srnolandint mach64_engine_reset(struct drm_device *dev, void *data, 1452182080Srnoland struct drm_file *file_priv) 1453145132Sanholt{ 1454145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1455145132Sanholt 1456182080Srnoland DRM_DEBUG("\n"); 1457145132Sanholt 1458182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 1459145132Sanholt 1460145132Sanholt return mach64_do_engine_reset(dev_priv); 1461145132Sanholt} 1462145132Sanholt 1463145132Sanholt/*@}*/ 1464145132Sanholt 1465145132Sanholt 1466145132Sanholt/*******************************************************************/ 1467145132Sanholt/** \name Freelist management */ 1468145132Sanholt/*@{*/ 1469145132Sanholt 1470182080Srnolandint mach64_init_freelist(struct drm_device * dev) 1471145132Sanholt{ 1472182080Srnoland struct drm_device_dma *dma = dev->dma; 1473145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1474145132Sanholt drm_mach64_freelist_t *entry; 1475145132Sanholt struct list_head *ptr; 1476145132Sanholt int i; 1477145132Sanholt 1478182080Srnoland DRM_DEBUG("adding %d buffers to freelist\n", dma->buf_count); 1479145132Sanholt 1480145132Sanholt for (i = 0; i < dma->buf_count; i++) { 1481145132Sanholt if ((entry = 1482145132Sanholt (drm_mach64_freelist_t *) 1483145132Sanholt drm_alloc(sizeof(drm_mach64_freelist_t), 1484145132Sanholt DRM_MEM_BUFLISTS)) == NULL) 1485182080Srnoland return -ENOMEM; 1486145132Sanholt memset(entry, 0, sizeof(drm_mach64_freelist_t)); 1487145132Sanholt entry->buf = dma->buflist[i]; 1488145132Sanholt ptr = &entry->list; 1489145132Sanholt list_add_tail(ptr, &dev_priv->free_list); 1490145132Sanholt } 1491145132Sanholt 1492145132Sanholt return 0; 1493145132Sanholt} 1494145132Sanholt 1495182080Srnolandvoid mach64_destroy_freelist(struct drm_device * dev) 1496145132Sanholt{ 1497145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1498145132Sanholt drm_mach64_freelist_t *entry; 1499145132Sanholt struct list_head *ptr; 1500145132Sanholt struct list_head *tmp; 1501145132Sanholt 1502182080Srnoland DRM_DEBUG("\n"); 1503145132Sanholt 1504145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->pending) { 1505145132Sanholt list_del(ptr); 1506145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1507145132Sanholt drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); 1508145132Sanholt } 1509145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->placeholders) { 1510145132Sanholt list_del(ptr); 1511145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1512145132Sanholt drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); 1513145132Sanholt } 1514145132Sanholt 1515145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->free_list) { 1516145132Sanholt list_del(ptr); 1517145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1518145132Sanholt drm_free(entry, sizeof(*entry), DRM_MEM_BUFLISTS); 1519145132Sanholt } 1520145132Sanholt} 1521145132Sanholt 1522145132Sanholt/* IMPORTANT: This function should only be called when the engine is idle or locked up, 1523145132Sanholt * as it assumes all buffers in the pending list have been completed by the hardware. 1524145132Sanholt */ 1525182080Srnolandint mach64_do_release_used_buffers(drm_mach64_private_t *dev_priv) 1526145132Sanholt{ 1527145132Sanholt struct list_head *ptr; 1528145132Sanholt struct list_head *tmp; 1529145132Sanholt drm_mach64_freelist_t *entry; 1530145132Sanholt int i; 1531145132Sanholt 1532145132Sanholt if (list_empty(&dev_priv->pending)) 1533145132Sanholt return 0; 1534145132Sanholt 1535145132Sanholt /* Iterate the pending list and move all buffers into the freelist... */ 1536145132Sanholt i = 0; 1537145132Sanholt list_for_each_safe(ptr, tmp, &dev_priv->pending) { 1538145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1539145132Sanholt if (entry->discard) { 1540145132Sanholt entry->buf->pending = 0; 1541145132Sanholt list_del(ptr); 1542145132Sanholt list_add_tail(ptr, &dev_priv->free_list); 1543145132Sanholt i++; 1544145132Sanholt } 1545145132Sanholt } 1546145132Sanholt 1547182080Srnoland DRM_DEBUG("released %d buffers from pending list\n", i); 1548145132Sanholt 1549145132Sanholt return 0; 1550145132Sanholt} 1551145132Sanholt 1552182080Srnolandstatic int mach64_do_reclaim_completed(drm_mach64_private_t *dev_priv) 1553145132Sanholt{ 1554145132Sanholt drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 1555182080Srnoland struct list_head *ptr; 1556182080Srnoland struct list_head *tmp; 1557145132Sanholt drm_mach64_freelist_t *entry; 1558182080Srnoland u32 head, tail, ofs; 1559182080Srnoland 1560182080Srnoland mach64_ring_tick(dev_priv, ring); 1561182080Srnoland head = ring->head; 1562182080Srnoland tail = ring->tail; 1563182080Srnoland 1564182080Srnoland if (head == tail) { 1565182080Srnoland#if MACH64_EXTRA_CHECKING 1566182080Srnoland if (MACH64_READ(MACH64_GUI_STAT) & MACH64_GUI_ACTIVE) { 1567182080Srnoland DRM_ERROR("Empty ring with non-idle engine!\n"); 1568182080Srnoland mach64_dump_ring_info(dev_priv); 1569182080Srnoland return -1; 1570182080Srnoland } 1571182080Srnoland#endif 1572182080Srnoland /* last pass is complete, so release everything */ 1573182080Srnoland mach64_do_release_used_buffers(dev_priv); 1574182080Srnoland DRM_DEBUG("idle engine, freed all buffers.\n"); 1575182080Srnoland if (list_empty(&dev_priv->free_list)) { 1576182080Srnoland DRM_ERROR("Freelist empty with idle engine\n"); 1577182080Srnoland return -1; 1578182080Srnoland } 1579182080Srnoland return 0; 1580182080Srnoland } 1581182080Srnoland /* Look for a completed buffer and bail out of the loop 1582182080Srnoland * as soon as we find one -- don't waste time trying 1583182080Srnoland * to free extra bufs here, leave that to do_release_used_buffers 1584182080Srnoland */ 1585182080Srnoland list_for_each_safe(ptr, tmp, &dev_priv->pending) { 1586182080Srnoland entry = list_entry(ptr, drm_mach64_freelist_t, list); 1587182080Srnoland ofs = entry->ring_ofs; 1588182080Srnoland if (entry->discard && 1589182080Srnoland ((head < tail && (ofs < head || ofs >= tail)) || 1590182080Srnoland (head > tail && (ofs < head && ofs >= tail)))) { 1591182080Srnoland#if MACH64_EXTRA_CHECKING 1592182080Srnoland int i; 1593182080Srnoland 1594182080Srnoland for (i = head; i != tail; i = (i + 4) & ring->tail_mask) 1595182080Srnoland { 1596182080Srnoland u32 o1 = le32_to_cpu(((u32 *) ring-> 1597182080Srnoland start)[i + 1]); 1598182080Srnoland u32 o2 = GETBUFADDR(entry->buf); 1599182080Srnoland 1600182080Srnoland if (o1 == o2) { 1601182080Srnoland DRM_ERROR 1602182080Srnoland ("Attempting to free used buffer: " 1603182080Srnoland "i=%d buf=0x%08x\n", 1604182080Srnoland i, o1); 1605182080Srnoland mach64_dump_ring_info(dev_priv); 1606182080Srnoland return -1; 1607182080Srnoland } 1608182080Srnoland } 1609182080Srnoland#endif 1610182080Srnoland /* found a processed buffer */ 1611182080Srnoland entry->buf->pending = 0; 1612182080Srnoland list_del(ptr); 1613182080Srnoland list_add_tail(ptr, &dev_priv->free_list); 1614182080Srnoland DRM_DEBUG 1615182080Srnoland ("freed processed buffer (head=%d tail=%d " 1616182080Srnoland "buf ring ofs=%d).\n", 1617182080Srnoland head, tail, ofs); 1618182080Srnoland return 0; 1619182080Srnoland } 1620182080Srnoland } 1621182080Srnoland 1622182080Srnoland return 1; 1623182080Srnoland} 1624182080Srnoland 1625182080Srnolandstruct drm_buf *mach64_freelist_get(drm_mach64_private_t *dev_priv) 1626182080Srnoland{ 1627182080Srnoland drm_mach64_descriptor_ring_t *ring = &dev_priv->ring; 1628182080Srnoland drm_mach64_freelist_t *entry; 1629145132Sanholt struct list_head *ptr; 1630145132Sanholt int t; 1631145132Sanholt 1632145132Sanholt if (list_empty(&dev_priv->free_list)) { 1633145132Sanholt if (list_empty(&dev_priv->pending)) { 1634145132Sanholt DRM_ERROR 1635145132Sanholt ("Couldn't get buffer - pending and free lists empty\n"); 1636145132Sanholt t = 0; 1637145132Sanholt list_for_each(ptr, &dev_priv->placeholders) { 1638145132Sanholt t++; 1639145132Sanholt } 1640145132Sanholt DRM_INFO("Placeholders: %d\n", t); 1641145132Sanholt return NULL; 1642145132Sanholt } 1643145132Sanholt 1644145132Sanholt for (t = 0; t < dev_priv->usec_timeout; t++) { 1645182080Srnoland int ret; 1646145132Sanholt 1647182080Srnoland ret = mach64_do_reclaim_completed(dev_priv); 1648182080Srnoland if (ret == 0) 1649145132Sanholt goto _freelist_entry_found; 1650182080Srnoland if (ret < 0) 1651182080Srnoland return NULL; 1652145132Sanholt 1653145132Sanholt DRM_UDELAY(1); 1654145132Sanholt } 1655145132Sanholt mach64_dump_ring_info(dev_priv); 1656145132Sanholt DRM_ERROR 1657145132Sanholt ("timeout waiting for buffers: ring head_addr: 0x%08x head: %d tail: %d\n", 1658145132Sanholt ring->head_addr, ring->head, ring->tail); 1659145132Sanholt return NULL; 1660145132Sanholt } 1661145132Sanholt 1662145132Sanholt _freelist_entry_found: 1663145132Sanholt ptr = dev_priv->free_list.next; 1664145132Sanholt list_del(ptr); 1665145132Sanholt entry = list_entry(ptr, drm_mach64_freelist_t, list); 1666145132Sanholt entry->buf->used = 0; 1667145132Sanholt list_add_tail(ptr, &dev_priv->placeholders); 1668145132Sanholt return entry->buf; 1669145132Sanholt} 1670145132Sanholt 1671182080Srnolandint mach64_freelist_put(drm_mach64_private_t *dev_priv, struct drm_buf *copy_buf) 1672182080Srnoland{ 1673182080Srnoland struct list_head *ptr; 1674182080Srnoland drm_mach64_freelist_t *entry; 1675182080Srnoland 1676182080Srnoland#if MACH64_EXTRA_CHECKING 1677182080Srnoland list_for_each(ptr, &dev_priv->pending) { 1678182080Srnoland entry = list_entry(ptr, drm_mach64_freelist_t, list); 1679182080Srnoland if (copy_buf == entry->buf) { 1680182080Srnoland DRM_ERROR("Trying to release a pending buf\n"); 1681182080Srnoland return -EFAULT; 1682182080Srnoland } 1683182080Srnoland } 1684182080Srnoland#endif 1685182080Srnoland ptr = dev_priv->placeholders.next; 1686182080Srnoland entry = list_entry(ptr, drm_mach64_freelist_t, list); 1687182080Srnoland copy_buf->pending = 0; 1688182080Srnoland copy_buf->used = 0; 1689182080Srnoland entry->buf = copy_buf; 1690182080Srnoland entry->discard = 1; 1691182080Srnoland list_del(ptr); 1692182080Srnoland list_add_tail(ptr, &dev_priv->free_list); 1693182080Srnoland 1694182080Srnoland return 0; 1695182080Srnoland} 1696182080Srnoland 1697145132Sanholt/*@}*/ 1698145132Sanholt 1699145132Sanholt 1700145132Sanholt/*******************************************************************/ 1701145132Sanholt/** \name DMA buffer request and submission IOCTL handler */ 1702145132Sanholt/*@{*/ 1703145132Sanholt 1704182080Srnolandstatic int mach64_dma_get_buffers(struct drm_device *dev, 1705182080Srnoland struct drm_file *file_priv, 1706182080Srnoland struct drm_dma * d) 1707145132Sanholt{ 1708145132Sanholt int i; 1709182080Srnoland struct drm_buf *buf; 1710145132Sanholt drm_mach64_private_t *dev_priv = dev->dev_private; 1711145132Sanholt 1712145132Sanholt for (i = d->granted_count; i < d->request_count; i++) { 1713145132Sanholt buf = mach64_freelist_get(dev_priv); 1714145132Sanholt#if MACH64_EXTRA_CHECKING 1715145132Sanholt if (!buf) 1716182080Srnoland return -EFAULT; 1717145132Sanholt#else 1718145132Sanholt if (!buf) 1719182080Srnoland return -EAGAIN; 1720145132Sanholt#endif 1721145132Sanholt 1722182080Srnoland buf->file_priv = file_priv; 1723145132Sanholt 1724145132Sanholt if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx, 1725145132Sanholt sizeof(buf->idx))) 1726182080Srnoland return -EFAULT; 1727145132Sanholt if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total, 1728145132Sanholt sizeof(buf->total))) 1729182080Srnoland return -EFAULT; 1730145132Sanholt 1731145132Sanholt d->granted_count++; 1732145132Sanholt } 1733145132Sanholt return 0; 1734145132Sanholt} 1735145132Sanholt 1736182080Srnolandint mach64_dma_buffers(struct drm_device *dev, void *data, 1737182080Srnoland struct drm_file *file_priv) 1738145132Sanholt{ 1739182080Srnoland struct drm_device_dma *dma = dev->dma; 1740182080Srnoland struct drm_dma *d = data; 1741145132Sanholt int ret = 0; 1742145132Sanholt 1743182080Srnoland LOCK_TEST_WITH_RETURN(dev, file_priv); 1744145132Sanholt 1745145132Sanholt /* Please don't send us buffers. 1746145132Sanholt */ 1747182080Srnoland if (d->send_count != 0) { 1748145132Sanholt DRM_ERROR("Process %d trying to send %d buffers via drmDMA\n", 1749182080Srnoland DRM_CURRENTPID, d->send_count); 1750182080Srnoland return -EINVAL; 1751145132Sanholt } 1752145132Sanholt 1753145132Sanholt /* We'll send you buffers. 1754145132Sanholt */ 1755182080Srnoland if (d->request_count < 0 || d->request_count > dma->buf_count) { 1756145132Sanholt DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", 1757182080Srnoland DRM_CURRENTPID, d->request_count, dma->buf_count); 1758182080Srnoland ret = -EINVAL; 1759145132Sanholt } 1760145132Sanholt 1761182080Srnoland d->granted_count = 0; 1762145132Sanholt 1763182080Srnoland if (d->request_count) { 1764182080Srnoland ret = mach64_dma_get_buffers(dev, file_priv, d); 1765145132Sanholt } 1766145132Sanholt 1767145132Sanholt return ret; 1768145132Sanholt} 1769145132Sanholt 1770182080Srnolandvoid mach64_driver_lastclose(struct drm_device * dev) 1771145132Sanholt{ 1772145132Sanholt mach64_do_cleanup_dma(dev); 1773145132Sanholt} 1774145132Sanholt 1775145132Sanholt/*@}*/ 1776