cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

via_dma.c (20885B)


      1/* via_dma.c -- DMA support for the VIA Unichrome/Pro
      2 *
      3 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
      4 * All Rights Reserved.
      5 *
      6 * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A.
      7 * All Rights Reserved.
      8 *
      9 * Copyright 2004 The Unichrome project.
     10 * All Rights Reserved.
     11 *
     12 * Permission is hereby granted, free of charge, to any person obtaining a
     13 * copy of this software and associated documentation files (the "Software"),
     14 * to deal in the Software without restriction, including without limitation
     15 * the rights to use, copy, modify, merge, publish, distribute, sub license,
     16 * and/or sell copies of the Software, and to permit persons to whom the
     17 * Software is furnished to do so, subject to the following conditions:
     18 *
     19 * The above copyright notice and this permission notice (including the
     20 * next paragraph) shall be included in all copies or substantial portions
     21 * of the Software.
     22 *
     23 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     24 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     25 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
     26 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
     27 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     28 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
     29 * USE OR OTHER DEALINGS IN THE SOFTWARE.
     30 *
     31 * Authors:
     32 *    Tungsten Graphics,
     33 *    Erdi Chen,
     34 *    Thomas Hellstrom.
     35 */
     36
     37#include <linux/delay.h>
     38#include <linux/uaccess.h>
     39
     40#include <drm/drm.h>
     41#include <drm/drm_device.h>
     42#include <drm/drm_file.h>
     43#include <drm/via_drm.h>
     44
     45#include "via_drv.h"
     46#include "via_3d_reg.h"
     47
     48#define CMDBUF_ALIGNMENT_SIZE   (0x100)
     49#define CMDBUF_ALIGNMENT_MASK   (0x0ff)
     50
     51/* defines for VIA 3D registers */
     52#define VIA_REG_STATUS          0x400
     53#define VIA_REG_TRANSET         0x43C
     54#define VIA_REG_TRANSPACE       0x440
     55
     56/* VIA_REG_STATUS(0x400): Engine Status */
     57#define VIA_CMD_RGTR_BUSY       0x00000080	/* Command Regulator is busy */
     58#define VIA_2D_ENG_BUSY         0x00000001	/* 2D Engine is busy */
     59#define VIA_3D_ENG_BUSY         0x00000002	/* 3D Engine is busy */
     60#define VIA_VR_QUEUE_BUSY       0x00020000	/* Virtual Queue is busy */
     61
     62#define SetReg2DAGP(nReg, nData) {				\
     63	*((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1;	\
     64	*((uint32_t *)(vb) + 1) = (nData);			\
     65	vb = ((uint32_t *)vb) + 2;				\
     66	dev_priv->dma_low += 8;					\
     67}
     68
     69#define via_flush_write_combine() mb()
     70
     71#define VIA_OUT_RING_QW(w1, w2)	do {		\
     72	*vb++ = (w1);				\
     73	*vb++ = (w2);				\
     74	dev_priv->dma_low += 8;			\
     75} while (0)
     76
     77static void via_cmdbuf_start(drm_via_private_t *dev_priv);
     78static void via_cmdbuf_pause(drm_via_private_t *dev_priv);
     79static void via_cmdbuf_reset(drm_via_private_t *dev_priv);
     80static void via_cmdbuf_rewind(drm_via_private_t *dev_priv);
     81static int via_wait_idle(drm_via_private_t *dev_priv);
     82static void via_pad_cache(drm_via_private_t *dev_priv, int qwords);
     83
     84/*
     85 * Free space in command buffer.
     86 */
     87
     88static uint32_t via_cmdbuf_space(drm_via_private_t *dev_priv)
     89{
     90	uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
     91	uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
     92
     93	return ((hw_addr <= dev_priv->dma_low) ?
     94		(dev_priv->dma_high + hw_addr - dev_priv->dma_low) :
     95		(hw_addr - dev_priv->dma_low));
     96}
     97
     98/*
     99 * How much does the command regulator lag behind?
    100 */
    101
    102static uint32_t via_cmdbuf_lag(drm_via_private_t *dev_priv)
    103{
    104	uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
    105	uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;
    106
    107	return ((hw_addr <= dev_priv->dma_low) ?
    108		(dev_priv->dma_low - hw_addr) :
    109		(dev_priv->dma_wrap + dev_priv->dma_low - hw_addr));
    110}
    111
    112/*
    113 * Check that the given size fits in the buffer, otherwise wait.
    114 */
    115
    116static inline int
    117via_cmdbuf_wait(drm_via_private_t *dev_priv, unsigned int size)
    118{
    119	uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
    120	uint32_t cur_addr, hw_addr, next_addr;
    121	volatile uint32_t *hw_addr_ptr;
    122	uint32_t count;
    123	hw_addr_ptr = dev_priv->hw_addr_ptr;
    124	cur_addr = dev_priv->dma_low;
    125	next_addr = cur_addr + size + 512 * 1024;
    126	count = 1000000;
    127	do {
    128		hw_addr = *hw_addr_ptr - agp_base;
    129		if (count-- == 0) {
    130			DRM_ERROR
    131			    ("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n",
    132			     hw_addr, cur_addr, next_addr);
    133			return -1;
    134		}
    135		if  ((cur_addr < hw_addr) && (next_addr >= hw_addr))
    136			msleep(1);
    137	} while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
    138	return 0;
    139}
    140
    141/*
    142 * Checks whether buffer head has reach the end. Rewind the ring buffer
    143 * when necessary.
    144 *
    145 * Returns virtual pointer to ring buffer.
    146 */
    147
    148static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,
    149				      unsigned int size)
    150{
    151	if ((dev_priv->dma_low + size + 4 * CMDBUF_ALIGNMENT_SIZE) >
    152	    dev_priv->dma_high) {
    153		via_cmdbuf_rewind(dev_priv);
    154	}
    155	if (via_cmdbuf_wait(dev_priv, size) != 0)
    156		return NULL;
    157
    158	return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
    159}
    160
    161int via_dma_cleanup(struct drm_device *dev)
    162{
    163	if (dev->dev_private) {
    164		drm_via_private_t *dev_priv =
    165		    (drm_via_private_t *) dev->dev_private;
    166
    167		if (dev_priv->ring.virtual_start) {
    168			via_cmdbuf_reset(dev_priv);
    169
    170			drm_legacy_ioremapfree(&dev_priv->ring.map, dev);
    171			dev_priv->ring.virtual_start = NULL;
    172		}
    173
    174	}
    175
    176	return 0;
    177}
    178
    179static int via_initialize(struct drm_device *dev,
    180			  drm_via_private_t *dev_priv,
    181			  drm_via_dma_init_t *init)
    182{
    183	if (!dev_priv || !dev_priv->mmio) {
    184		DRM_ERROR("via_dma_init called before via_map_init\n");
    185		return -EFAULT;
    186	}
    187
    188	if (dev_priv->ring.virtual_start != NULL) {
    189		DRM_ERROR("called again without calling cleanup\n");
    190		return -EFAULT;
    191	}
    192
    193	if (!dev->agp || !dev->agp->base) {
    194		DRM_ERROR("called with no agp memory available\n");
    195		return -EFAULT;
    196	}
    197
    198	if (dev_priv->chipset == VIA_DX9_0) {
    199		DRM_ERROR("AGP DMA is not supported on this chip\n");
    200		return -EINVAL;
    201	}
    202
    203	dev_priv->ring.map.offset = dev->agp->base + init->offset;
    204	dev_priv->ring.map.size = init->size;
    205	dev_priv->ring.map.type = 0;
    206	dev_priv->ring.map.flags = 0;
    207	dev_priv->ring.map.mtrr = 0;
    208
    209	drm_legacy_ioremap(&dev_priv->ring.map, dev);
    210
    211	if (dev_priv->ring.map.handle == NULL) {
    212		via_dma_cleanup(dev);
    213		DRM_ERROR("can not ioremap virtual address for"
    214			  " ring buffer\n");
    215		return -ENOMEM;
    216	}
    217
    218	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;
    219
    220	dev_priv->dma_ptr = dev_priv->ring.virtual_start;
    221	dev_priv->dma_low = 0;
    222	dev_priv->dma_high = init->size;
    223	dev_priv->dma_wrap = init->size;
    224	dev_priv->dma_offset = init->offset;
    225	dev_priv->last_pause_ptr = NULL;
    226	dev_priv->hw_addr_ptr =
    227		(volatile uint32_t *)((char *)dev_priv->mmio->handle +
    228		init->reg_pause_addr);
    229
    230	via_cmdbuf_start(dev_priv);
    231
    232	return 0;
    233}
    234
    235static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
    236{
    237	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
    238	drm_via_dma_init_t *init = data;
    239	int retcode = 0;
    240
    241	switch (init->func) {
    242	case VIA_INIT_DMA:
    243		if (!capable(CAP_SYS_ADMIN))
    244			retcode = -EPERM;
    245		else
    246			retcode = via_initialize(dev, dev_priv, init);
    247		break;
    248	case VIA_CLEANUP_DMA:
    249		if (!capable(CAP_SYS_ADMIN))
    250			retcode = -EPERM;
    251		else
    252			retcode = via_dma_cleanup(dev);
    253		break;
    254	case VIA_DMA_INITIALIZED:
    255		retcode = (dev_priv->ring.virtual_start != NULL) ?
    256			0 : -EFAULT;
    257		break;
    258	default:
    259		retcode = -EINVAL;
    260		break;
    261	}
    262
    263	return retcode;
    264}
    265
    266static int via_dispatch_cmdbuffer(struct drm_device *dev, drm_via_cmdbuffer_t *cmd)
    267{
    268	drm_via_private_t *dev_priv;
    269	uint32_t *vb;
    270	int ret;
    271
    272	dev_priv = (drm_via_private_t *) dev->dev_private;
    273
    274	if (dev_priv->ring.virtual_start == NULL) {
    275		DRM_ERROR("called without initializing AGP ring buffer.\n");
    276		return -EFAULT;
    277	}
    278
    279	if (cmd->size > VIA_PCI_BUF_SIZE)
    280		return -ENOMEM;
    281
    282	if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size))
    283		return -EFAULT;
    284
    285	/*
    286	 * Running this function on AGP memory is dead slow. Therefore
    287	 * we run it on a temporary cacheable system memory buffer and
    288	 * copy it to AGP memory when ready.
    289	 */
    290
    291	if ((ret =
    292	     via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
    293				       cmd->size, dev, 1))) {
    294		return ret;
    295	}
    296
    297	vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
    298	if (vb == NULL)
    299		return -EAGAIN;
    300
    301	memcpy(vb, dev_priv->pci_buf, cmd->size);
    302
    303	dev_priv->dma_low += cmd->size;
    304
    305	/*
    306	 * Small submissions somehow stalls the CPU. (AGP cache effects?)
    307	 * pad to greater size.
    308	 */
    309
    310	if (cmd->size < 0x100)
    311		via_pad_cache(dev_priv, (0x100 - cmd->size) >> 3);
    312	via_cmdbuf_pause(dev_priv);
    313
    314	return 0;
    315}
    316
    317int via_driver_dma_quiescent(struct drm_device *dev)
    318{
    319	drm_via_private_t *dev_priv = dev->dev_private;
    320
    321	if (!via_wait_idle(dev_priv))
    322		return -EBUSY;
    323	return 0;
    324}
    325
    326static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
    327{
    328
    329	LOCK_TEST_WITH_RETURN(dev, file_priv);
    330
    331	return via_driver_dma_quiescent(dev);
    332}
    333
    334static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
    335{
    336	drm_via_cmdbuffer_t *cmdbuf = data;
    337	int ret;
    338
    339	LOCK_TEST_WITH_RETURN(dev, file_priv);
    340
    341	DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
    342
    343	ret = via_dispatch_cmdbuffer(dev, cmdbuf);
    344	return ret;
    345}
    346
    347static int via_dispatch_pci_cmdbuffer(struct drm_device *dev,
    348				      drm_via_cmdbuffer_t *cmd)
    349{
    350	drm_via_private_t *dev_priv = dev->dev_private;
    351	int ret;
    352
    353	if (cmd->size > VIA_PCI_BUF_SIZE)
    354		return -ENOMEM;
    355	if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size))
    356		return -EFAULT;
    357
    358	if ((ret =
    359	     via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
    360				       cmd->size, dev, 0))) {
    361		return ret;
    362	}
    363
    364	ret =
    365	    via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf,
    366				     cmd->size);
    367	return ret;
    368}
    369
    370static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
    371{
    372	drm_via_cmdbuffer_t *cmdbuf = data;
    373	int ret;
    374
    375	LOCK_TEST_WITH_RETURN(dev, file_priv);
    376
    377	DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);
    378
    379	ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
    380	return ret;
    381}
    382
    383static inline uint32_t *via_align_buffer(drm_via_private_t *dev_priv,
    384					 uint32_t * vb, int qw_count)
    385{
    386	for (; qw_count > 0; --qw_count)
    387		VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY);
    388	return vb;
    389}
    390
    391/*
    392 * This function is used internally by ring buffer management code.
    393 *
    394 * Returns virtual pointer to ring buffer.
    395 */
    396static inline uint32_t *via_get_dma(drm_via_private_t *dev_priv)
    397{
    398	return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
    399}
    400
    401/*
    402 * Hooks a segment of data into the tail of the ring-buffer by
    403 * modifying the pause address stored in the buffer itself. If
    404 * the regulator has already paused, restart it.
    405 */
    406static int via_hook_segment(drm_via_private_t *dev_priv,
    407			    uint32_t pause_addr_hi, uint32_t pause_addr_lo,
    408			    int no_pci_fire)
    409{
    410	int paused, count;
    411	volatile uint32_t *paused_at = dev_priv->last_pause_ptr;
    412	uint32_t reader, ptr;
    413	uint32_t diff;
    414
    415	paused = 0;
    416	via_flush_write_combine();
    417	(void) *(volatile uint32_t *)(via_get_dma(dev_priv) - 1);
    418
    419	*paused_at = pause_addr_lo;
    420	via_flush_write_combine();
    421	(void) *paused_at;
    422
    423	reader = *(dev_priv->hw_addr_ptr);
    424	ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) +
    425		dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
    426
    427	dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1;
    428
    429	/*
    430	 * If there is a possibility that the command reader will
    431	 * miss the new pause address and pause on the old one,
    432	 * In that case we need to program the new start address
    433	 * using PCI.
    434	 */
    435
    436	diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
    437	count = 10000000;
    438	while (diff == 0 && count--) {
    439		paused = (via_read(dev_priv, 0x41c) & 0x80000000);
    440		if (paused)
    441			break;
    442		reader = *(dev_priv->hw_addr_ptr);
    443		diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
    444	}
    445
    446	paused = via_read(dev_priv, 0x41c) & 0x80000000;
    447
    448	if (paused && !no_pci_fire) {
    449		reader = *(dev_priv->hw_addr_ptr);
    450		diff = (uint32_t) (ptr - reader) - dev_priv->dma_diff;
    451		diff &= (dev_priv->dma_high - 1);
    452		if (diff != 0 && diff < (dev_priv->dma_high >> 1)) {
    453			DRM_ERROR("Paused at incorrect address. "
    454				  "0x%08x, 0x%08x 0x%08x\n",
    455				  ptr, reader, dev_priv->dma_diff);
    456		} else if (diff == 0) {
    457			/*
    458			 * There is a concern that these writes may stall the PCI bus
    459			 * if the GPU is not idle. However, idling the GPU first
    460			 * doesn't make a difference.
    461			 */
    462
    463			via_write(dev_priv, VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
    464			via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_hi);
    465			via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_lo);
    466			via_read(dev_priv, VIA_REG_TRANSPACE);
    467		}
    468	}
    469	return paused;
    470}
    471
    472static int via_wait_idle(drm_via_private_t *dev_priv)
    473{
    474	int count = 10000000;
    475
    476	while (!(via_read(dev_priv, VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && --count)
    477		;
    478
    479	while (count && (via_read(dev_priv, VIA_REG_STATUS) &
    480			   (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY |
    481			    VIA_3D_ENG_BUSY)))
    482		--count;
    483	return count;
    484}
    485
    486static uint32_t *via_align_cmd(drm_via_private_t *dev_priv, uint32_t cmd_type,
    487			       uint32_t addr, uint32_t *cmd_addr_hi,
    488			       uint32_t *cmd_addr_lo, int skip_wait)
    489{
    490	uint32_t agp_base;
    491	uint32_t cmd_addr, addr_lo, addr_hi;
    492	uint32_t *vb;
    493	uint32_t qw_pad_count;
    494
    495	if (!skip_wait)
    496		via_cmdbuf_wait(dev_priv, 2 * CMDBUF_ALIGNMENT_SIZE);
    497
    498	vb = via_get_dma(dev_priv);
    499	VIA_OUT_RING_QW(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) |
    500			(VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16);
    501	agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
    502	qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) -
    503	    ((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3);
    504
    505	cmd_addr = (addr) ? addr :
    506	    agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3);
    507	addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) |
    508		   (cmd_addr & HC_HAGPBpL_MASK));
    509	addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24));
    510
    511	vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1);
    512	VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, *cmd_addr_lo = addr_lo);
    513	return vb;
    514}
    515
    516static void via_cmdbuf_start(drm_via_private_t *dev_priv)
    517{
    518	uint32_t pause_addr_lo, pause_addr_hi;
    519	uint32_t start_addr, start_addr_lo;
    520	uint32_t end_addr, end_addr_lo;
    521	uint32_t command;
    522	uint32_t agp_base;
    523	uint32_t ptr;
    524	uint32_t reader;
    525	int count;
    526
    527	dev_priv->dma_low = 0;
    528
    529	agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
    530	start_addr = agp_base;
    531	end_addr = agp_base + dev_priv->dma_high;
    532
    533	start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF));
    534	end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF));
    535	command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) |
    536		   ((end_addr & 0xff000000) >> 16));
    537
    538	dev_priv->last_pause_ptr =
    539	    via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0,
    540			  &pause_addr_hi, &pause_addr_lo, 1) - 1;
    541
    542	via_flush_write_combine();
    543	(void) *(volatile uint32_t *)dev_priv->last_pause_ptr;
    544
    545	via_write(dev_priv, VIA_REG_TRANSET, (HC_ParaType_PreCR << 16));
    546	via_write(dev_priv, VIA_REG_TRANSPACE, command);
    547	via_write(dev_priv, VIA_REG_TRANSPACE, start_addr_lo);
    548	via_write(dev_priv, VIA_REG_TRANSPACE, end_addr_lo);
    549
    550	via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_hi);
    551	via_write(dev_priv, VIA_REG_TRANSPACE, pause_addr_lo);
    552	wmb();
    553	via_write(dev_priv, VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
    554	via_read(dev_priv, VIA_REG_TRANSPACE);
    555
    556	dev_priv->dma_diff = 0;
    557
    558	count = 10000000;
    559	while (!(via_read(dev_priv, 0x41c) & 0x80000000) && count--);
    560
    561	reader = *(dev_priv->hw_addr_ptr);
    562	ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) +
    563	    dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4;
    564
    565	/*
    566	 * This is the difference between where we tell the
    567	 * command reader to pause and where it actually pauses.
    568	 * This differs between hw implementation so we need to
    569	 * detect it.
    570	 */
    571
    572	dev_priv->dma_diff = ptr - reader;
    573}
    574
    575static void via_pad_cache(drm_via_private_t *dev_priv, int qwords)
    576{
    577	uint32_t *vb;
    578
    579	via_cmdbuf_wait(dev_priv, qwords + 2);
    580	vb = via_get_dma(dev_priv);
    581	VIA_OUT_RING_QW(HC_HEADER2, HC_ParaType_NotTex << 16);
    582	via_align_buffer(dev_priv, vb, qwords);
    583}
    584
    585static inline void via_dummy_bitblt(drm_via_private_t *dev_priv)
    586{
    587	uint32_t *vb = via_get_dma(dev_priv);
    588	SetReg2DAGP(0x0C, (0 | (0 << 16)));
    589	SetReg2DAGP(0x10, 0 | (0 << 16));
    590	SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000);
    591}
    592
    593static void via_cmdbuf_jump(drm_via_private_t *dev_priv)
    594{
    595	uint32_t pause_addr_lo, pause_addr_hi;
    596	uint32_t jump_addr_lo, jump_addr_hi;
    597	volatile uint32_t *last_pause_ptr;
    598	uint32_t dma_low_save1, dma_low_save2;
    599
    600	via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi,
    601		      &jump_addr_lo, 0);
    602
    603	dev_priv->dma_wrap = dev_priv->dma_low;
    604
    605	/*
    606	 * Wrap command buffer to the beginning.
    607	 */
    608
    609	dev_priv->dma_low = 0;
    610	if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0)
    611		DRM_ERROR("via_cmdbuf_jump failed\n");
    612
    613	via_dummy_bitblt(dev_priv);
    614	via_dummy_bitblt(dev_priv);
    615
    616	last_pause_ptr =
    617	    via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
    618			  &pause_addr_lo, 0) - 1;
    619	via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
    620		      &pause_addr_lo, 0);
    621
    622	*last_pause_ptr = pause_addr_lo;
    623	dma_low_save1 = dev_priv->dma_low;
    624
    625	/*
    626	 * Now, set a trap that will pause the regulator if it tries to rerun the old
    627	 * command buffer. (Which may happen if via_hook_segment detecs a command regulator pause
    628	 * and reissues the jump command over PCI, while the regulator has already taken the jump
    629	 * and actually paused at the current buffer end).
    630	 * There appears to be no other way to detect this condition, since the hw_addr_pointer
    631	 * does not seem to get updated immediately when a jump occurs.
    632	 */
    633
    634	last_pause_ptr =
    635		via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
    636			      &pause_addr_lo, 0) - 1;
    637	via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi,
    638		      &pause_addr_lo, 0);
    639	*last_pause_ptr = pause_addr_lo;
    640
    641	dma_low_save2 = dev_priv->dma_low;
    642	dev_priv->dma_low = dma_low_save1;
    643	via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0);
    644	dev_priv->dma_low = dma_low_save2;
    645	via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
    646}
    647
    648
    649static void via_cmdbuf_rewind(drm_via_private_t *dev_priv)
    650{
    651	via_cmdbuf_jump(dev_priv);
    652}
    653
    654static void via_cmdbuf_flush(drm_via_private_t *dev_priv, uint32_t cmd_type)
    655{
    656	uint32_t pause_addr_lo, pause_addr_hi;
    657
    658	via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0);
    659	via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0);
    660}
    661
    662static void via_cmdbuf_pause(drm_via_private_t *dev_priv)
    663{
    664	via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE);
    665}
    666
    667static void via_cmdbuf_reset(drm_via_private_t *dev_priv)
    668{
    669	via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP);
    670	via_wait_idle(dev_priv);
    671}
    672
    673/*
    674 * User interface to the space and lag functions.
    675 */
    676
    677static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv)
    678{
    679	drm_via_cmdbuf_size_t *d_siz = data;
    680	int ret = 0;
    681	uint32_t tmp_size, count;
    682	drm_via_private_t *dev_priv;
    683
    684	DRM_DEBUG("\n");
    685	LOCK_TEST_WITH_RETURN(dev, file_priv);
    686
    687	dev_priv = (drm_via_private_t *) dev->dev_private;
    688
    689	if (dev_priv->ring.virtual_start == NULL) {
    690		DRM_ERROR("called without initializing AGP ring buffer.\n");
    691		return -EFAULT;
    692	}
    693
    694	count = 1000000;
    695	tmp_size = d_siz->size;
    696	switch (d_siz->func) {
    697	case VIA_CMDBUF_SPACE:
    698		while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size)
    699		       && --count) {
    700			if (!d_siz->wait)
    701				break;
    702		}
    703		if (!count) {
    704			DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n");
    705			ret = -EAGAIN;
    706		}
    707		break;
    708	case VIA_CMDBUF_LAG:
    709		while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size)
    710		       && --count) {
    711			if (!d_siz->wait)
    712				break;
    713		}
    714		if (!count) {
    715			DRM_ERROR("VIA_CMDBUF_LAG timed out.\n");
    716			ret = -EAGAIN;
    717		}
    718		break;
    719	default:
    720		ret = -EFAULT;
    721	}
    722	d_siz->size = tmp_size;
    723
    724	return ret;
    725}
    726
    727const struct drm_ioctl_desc via_ioctls[] = {
    728	DRM_IOCTL_DEF_DRV(VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH),
    729	DRM_IOCTL_DEF_DRV(VIA_FREEMEM, via_mem_free, DRM_AUTH),
    730	DRM_IOCTL_DEF_DRV(VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER),
    731	DRM_IOCTL_DEF_DRV(VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER),
    732	DRM_IOCTL_DEF_DRV(VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER),
    733	DRM_IOCTL_DEF_DRV(VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH),
    734	DRM_IOCTL_DEF_DRV(VIA_DMA_INIT, via_dma_init, DRM_AUTH),
    735	DRM_IOCTL_DEF_DRV(VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH),
    736	DRM_IOCTL_DEF_DRV(VIA_FLUSH, via_flush_ioctl, DRM_AUTH),
    737	DRM_IOCTL_DEF_DRV(VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH),
    738	DRM_IOCTL_DEF_DRV(VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH),
    739	DRM_IOCTL_DEF_DRV(VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH),
    740	DRM_IOCTL_DEF_DRV(VIA_DMA_BLIT, via_dma_blit, DRM_AUTH),
    741	DRM_IOCTL_DEF_DRV(VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH)
    742};
    743
    744int via_max_ioctl = ARRAY_SIZE(via_ioctls);