summaryrefslogtreecommitdiff
path: root/bsd-core/drmP.h
AgeCommit message (Collapse)Author
2004-11-07Refine the locking of the DRM. Most significant is covering the driverEric Anholt
ioctls with dev_lock, which is a major step toward being able to remove Giant. Covers some new pieces (dev->unique*) in the core, and avoids one call down into system internals with the drm lock held, which is usually bad (FreeBSD LOR #23, #27).
2004-11-06Remove some core stuff that ended up being unnecessary.Eric Anholt
2004-11-06Get r128 basically working: Hook up the driver's dma ioctl, use the properEric Anholt
offset into the driver ioctl array, and don't make the ctx bitmap conditional.
2004-11-06Hook the debug output up to a sysctl, so you can choose to enable atEric Anholt
runtime.
2004-11-06Commit first pieces of port to OpenBSD, done by Martin Lexa (martin atEric Anholt
martinlexa dot cz). Now that we've got porting for all three major BSDs (and the fourth being very similar to FreeBSD), move the mostly-duplication drm_os_* files into drmP.h. Remove some cruft from linux heritage and from pieces of the DRM that have since been removed. Note that things are still not quite working for even FreeBSD, but these are first steps at cleanup, and just a WIP checkpoint.
2004-11-06Commit WIP of BSD conversion to core model. Compiles for r128, radeon, butEric Anholt
doesn't run yet. Moves the ioctl definitions for these two drivers back to the shared code -- they aren't OS-specific.
2004-08-17Merged drmfntbl-0-0-1Dave Airlie
2004-07-06MFC as of 20040705: dev_t -> struct cdev * change.Eric Anholt
2004-05-09drm_hw_lock_t is now defined in drm.h, remove from here.Eric Anholt
2003-12-16Don't ioremap the framebuffer area. The ioremapped area wasn't used byEric Anholt
anything, and took up valuable KVA. While I'm in the area, clean up BSD MTRR stuff some more. Suggested by: jonsmirl
2003-11-05- Tie the DRM to a specific device: setunique no longer succeeds when givenEric Anholt
a busid that doesn't correspond to the device the DRM is attached to. This is a breaking of backwards-compatibility only for the multiple-DRI-head case with X Servers that don't use interface 1.1. - Move irq_busid to drm_irq.h and make it only return the IRQ for the current device. Retains compatibility with previous X Servers, cleans up unnecessary code. This means no irq_busid on !__HAVE_IRQ, but can be changed if necessary. - Bump interface version to 1.2. This version when set signifies that the control ioctl should ignore the irq number passed in and enable the interrupt handler for the attached device. Otherwise it errors out when the passed-in irq is not equal to the device's. - Store the highest version the interface has been set to in the device. - Fix a recursion on DRM_LOCK in irq_uninstall on FreeBSD. This leaves irq_uninstall being done without the lock in some cases, but it was racey anyways.
2003-11-05Remove buf_alloc which is unused since the locking commit.Eric Anholt
2003-11-04Memory layout transition:Michel Daenzer
the 2D driver initializes MC_FB_LOCATION and related registers sanely the DRM deduces the layout from these registers clients use the new SETPARAM ioctl to tell the DRM where they think the framebuffer is located in the card's address space the DRM uses all this information to check client state and fix it up if necessary This is a prerequisite for things like direct rendering with IGP chips and video capturing.
2003-10-23- Introduce a new ioctl, DRM_IOCTL_SET_VERSION. This ioctl allows theEric Anholt
server or client to notify the DRM that it expects a certain version of the device dependent or device independent interface. If the major doesn't match or minor is too large, EINVAL is returned. A major of -1 means that the requestor doesn't care about that portion of the interface. The ioctl returns the actual versions in the same struct. - Introduce DRM DI interface version 1.1. If the server requests version 1.1, then the DRM sets the unique itself according to the busid of the device it probed, which may then be accessed as normal using getunique. - Request version 1.1 in libdrm's drmOpenByBusID, allowing the X Server to request based on a BusID. Introduce a wrapper for DRM_IOCTL_SET_VERSION and bump libdrm minor version. - Pass the busid in DRIScreenInit if libdrm can handle both a busid and name. This allows drmOpenByBusID to be used to find the DRM instead of just the driver name, which allows us in the future to tie a DRM more strongly to the device it probed to. Introduce a function DRICreatePCIBusID which creates a busid in the form pci:oooo:bb:dd.f similar to linux's pci_name() function. This matches the format used by the DRM in version 1.1. libdrm knows how to match both this format and the old PCI:b:d:f format. - Use the new DRICreatePCIBusID function in the *_dri.c to request the new, more exact busid format.
2003-10-20Clean up BSD MTRR handling. The NetBSD code is untested, but it's my bestEric Anholt
shot.
2003-10-19- SMPng lock the DRM. This is only partial -- there are a few code pathsEric Anholt
used by root (the X Server) which are not locked. However, it should deal with lost-IRQ issues on -current which I think people have been experiencing but I am unable to reproduce (though I understand why they would occur, because of a bug of mine). Note that most of the locking (DRM_LOCK()/UNLOCK()) is all covered by Giant still, so it doesn't matter yet. - Remove locking on FreeBSD-stable and NetBSD. These are covered by the fact that there is no reentrancy of the kernel except by interrupts, which are locked using spldrm()/splx() instead.
2003-10-17- Move IRQ functions from drm_dma.h to new drm_irq.h and disentangle themEric Anholt
from __HAVE_DMA. This will be useful for adding vblank sync support to sis and tdfx. Rename dma_service to irq_handler, which is more accurately what it is. - Fix the #if _HAVE_DMA_IRQ in radeon, r128, mga, i810, i830, gamma to have the right number of underscores. This may have been a problem in the case that the server died without doing its DRM_IOCTL_CONTROL to uninit.
2003-10-17- Converted Linux drivers to initialize DRM instances based on PCI IDs, notEric Anholt
just a single instance. Moved the PCI ID lists from <card>_drv.c in BSD to <card>.h. The PCI ID lists include a driver private field, which may be used by drivers for chip family or other information. Based on work by jonsmirl. - Make tdfx_drv.c and tdfx.h match other drivers. - Fixed up linking of sis shared files. Tested with Radeon and SiS on Linux and FreeBSD, including a Linux setup with 2 SiS cards in a machine, but only one head being used (with DRI)
2003-10-02Axe more old gamma DMA infrastructure.Eric Anholt
2003-08-29Add DRM(calloc), which is convenient, used by the new sis code, and takesEric Anholt
advantage of M_ZERO on BSDs.
2003-08-19- Remove $FreeBSD$ tags as they weren't too useful and merges are now beingEric Anholt
done through perforce. - Add copyright headers to drm_os_*bsd.h, still need to research the other copyright-less files better.
2003-07-29IRQ code cleanup suggested by Linus TorvaldsMichel Daenzer
i830 build fix
2003-07-25Compile fixes for recent 2.5/2.6 Linux kernels. I hope this doesn't breakMichel Daenzer
the i830 driver or the BSDs. :)
2003-05-16Support AGP bridges where the AGP aperture can't be accessed directly byMichel Daenzer
the CPU (David Mosberger, Benjamin Herrenschmidt, myself, Paul Mackerras, Jeff Wiedemeier)
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-26Move the memory functions with debugging info to drm_memory_debug.h, andEric Anholt
remove a couple of dead functions.
2003-04-25Merge from FreeBSD-current.Eric Anholt
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 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-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-03-29Remove dead vma code and remove the unused devstate struct definition.Eric Anholt
2003-03-29Add DRMFILE definitions and supply filp for BSD in theEric Anholt
post-drm-filp-0-1-branch world. The filp is a void * cast from the current pid. This is a temporary solution which maintains the status quo until a proper solution is implemented. What is really needed is a unique pointer per open, hopefully with a device private area. This can be done in FreeBSD for all entry points except mmap, but is difficult (sys/dev/streams/streams.c is an example). I have partially completed code for this but have not had time to debug, so this is a temporary fix.
2003-03-11Merge back from FreeBSD-current, adding FreeBSD ID tags to aid futureEric Anholt
merging. Also includes an update to radeon PCI IDs.
2003-03-06Remove the vbl signal code because it's untested (and has lock issues onEric Anholt
-current).
2003-02-21Merge from bsd-4-0-0-branch.Eric Anholt
2002-12-06Add vblank signal code for BSD DRM. Untested so far, but working with aEric Anholt
4.2.0 userland at least.
2002-10-29Use bus_alloc_resource/bus_release_resource more properly: save the ridEric Anholt
returned by alloc.
2002-09-26BSD vblank framework.Eric Anholt
2002-07-05merged bsd-3-0-0-branchAlan Hourihane
2002-03-06first pass at merging mesa 4.0 kernel drivers into new bsd-3-0-0 branch.Alan Hourihane
2002-01-27First pass merge of XFree86 4.2.0 import.David Dawes
2001-04-09First pass of XFree86 4.0.99.2 merge.David Dawes
2000-07-10Import of XFree86 4.0.1Alan Hourihane
2000-06-13Merged bsd-1-0-1Doug Rabson
2000-05-30Merged bsd-1-0-0Doug Rabson
e "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; } } 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("%s called again without calling cleanup\n", __FUNCTION__); return -EFAULT; } if (!dev->agp || !dev->agp->base) { DRM_ERROR("%s called with no agp memory available\n", __FUNCTION__); 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("%s called without initializing AGP ring buffer.\n", __FUNCTION__); 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("via cmdbuffer, 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("via_pci_cmdbuffer, 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, uint32_t * vb, int qw_count) { for (; qw_count > 0; --qw_count) { VIA_OUT_RING_QW(HC_DUMMY, HC_DUMMY); } return vb; } /* * This function is used internally by ring buffer mangement code. * * Returns virtual pointer to ring buffer. */ static inline uint32_t *via_get_dma(drm_via_private_t * dev_priv) { return (uint32_t *) (dev_priv->dma_ptr + dev_priv->dma_low); } /* * Hooks a segment of data into the tail of the ring-buffer by * modifying the pause address stored in the buffer itself. If * the regulator has already paused, restart it. */ static int via_hook_segment(drm_via_private_t * dev_priv, uint32_t pause_addr_hi, uint32_t pause_addr_lo, int no_pci_fire) { int paused, count; volatile uint32_t *paused_at = dev_priv->last_pause_ptr; uint32_t reader,ptr; paused = 0; via_flush_write_combine(); (void) *(volatile uint32_t *)(via_get_dma(dev_priv) -1); *paused_at = pause_addr_lo; via_flush_write_combine(); (void) *paused_at; reader = *(dev_priv->hw_addr_ptr); ptr = ((volatile char *)paused_at - dev_priv->dma_ptr) + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; dev_priv->last_pause_ptr = via_get_dma(dev_priv) - 1; if ((ptr - reader) <= dev_priv->dma_diff ) { count = 10000000; while (!(paused = (VIA_READ(0x41c) & 0x80000000)) && count--); } if (paused && !no_pci_fire) { reader = *(dev_priv->hw_addr_ptr); if ((ptr - reader) == dev_priv->dma_diff) { /* * There is a concern that these writes may stall the PCI bus * if the GPU is not idle. However, idling the GPU first * doesn't make a difference. */ VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); VIA_READ(VIA_REG_TRANSPACE); } } return paused; } static int via_wait_idle(drm_via_private_t *dev_priv) { int count = 10000000; while (!(VIA_READ(VIA_REG_STATUS) & VIA_VR_QUEUE_BUSY) && count--); while (count-- && (VIA_READ(VIA_REG_STATUS) & (VIA_CMD_RGTR_BUSY | VIA_2D_ENG_BUSY | VIA_3D_ENG_BUSY))) ; return count; } static uint32_t *via_align_cmd(drm_via_private_t *dev_priv, uint32_t cmd_type, uint32_t addr, uint32_t *cmd_addr_hi, uint32_t *cmd_addr_lo, int skip_wait) { uint32_t agp_base; uint32_t cmd_addr, addr_lo, addr_hi; uint32_t *vb; uint32_t qw_pad_count; if (!skip_wait) via_cmdbuf_wait(dev_priv, 2 * CMDBUF_ALIGNMENT_SIZE); vb = via_get_dma(dev_priv); VIA_OUT_RING_QW(HC_HEADER2 | ((VIA_REG_TRANSET >> 2) << 12) | (VIA_REG_TRANSPACE >> 2), HC_ParaType_PreCR << 16); agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; qw_pad_count = (CMDBUF_ALIGNMENT_SIZE >> 3) - ((dev_priv->dma_low & CMDBUF_ALIGNMENT_MASK) >> 3); cmd_addr = (addr) ? addr : agp_base + dev_priv->dma_low - 8 + (qw_pad_count << 3); addr_lo = ((HC_SubA_HAGPBpL << 24) | (cmd_type & HC_HAGPBpID_MASK) | (cmd_addr & HC_HAGPBpL_MASK)); addr_hi = ((HC_SubA_HAGPBpH << 24) | (cmd_addr >> 24)); vb = via_align_buffer(dev_priv, vb, qw_pad_count - 1); VIA_OUT_RING_QW(*cmd_addr_hi = addr_hi, *cmd_addr_lo = addr_lo); return vb; } static void via_cmdbuf_start(drm_via_private_t * dev_priv) { uint32_t pause_addr_lo, pause_addr_hi; uint32_t start_addr, start_addr_lo; uint32_t end_addr, end_addr_lo; uint32_t command; uint32_t agp_base; uint32_t ptr; uint32_t reader; int count; dev_priv->dma_low = 0; agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; start_addr = agp_base; end_addr = agp_base + dev_priv->dma_high; start_addr_lo = ((HC_SubA_HAGPBstL << 24) | (start_addr & 0xFFFFFF)); end_addr_lo = ((HC_SubA_HAGPBendL << 24) | (end_addr & 0xFFFFFF)); command = ((HC_SubA_HAGPCMNT << 24) | (start_addr >> 24) | ((end_addr & 0xff000000) >> 16)); dev_priv->last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, & pause_addr_lo, 1) - 1; via_flush_write_combine(); (void) *(volatile uint32_t *)dev_priv->last_pause_ptr; VIA_WRITE(VIA_REG_TRANSET, (HC_ParaType_PreCR << 16)); VIA_WRITE(VIA_REG_TRANSPACE, command); VIA_WRITE(VIA_REG_TRANSPACE, start_addr_lo); VIA_WRITE(VIA_REG_TRANSPACE, end_addr_lo); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi); VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo); DRM_WRITEMEMORYBARRIER(); VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK); VIA_READ(VIA_REG_TRANSPACE); dev_priv->dma_diff = 0; count = 10000000; while (!(VIA_READ(0x41c) & 0x80000000) && count--); reader = *(dev_priv->hw_addr_ptr); ptr = ((volatile char *)dev_priv->last_pause_ptr - dev_priv->dma_ptr) + dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr + 4; /* * This is the difference between where we tell the * command reader to pause and where it actually pauses. * This differs between hw implementation so we need to * detect it. */ dev_priv->dma_diff = ptr - reader; } static void via_pad_cache(drm_via_private_t *dev_priv, int qwords) { uint32_t *vb; via_cmdbuf_wait(dev_priv, qwords + 2); vb = via_get_dma(dev_priv); VIA_OUT_RING_QW(HC_HEADER2, HC_ParaType_NotTex << 16); via_align_buffer(dev_priv, vb, qwords); } static inline void via_dummy_bitblt(drm_via_private_t * dev_priv) { uint32_t *vb = via_get_dma(dev_priv); SetReg2DAGP(0x0C, (0 | (0 << 16))); SetReg2DAGP(0x10, 0 | (0 << 16)); SetReg2DAGP(0x0, 0x1 | 0x2000 | 0xAA000000); } static void via_cmdbuf_jump(drm_via_private_t * dev_priv) { uint32_t agp_base; uint32_t pause_addr_lo, pause_addr_hi; uint32_t jump_addr_lo, jump_addr_hi; volatile uint32_t *last_pause_ptr; agp_base = dev_priv->dma_offset + (uint32_t) dev_priv->agpAddr; via_align_cmd(dev_priv, HC_HAGPBpID_JUMP, 0, &jump_addr_hi, &jump_addr_lo, 0); dev_priv->dma_wrap = dev_priv->dma_low; /* * Wrap command buffer to the beginning. */ dev_priv->dma_low = 0; if (via_cmdbuf_wait(dev_priv, CMDBUF_ALIGNMENT_SIZE) != 0) { DRM_ERROR("via_cmdbuf_jump failed\n"); } via_dummy_bitblt(dev_priv); via_dummy_bitblt(dev_priv); last_pause_ptr = via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, &pause_addr_lo, 0) -1; via_align_cmd(dev_priv, HC_HAGPBpID_PAUSE, 0, &pause_addr_hi, &pause_addr_lo, 0); *last_pause_ptr = pause_addr_lo; via_hook_segment(dev_priv, jump_addr_hi, jump_addr_lo, 0); } static void via_cmdbuf_rewind(drm_via_private_t * dev_priv) { via_cmdbuf_jump(dev_priv); } static void via_cmdbuf_flush(drm_via_private_t * dev_priv, uint32_t cmd_type) { uint32_t pause_addr_lo, pause_addr_hi; via_align_cmd(dev_priv, cmd_type, 0, &pause_addr_hi, &pause_addr_lo, 0); via_hook_segment(dev_priv, pause_addr_hi, pause_addr_lo, 0); } static void via_cmdbuf_pause(drm_via_private_t * dev_priv) { via_cmdbuf_flush(dev_priv, HC_HAGPBpID_PAUSE); } static void via_cmdbuf_reset(drm_via_private_t * dev_priv) { via_cmdbuf_flush(dev_priv, HC_HAGPBpID_STOP); via_wait_idle(dev_priv); } /* * User interface to the space and lag functions. */ static int via_cmdbuf_size(struct drm_device *dev, void *data, struct drm_file *file_priv) { drm_via_cmdbuf_size_t *d_siz = data; int ret = 0; uint32_t tmp_size, count; drm_via_private_t *dev_priv; DRM_DEBUG("via cmdbuf_size\n"); LOCK_TEST_WITH_RETURN(dev, file_priv); dev_priv = (drm_via_private_t *) dev->dev_private; if (dev_priv->ring.virtual_start == NULL) { DRM_ERROR("%s called without initializing AGP ring buffer.\n", __FUNCTION__); return -EFAULT; } count = 1000000; tmp_size = d_siz->size; switch (d_siz->func) { case VIA_CMDBUF_SPACE: while (((tmp_size = via_cmdbuf_space(dev_priv)) < d_siz->size) && count--) { if (!d_siz->wait) { break; } } if (!count) { DRM_ERROR("VIA_CMDBUF_SPACE timed out.\n"); ret = -EAGAIN; } break; case VIA_CMDBUF_LAG: while (((tmp_size = via_cmdbuf_lag(dev_priv)) > d_siz->size) && count--) { if (!d_siz->wait) { break; } } if (!count) { DRM_ERROR("VIA_CMDBUF_LAG timed out.\n"); ret = -EAGAIN; } break; default: ret = -EFAULT; } d_siz->size = tmp_size; return ret; } #ifndef VIA_HAVE_DMABLIT int via_dma_blit_sync( struct drm_device *dev, void *data, struct drm_file *file_priv ) { DRM_ERROR("PCI DMA BitBlt is not implemented for this system.\n"); return -EINVAL; } int via_dma_blit( struct drm_device *dev, void *data, struct drm_file *file_priv ) { DRM_ERROR("PCI DMA BitBlt is not implemented for this system.\n"); return -EINVAL; } #endif struct drm_ioctl_desc via_ioctls[] = { DRM_IOCTL_DEF(DRM_VIA_ALLOCMEM, via_mem_alloc, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_FREEMEM, via_mem_free, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_AGP_INIT, via_agp_init, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_VIA_FB_INIT, via_fb_init, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_VIA_MAP_INIT, via_map_init, DRM_AUTH|DRM_MASTER), DRM_IOCTL_DEF(DRM_VIA_DEC_FUTEX, via_decoder_futex, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_DMA_INIT, via_dma_init, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_CMDBUFFER, via_cmdbuffer, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_FLUSH, via_flush_ioctl, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_PCICMD, via_pci_cmdbuffer, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_CMDBUF_SIZE, via_cmdbuf_size, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_WAIT_IRQ, via_wait_irq, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_DMA_BLIT, via_dma_blit, DRM_AUTH), DRM_IOCTL_DEF(DRM_VIA_BLIT_SYNC, via_dma_blit_sync, DRM_AUTH) }; int via_max_ioctl = DRM_ARRAY_SIZE(via_ioctls);