summaryrefslogtreecommitdiff
AgeCommit message (Collapse)Author
2003-04-27Use real endian conversion functions.Eric Anholt
2003-04-26Fix formatting of hw.dri sysctl.Eric Anholt
2003-04-26Remove the map argument from DRM_*MEMORYBARRIER. Not all of the uses ofEric Anholt
DRM_*MEMORYBARRIER we had were related to an MMIO space. This means arch-specific code on the BSDs, unfortunately. Also add DRM_MEMORYBARRIER() and change the DRM_READMEMORYBARRIER()s that used to be read/write barriers to it.
2003-04-26MFL: Don't install irq handler unless the driver has been initialized.Eric Anholt
2003-04-26Add PCI DMA memory functions and make addbufs_pci and associated code useEric Anholt
it. To do this we need to save the bus address along with the virtual address in the seglist. Also fix some error handling and a few bits of whitespace.
2003-04-26Ensure driver has been initialized (dev_private != NULL) before installingLeif Delgass
irq handler in DRM(irq_install). Modify all drivers to ensure irq handler is removed before cleanup and cleanup is called at takedown. Remove unused buffer private struct fields in i810, i830. Check for lock on init/cleanup in all drivers except i810/i830. The current DDX for i810 and i830 doesn't hold the lock on kernel init (FIXME?).
2003-04-26Missed files in the last commit: Remove memory debugging sysctl unlessEric Anholt
MEMORY_DEBUG is set.
2003-04-26Move the memory functions with debugging info to drm_memory_debug.h, andEric Anholt
remove a couple of dead functions.
2003-04-26Remove #if 0'ed code.Eric Anholt
2003-04-262.5.x sync patch from Linus TorvaldsKeith Whitwell
2003-04-26move prototypes for gamma functions to gamma_drv.hKeith Whitwell
2003-04-26Remove #if 0'd codeKeith Whitwell
2003-04-26Replace the C atomic_cmpset_int compatibility function for -stable with theEric Anholt
real i386 atomic_cmpset_int from -current. FreeBSD-stable won't ever have DRM support for non-i386.
2003-04-26Disable MTRRs on FreeBSD-stable. Without this, it hangs on boot in the MTRREric Anholt
setting for AGP cards on SMP machines.
2003-04-25Fix potential oops and memory leaks when allocations fail inLeif Delgass
addbufs_agp/pci. Add support for buffer private structs with PCI DMA buffers. Also some debug format string fixes.
2003-04-25Merge from FreeBSD-current.Eric Anholt
2003-04-25Targets for building dristat and drmstat.David Dawes
2003-04-25Clean up the DRM_COPY_TO_USER()ing of DRM(infobufs), making it moreEric Anholt
legible.
2003-04-24Clean up the style of the linux-compat code and use ioctl() directly ratherEric Anholt
than reimplementing it.
2003-04-24Pass dma handle from pci_alloc_consistent to the card for status page,Leif Delgass
rather than using virt_to_bus() on the virtual address.
2003-04-24Remove more gamma DMA infrastructure. Most of this code was copied straightEric Anholt
from linux, so it could be added back if some driver needed it in the future.
2003-04-24Remove unused dev->map_count. We always iterate the maplist withLeif Delgass
list_for_each() and the count is not updated or used for stats.
2003-04-24Minor cleanups for dri/drmstat test progs (Both still need targets for newLeif Delgass
Makefile)
2003-04-24Remove unused variablesLeif Delgass
2003-04-24Move the debug versions of the DRM memory functions to a new file andKeith Whitwell
implement non-debug ones as standard.
2003-04-24Remove #if 0'd code and some unused string functionsKeith Whitwell
2003-04-24Remove more gamma DMA code. This isn't all of it, but it's a major portion.Eric Anholt
2003-04-24Move some common code from addbufs_<type> to addbufs. Make buf_alloc beEric Anholt
protected by the count_lock and make it non-atomic.
2003-04-24Remove the ioctl_count variable from the device. A reference is held to theEric Anholt
fp throughout the ioctl syscall, so the device can't be closed out from under us.
2003-04-24Remove a bunch of dead code and fix spelling of a couple of comments.Eric Anholt
2003-04-24Single/dual rasterizer quiescence patch for the glint/gamma DRI driverDavid Dawes
(#5685, Sven Luther).
2003-04-24break long lineDavid Dawes
2003-04-24Move one definition to drm_drv.h and remove the rest of drm_init.h whichEric Anholt
was all unused.
2003-04-24Remove DRM_DMA_HISTOGRAM and associated code.Eric Anholt
2003-04-24Make DRM(read) and DRM(poll) stubs and remove DRM(write) andEric Anholt
DRM(write_string). This is the first part of removing much of the support code for gamma from the BSD DRM, since it appears that no new drivers are using it and nobody has ever shown interest in gamma on BSD.
2003-04-23Install dummy/noop read & poll fops unless the driver has replacements.Keith Whitwell
2003-04-23deal correctly with read() from the DRM failingMichel Daenzer
2003-04-22get rid of superfluous fields in struct drm_radeon_ring_bufferMichel Daenzer
use correct address for ring read pointer writeback (yes, we seem to have been running with bogus values for the ring read pointer, which 'worked' because the return value of radeon_wait_ring() is never checked and the ring usually never fills up)
2003-04-22Remove AGP dependency in kernel config for radeon, sis. RemoveLeif Delgass
PCIGART_ENABLED define for radeon, pcigart support now included for any arch.
2003-04-22Only mga, i810, i830 require AGP (should mga define __MUST_HAVE_AGP?)Leif Delgass
2003-04-22change PREINSTALL/POSTINSTALL/UNINSTALL irq code to real functions as perAlan Hourihane
the other drivers
2003-04-22remove unused variableAlan Hourihane
2003-04-22fix gamma headersAlan Hourihane
2003-04-22Rename drm_lists.h to gamma_lists.hKeith Whitwell
2003-04-22new fileKeith Whitwell
2003-04-22Move the excitingly named DRM(flush_block_and_flush) and friends toKeith Whitwell
gamma-specific code. Fix templates so i8x0 drivers don't have to define __HAVE_DMA_WAITLIST.
2003-04-22remove unused __HAVE_KERNEL_CTX_SWITCH codeKeith Whitwell
2003-04-22Move a chunk of gamma-specific code out of drm_dma.h. Remove unusedKeith Whitwell
'DRM_FLAG_NOCTX' option.
2003-04-22remove unused dma histogram codeKeith Whitwell
2003-04-22Move a bunch of gamma-specific code into a gamma-specific file. Restore theKeith Whitwell
kooky DRM(write_string) code for gamma.
607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763
/* via_dma.c -- DMA support for the VIA Unichrome/Pro
 *
 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
 * All Rights Reserved.
 *
 * Copyright 2004 Digeo, Inc., Palo Alto, CA, U.S.A.
 * All Rights Reserved.
 *
 * Copyright 2004 The Unichrome project.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sub license,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * Authors:
 *    Tungsten Graphics,
 *    Erdi Chen,
 *    Thomas Hellstrom.
 */

#include "drmP.h"
#include "drm.h"
#include "via_drm.h"
#include "via_drv.h"
#include "via_3d_reg.h"

#define SetReg2DAGP(nReg, nData) {				\
	*((uint32_t *)(vb)) = ((nReg) >> 2) | HALCYON_HEADER1;	\
	*((uint32_t *)(vb) + 1) = (nData);			\
	vb = ((uint32_t *)vb) + 2;				\
	dev_priv->dma_low +=8;					\
}

#define via_flush_write_combine() DRM_MEMORYBARRIER()

#define VIA_OUT_RING_QW(w1,w2)			\
	*vb++ = (w1);				\
	*vb++ = (w2);				\
	dev_priv->dma_low += 8;

static void via_cmdbuf_start(drm_via_private_t *dev_priv);
static void via_cmdbuf_pause(drm_via_private_t *dev_priv);
static void via_cmdbuf_reset(drm_via_private_t *dev_priv);
static void via_cmdbuf_rewind(drm_via_private_t *dev_priv);
static int via_wait_idle(drm_via_private_t *dev_priv);
static void via_pad_cache(drm_via_private_t *dev_priv, int qwords);


/*
 * Free space in command buffer.
 */

static uint32_t via_cmdbuf_space(drm_via_private_t *dev_priv)
{
	uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
	uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;

	return ((hw_addr <= dev_priv->dma_low) ?
		(dev_priv->dma_high + hw_addr - dev_priv->dma_low) :
		(hw_addr - dev_priv->dma_low));
}

/*
 * How much does the command regulator lag behind?
 */

static uint32_t via_cmdbuf_lag(drm_via_private_t *dev_priv)
{
	uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
	uint32_t hw_addr = *(dev_priv->hw_addr_ptr) - agp_base;

	return ((hw_addr <= dev_priv->dma_low) ?
		(dev_priv->dma_low - hw_addr) :
		(dev_priv->dma_wrap + dev_priv->dma_low - hw_addr));
}

/*
 * Check that the given size fits in the buffer, otherwise wait.
 */

static inline int
via_cmdbuf_wait(drm_via_private_t * dev_priv, unsigned int size)
{
	uint32_t agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr;
	uint32_t cur_addr, hw_addr, next_addr;
	volatile uint32_t *hw_addr_ptr;
	uint32_t count;
	hw_addr_ptr = dev_priv->hw_addr_ptr;
	cur_addr = dev_priv->dma_low;
	next_addr = cur_addr + size + 512 * 1024;
	count = 1000000;
	do {
		hw_addr = *hw_addr_ptr - agp_base;
		if (count-- == 0) {
			DRM_ERROR
			    ("via_cmdbuf_wait timed out hw %x cur_addr %x next_addr %x\n",
			     hw_addr, cur_addr, next_addr);
			return -1;
		}
		if  ((cur_addr < hw_addr) && (next_addr >= hw_addr))
			msleep(1);
	} while ((cur_addr < hw_addr) && (next_addr >= hw_addr));
	return 0;
}


/*
 * Checks whether buffer head has reach the end. Rewind the ring buffer
 * when necessary.
 *
 * Returns virtual pointer to ring buffer.
 */

static inline uint32_t *via_check_dma(drm_via_private_t * dev_priv,
				      unsigned int size)
{
	if ((dev_priv->dma_low + size + 4 * CMDBUF_ALIGNMENT_SIZE) >
	    dev_priv->dma_high) {
		via_cmdbuf_rewind(dev_priv);
	}
	if (via_cmdbuf_wait(dev_priv, size) != 0) {
		return NULL;
	}

	return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low);
}

int via_dma_cleanup(struct drm_device * dev)
{
	if (dev->dev_private) {
		drm_via_private_t *dev_priv =
			(drm_via_private_t *) dev->dev_private;

		if (dev_priv->ring.virtual_start) {
			via_cmdbuf_reset(dev_priv);

			drm_core_ioremapfree(&dev_priv->ring.map, dev);
			dev_priv->ring.virtual_start = NULL;
		}

	}

	return 0;
}

static int via_initialize(struct drm_device * dev,
			  drm_via_private_t * dev_priv,
			  drm_via_dma_init_t * init)
{
	if (!dev_priv || !dev_priv->mmio) {
		DRM_ERROR("via_dma_init called before via_map_init\n");
		return -EFAULT;
	}

	if (dev_priv->ring.virtual_start != NULL) {
		DRM_ERROR("called again without calling cleanup\n");
		return -EFAULT;
	}

	if (!dev->agp || !dev->agp->base) {
		DRM_ERROR("called with no agp memory available\n");
		return -EFAULT;
	}

	if (dev_priv->chipset == VIA_DX9_0) {
		DRM_ERROR("AGP DMA is not supported on this chip\n");
		return -EINVAL;
	}

	dev_priv->ring.map.offset = dev->agp->base + init->offset;
	dev_priv->ring.map.size = init->size;
	dev_priv->ring.map.type = 0;
	dev_priv->ring.map.flags = 0;
	dev_priv->ring.map.mtrr = 0;

	drm_core_ioremap(&dev_priv->ring.map, dev);

	if (dev_priv->ring.map.handle == NULL) {
		via_dma_cleanup(dev);
		DRM_ERROR("can not ioremap virtual address for"
			  " ring buffer\n");
		return -ENOMEM;
	}

	dev_priv->ring.virtual_start = dev_priv->ring.map.handle;

	dev_priv->dma_ptr = dev_priv->ring.virtual_start;
	dev_priv->dma_low = 0;
	dev_priv->dma_high = init->size;
	dev_priv->dma_wrap = init->size;
	dev_priv->dma_offset = init->offset;
	dev_priv->last_pause_ptr = NULL;
	dev_priv->hw_addr_ptr =
		(volatile uint32_t *)((char *)dev_priv->mmio->handle +
		init->reg_pause_addr);

	via_cmdbuf_start(dev_priv);

	return 0;
}

static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
	drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
	drm_via_dma_init_t *init = data;
	int retcode = 0;

	switch (init->func) {
	case VIA_INIT_DMA:
		if (!DRM_SUSER(DRM_CURPROC))
			retcode = -EPERM;
		else
			retcode = via_initialize(dev, dev_priv, init);
		break;
	case VIA_CLEANUP_DMA:
		if (!DRM_SUSER(DRM_CURPROC))
			retcode = -EPERM;
		else
			retcode = via_dma_cleanup(dev);
		break;
	case VIA_DMA_INITIALIZED:
		retcode = (dev_priv->ring.virtual_start != NULL) ?
			0 : -EFAULT;
		break;
	default:
		retcode = -EINVAL;
		break;
	}

	return retcode;
}



static int via_dispatch_cmdbuffer(struct drm_device * dev, drm_via_cmdbuffer_t * cmd)
{
	drm_via_private_t *dev_priv;
	uint32_t *vb;
	int ret;

	dev_priv = (drm_via_private_t *) dev->dev_private;

	if (dev_priv->ring.virtual_start == NULL) {
		DRM_ERROR("called without initializing AGP ring buffer.\n");
		return -EFAULT;
	}

	if (cmd->size > VIA_PCI_BUF_SIZE) {
		return -ENOMEM;
	}

	if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
		return -EFAULT;

	/*
	 * Running this function on AGP memory is dead slow. Therefore
	 * we run it on a temporary cacheable system memory buffer and
	 * copy it to AGP memory when ready.
	 */

	if ((ret =
	     via_verify_command_stream((uint32_t *)dev_priv->pci_buf,
				       cmd->size, dev, 1))) {
		return ret;
	}

	vb = via_check_dma(dev_priv, (cmd->size < 0x100) ? 0x102 : cmd->size);
	if (vb == NULL) {
		return -EAGAIN;
	}

	memcpy(vb, dev_priv->pci_buf, cmd->size);

	dev_priv->dma_low += cmd->size;

	/*
	 * Small submissions somehow stalls the CPU. (AGP cache effects?)
	 * pad to greater size.
	 */

	if (cmd->size < 0x100)
		via_pad_cache(dev_priv, (0x100 - cmd->size) >> 3);
	via_cmdbuf_pause(dev_priv);

	return 0;
}

int via_driver_dma_quiescent(struct drm_device * dev)
{
	drm_via_private_t *dev_priv = dev->dev_private;

	if (!via_wait_idle(dev_priv)) {
		return -EBUSY;
	}
	return 0;
}

static int via_flush_ioctl(struct drm_device *dev, void *data, struct drm_file *file_priv)
{

	LOCK_TEST_WITH_RETURN(dev, file_priv);

	return via_driver_dma_quiescent(dev);
}

static int via_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
	drm_via_cmdbuffer_t *cmdbuf = data;
	int ret;

	LOCK_TEST_WITH_RETURN(dev, file_priv);

	DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);

	ret = via_dispatch_cmdbuffer(dev, cmdbuf);
	if (ret) {
		return ret;
	}

	return 0;
}

static int via_dispatch_pci_cmdbuffer(struct drm_device * dev,
				      drm_via_cmdbuffer_t * cmd)
{
	drm_via_private_t *dev_priv = dev->dev_private;
	int ret;

	if (cmd->size > VIA_PCI_BUF_SIZE) {
		return -ENOMEM;
	}
	if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
		return -EFAULT;

	if ((ret =
	     via_verify_command_stream((uint32_t *) dev_priv->pci_buf,
				       cmd->size, dev, 0))) {
		return ret;
	}

	ret =
	    via_parse_command_stream(dev, (const uint32_t *)dev_priv->pci_buf,
				     cmd->size);
	return ret;
}

static int via_pci_cmdbuffer(struct drm_device *dev, void *data, struct drm_file *file_priv)
{
	drm_via_cmdbuffer_t *cmdbuf = data;
	int ret;

	LOCK_TEST_WITH_RETURN(dev, file_priv);

	DRM_DEBUG("buf %p size %lu\n", cmdbuf->buf, cmdbuf->size);

	ret = via_dispatch_pci_cmdbuffer(dev, cmdbuf);
	if (ret) {
		return ret;
	}

	return 0;
}

static inline uint32_t *via_align_buffer(drm_via_private_t * dev_priv,