diff options
author | Gareth Hughes <gareth@users.sourceforge.net> | 2000-09-19 16:40:02 +0000 |
---|---|---|
committer | Gareth Hughes <gareth@users.sourceforge.net> | 2000-09-19 16:40:02 +0000 |
commit | cc57f63b8f9ab759a1217e9532a9d7c48b7f684f (patch) | |
tree | a8ae06651c911ed9c81a13b5a3903f3d69400574 | |
parent | 83253109dc9400daece9111d9a832587ce3690ed (diff) |
Somewhat unstable development work. Use at your own risk.
-rw-r--r-- | linux-core/Makefile.kernel | 3 | ||||
-rw-r--r-- | linux-core/r128_drv.c | 36 | ||||
-rw-r--r-- | linux/Makefile.kernel | 3 | ||||
-rw-r--r-- | linux/Makefile.linux | 8 | ||||
-rw-r--r-- | linux/r128_bufs.c | 38 | ||||
-rw-r--r-- | linux/r128_cce.c | 970 | ||||
-rw-r--r-- | linux/r128_context.c | 22 | ||||
-rw-r--r-- | linux/r128_dma.c | 909 | ||||
-rw-r--r-- | linux/r128_drm.h | 227 | ||||
-rw-r--r-- | linux/r128_drv.c | 36 | ||||
-rw-r--r-- | linux/r128_drv.h | 378 | ||||
-rw-r--r-- | linux/r128_state.c | 464 |
12 files changed, 1912 insertions, 1182 deletions
diff --git a/linux-core/Makefile.kernel b/linux-core/Makefile.kernel index b1b8d9768..278ff264c 100644 --- a/linux-core/Makefile.kernel +++ b/linux-core/Makefile.kernel @@ -38,7 +38,8 @@ endif gamma-objs := $(lib-objs) gamma_drv.o gamma_dma.o tdfx-objs := $(lib-objs) tdfx_drv.o tdfx_context.o -r128-objs := $(lib-objs) r128_drv.o r128_dma.o r128_context.o r128_bufs.o +r128-objs := $(lib-objs) r128_drv.o r128_cce.o r128_context.o r128_bufs.o\ + r128_state.o ffb-objs := $(lib-objs) ffb_drv.o ffb_context.o mga-objs := $(lib-objs) mga_drv.o mga_dma.o mga_context.o mga_bufs.o \ mga_state.o diff --git a/linux-core/r128_drv.c b/linux-core/r128_drv.c index b58dcf066..6393812e2 100644 --- a/linux-core/r128_drv.c +++ b/linux-core/r128_drv.c @@ -33,15 +33,15 @@ #include "drmP.h" #include "r128_drv.h" -#define R128_NAME "r128" -#define R128_DESC "ATI Rage 128" -#define R128_DATE "20000910" -#define R128_MAJOR 1 -#define R128_MINOR 0 -#define R128_PATCHLEVEL 0 +#define R128_NAME "r128" +#define R128_DESC "ATI Rage 128" +#define R128_DATE "20000905" +#define R128_MAJOR 1 +#define R128_MINOR 1 +#define R128_PATCHLEVEL 0 -static drm_device_t r128_device; -drm_ctx_t r128_res_ctx; +static drm_device_t r128_device; +drm_ctx_t r128_res_ctx; static struct file_operations r128_fops = { #if LINUX_VERSION_CODE >= 0x020400 @@ -108,9 +108,9 @@ static drm_ioctl_desc_t r128_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_init_cce, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_eng_reset, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_FLUSH)] = { r128_eng_flush, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_cce_packet, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_IDLE)] = { r128_cce_idle, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_cce_vertex, 1, 0 }, }; #define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) @@ -425,13 +425,13 @@ int r128_version(struct inode *inode, struct file *filp, unsigned int cmd, sizeof(version))) return -EFAULT; -#define DRM_COPY(name,value) \ - len = strlen(value); \ - if (len > name##_len) len = name##_len; \ - name##_len = strlen(value); \ - if (len && name) { \ - if (copy_to_user(name, value, len)) \ - return -EFAULT; \ +#define DRM_COPY(name,value) \ + len = strlen(value); \ + if (len > name##_len) len = name##_len; \ + name##_len = strlen(value); \ + if (len && name) { \ + if (copy_to_user(name, value, len)) \ + return -EFAULT; \ } version.version_major = R128_MAJOR; @@ -666,6 +666,7 @@ int r128_lock(struct inode *inode, struct file *filp, unsigned int cmd, dev->sigdata.context = lock.context; dev->sigdata.lock = dev->lock.hw_lock; block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + if (lock.flags & _DRM_LOCK_READY) { /* Wait for space in DMA/FIFO */ } @@ -730,6 +731,7 @@ int r128_unlock(struct inode *inode, struct file *filp, unsigned int cmd, current->priority = DEF_PRIORITY; } #endif + unblock_all_signals(); return 0; } diff --git a/linux/Makefile.kernel b/linux/Makefile.kernel index b1b8d9768..278ff264c 100644 --- a/linux/Makefile.kernel +++ b/linux/Makefile.kernel @@ -38,7 +38,8 @@ endif gamma-objs := $(lib-objs) gamma_drv.o gamma_dma.o tdfx-objs := $(lib-objs) tdfx_drv.o tdfx_context.o -r128-objs := $(lib-objs) r128_drv.o r128_dma.o r128_context.o r128_bufs.o +r128-objs := $(lib-objs) r128_drv.o r128_cce.o r128_context.o r128_bufs.o\ + r128_state.o ffb-objs := $(lib-objs) ffb_drv.o ffb_context.o mga-objs := $(lib-objs) mga_drv.o mga_dma.o mga_context.o mga_bufs.o \ mga_state.o diff --git a/linux/Makefile.linux b/linux/Makefile.linux index 7fe57f8e3..d92d259ac 100644 --- a/linux/Makefile.linux +++ b/linux/Makefile.linux @@ -11,11 +11,11 @@ # the rights to use, copy, modify, merge, publish, distribute, sublicense, # 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 NONINFRINGEMENT. IN NO EVENT SHALL @@ -23,7 +23,7 @@ # 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. -# +# # $XFree86: xc/programs/Xserver/hw/xfree86/os-support/linux/drm/kernel/Makefile.linux,v 1.9 2000/08/04 03:51:47 tsi Exp $ # # ***** NOTE NOTE NOTE NOTE NOTE ***** @@ -62,7 +62,7 @@ GAMMAHEADERS= gamma_drv.h $(DRMHEADERS) TDFXOBJS= tdfx_drv.o tdfx_context.o TDFXHEADERS= tdfx_drv.h $(DRMHEADERS) -R128OBJS= r128_drv.o r128_dma.o r128_bufs.o r128_context.o +R128OBJS= r128_drv.o r128_cce.o r128_bufs.o r128_state.o r128_context.o R128HEADERS= r128_drv.h r128_drm.h $(DRMHEADERS) PROGOBJS= drmstat.po xf86drm.po xf86drmHash.po xf86drmRandom.po sigio.po diff --git a/linux/r128_bufs.c b/linux/r128_bufs.c index 7e76441ee..0053c0feb 100644 --- a/linux/r128_bufs.c +++ b/linux/r128_bufs.c @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 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 NONINFRINGEMENT. IN NO EVENT SHALL @@ -23,11 +23,11 @@ * 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: Kevin E. Martin <martin@valinux.com> * Rickard E. (Rik) Faith <faith@valinux.com> * Jeff Hartmann <jhartmann@valinux.com> - * + * */ #define __NO_VERSION__ @@ -60,9 +60,7 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, if (!dma) return -EINVAL; - if (copy_from_user(&request, - (drm_buf_desc_t *)arg, - sizeof(request))) + if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request))) return -EFAULT; count = request.count; @@ -94,7 +92,7 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, } atomic_inc(&dev->buf_alloc); spin_unlock(&dev->count_lock); - + down(&dev->struct_sem); entry = &dma->bufs[order]; if (entry->buf_count) { @@ -102,7 +100,7 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, atomic_dec(&dev->buf_alloc); return -ENOMEM; /* May only call once for each order */ } - + entry->buflist = drm_alloc(count * sizeof(*entry->buflist), DRM_MEM_BUFS); if (!entry->buflist) { @@ -111,7 +109,7 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, return -ENOMEM; } memset(entry->buflist, 0, count * sizeof(*entry->buflist)); - + entry->buf_size = size; entry->page_order = page_order; offset = 0; @@ -173,9 +171,7 @@ int r128_addbufs_agp(struct inode *inode, struct file *filp, unsigned int cmd, request.count = entry->buf_count; request.size = size; - if (copy_to_user((drm_buf_desc_t *)arg, - &request, - sizeof(request))) + if (copy_to_user((drm_buf_desc_t *)arg, &request, sizeof(request))) return -EFAULT; dma->flags = _DRM_DMA_USE_AGP; @@ -195,9 +191,7 @@ int r128_addbufs(struct inode *inode, struct file *filp, unsigned int cmd, if (!dev_priv || dev_priv->is_pci) return -EINVAL; - if (copy_from_user(&request, - (drm_buf_desc_t *)arg, - sizeof(request))) + if (copy_from_user(&request, (drm_buf_desc_t *)arg, sizeof(request))) return -EFAULT; #if defined(CONFIG_AGP) || defined(CONFIG_AGP_MODULE) @@ -234,9 +228,7 @@ int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, ++dev->buf_use; /* Can't allocate more after this call */ spin_unlock(&dev->count_lock); - if (copy_from_user(&request, - (drm_buf_map_t *)arg, - sizeof(request))) + if (copy_from_user(&request, (drm_buf_map_t *)arg, sizeof(request))) return -EFAULT; if (request.count >= dma->buf_count) { @@ -250,9 +242,9 @@ int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, } down(¤t->mm->mmap_sem); - virtual = do_mmap(filp, 0, map->size, + virtual = do_mmap(filp, 0, map->size, PROT_READ|PROT_WRITE, - MAP_SHARED, + MAP_SHARED, (unsigned long)map->offset); up(¤t->mm->mmap_sem); } else { @@ -300,9 +292,7 @@ int r128_mapbufs(struct inode *inode, struct file *filp, unsigned int cmd, request.count = dma->buf_count; DRM_DEBUG("%d buffers, retcode = %d\n", request.count, retcode); - if (copy_to_user((drm_buf_map_t *)arg, - &request, - sizeof(request))) + if (copy_to_user((drm_buf_map_t *)arg, &request, sizeof(request))) return -EFAULT; return retcode; diff --git a/linux/r128_cce.c b/linux/r128_cce.c new file mode 100644 index 000000000..d9f988ed1 --- /dev/null +++ b/linux/r128_cce.c @@ -0,0 +1,970 @@ +/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*- + * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com + * + * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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: Kevin E. Martin <martin@valinux.com> + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "r128_drv.h" + +#include <linux/interrupt.h> /* For task queue support */ +#include <linux/delay.h> + + +/* FIXME: Temporary CCE packet buffer */ +u32 r128_cce_buffer[(1 << 14)] __attribute__ ((aligned (32))); + + +#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) + +#define DO_REMAPFREE(_m) \ + do { \ + if ((_m)->handle && (_m)->size) \ + drm_ioremapfree((_m)->handle, (_m)->size); \ + } while (0) + +#define DO_FIND_MAP(_m, _o) \ + do { \ + int _i; \ + for (_i = 0; _i < dev->map_count; _i++) { \ + if (dev->maplist[_i]->offset == _o) { \ + _m = dev->maplist[_i]; \ + break; \ + } \ + } \ + } while (0) + + +int R128_READ_PLL(drm_device_t *dev, int addr) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + + R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); + return R128_READ(R128_CLOCK_CNTL_DATA); +} + +/* GH: This should really use my PIII mb() patch */ +#define r128_flush_write_combine() mb() + + +static void r128_status(drm_device_t *dev) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + + printk("GUI_STAT = 0x%08x\n", + (unsigned int)R128_READ(R128_GUI_STAT)); + printk("PM4_STAT = 0x%08x\n", + (unsigned int)R128_READ(R128_PM4_STAT)); + printk("PM4_BUFFER_DL_WPTR = 0x%08x\n", + (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR)); + printk("PM4_BUFFER_DL_RPTR = 0x%08x\n", + (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR)); +} + +static int r128_do_cleanup_cce(drm_device_t *dev) +{ + if (dev->dev_private) { + drm_r128_private_t *dev_priv = dev->dev_private; + + if (!dev_priv->is_pci) { + DO_REMAPFREE(dev_priv->agp_ring); + DO_REMAPFREE(dev_priv->agp_read_ptr); + DO_REMAPFREE(dev_priv->agp_vertbufs); + DO_REMAPFREE(dev_priv->agp_indbufs); + DO_REMAPFREE(dev_priv->agp_textures); + } + + drm_free(dev->dev_private, sizeof(drm_r128_private_t), + DRM_MEM_DRIVER); + dev->dev_private = NULL; + } + + return 0; +} + +static int r128_do_init_cce(drm_device_t *dev, drm_r128_init_t *init) +{ + drm_r128_private_t *dev_priv; + int i; + + dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); + if (dev_priv == NULL) return -ENOMEM; + dev->dev_private = (void *)dev_priv; + + memset(dev_priv, 0, sizeof(drm_r128_private_t)); + + dev_priv->is_pci = init->is_pci; + + dev_priv->usec_timeout = init->usec_timeout; + if (dev_priv->usec_timeout < 1 || + dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) { + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + dev->dev_private = NULL; + return -EINVAL; + } + + dev_priv->cce_mode = init->cce_mode; + dev_priv->cce_fifo_size = init->cce_fifo_size; + dev_priv->cce_is_bm_mode = + ((init->cce_mode == R128_PM4_192BM) || + (init->cce_mode == R128_PM4_128BM_64INDBM) || + (init->cce_mode == R128_PM4_64BM_128INDBM) || + (init->cce_mode == R128_PM4_64BM_64VCBM_64INDBM)); + dev_priv->cce_secure = init->cce_secure; + + dev_priv->cce_buffer = r128_cce_buffer; + + if (dev_priv->cce_is_bm_mode && dev_priv->is_pci) { + drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); + dev->dev_private = NULL; + return -EINVAL; + } + + for (i = 0; i < dev->map_count; i++) { + if (dev->maplist[i]->type == _DRM_SHM) { + dev_priv->sarea = dev->maplist[i]; + break; + } + } + + DO_FIND_MAP(dev_priv->fb, init->fb_offset); + if (!dev_priv->is_pci) { + DO_FIND_MAP(dev_priv->agp_ring, init->agp_ring_offset); + DO_FIND_MAP(dev_priv->agp_read_ptr, init->agp_read_ptr_offset); + DO_FIND_MAP(dev_priv->agp_vertbufs, init->agp_vertbufs_offset); + DO_FIND_MAP(dev_priv->agp_indbufs, init->agp_indbufs_offset); + DO_FIND_MAP(dev_priv->agp_textures, init->agp_textures_offset); + } + DO_FIND_MAP(dev_priv->mmio, init->mmio_offset); + + dev_priv->sarea_priv = + (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + + init->sarea_priv_offset); + + if (!dev_priv->is_pci) { + DO_REMAP(dev_priv->agp_ring); + DO_REMAP(dev_priv->agp_read_ptr); + DO_REMAP(dev_priv->agp_vertbufs); +#if 0 + DO_REMAP(dev_priv->agp_indirectbufs); + DO_REMAP(dev_priv->agp_textures); +#endif + + dev_priv->ring_size = init->ring_size; + dev_priv->ring_sizel2qw = drm_order(init->ring_size/8); + dev_priv->ring_entries = init->ring_size/sizeof(u32); + dev_priv->ring_read_ptr = ((__volatile__ u32 *) + dev_priv->agp_read_ptr->handle); + dev_priv->ring_start = (u32 *)dev_priv->agp_ring->handle; + dev_priv->ring_end = ((u32 *)dev_priv->agp_ring->handle + + dev_priv->ring_entries); + } + + dev_priv->submit_age = 0; + R128_WRITE(R128_VB_AGE_REG, dev_priv->submit_age); + + return 0; +} + + + +/* ================================================================ + * GH: Done from here down + */ + +int r128_init_cce( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_init_t init; + + if ( copy_from_user( &init, (drm_r128_init_t *)arg, sizeof(init) ) ) + return -EFAULT; + + switch ( init.func ) { + case R128_INIT_CCE: + return r128_do_init_cce( dev, &init ); + case R128_CLEANUP_CCE: + return r128_do_cleanup_cce( dev ); + } + + return -EINVAL; +} + + +/* ================================================================ + * Freelist management + */ + +void r128_freelist_reset( drm_device_t *dev ) +{ + drm_device_dma_t *dma = dev->dma; + int i; + + for ( i = 0 ; i < dma->buf_count ; i++ ) { + drm_buf_t *buf = dma->buflist[i]; + drm_r128_buf_priv_t *buf_priv = buf->dev_private; + buf_priv->age = 0; + } +} + +drm_buf_t *r128_freelist_get( drm_device_t *dev ) +{ + drm_device_dma_t *dma = dev->dma; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_buf_priv_t *buf_priv; + drm_buf_t *buf; + int i, t; + + /* FIXME: Optimize -- use freelist code */ + + for ( i = 0 ; i < dma->buf_count ; i++ ) { + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + if ( buf->pid == 0 ) return buf; + } + + for ( t = 0 ; t < dev_priv->usec_timeout ; t++ ) { + u32 done_age = R128_READ( R128_VB_AGE_REG ); + + for ( i = 0 ; i < dma->buf_count ; i++ ) { + buf = dma->buflist[i]; + buf_priv = buf->dev_private; + if ( buf->pending && buf_priv->age <= done_age ) { + /* The buffer has been processed, so it + * can now be used. + */ + buf->pending = 0; + return buf; + } + } + udelay( 1 ); + } + + r128_status( dev ); + return NULL; +} + + +/* ================================================================ + * Engine control + */ + +static int r128_do_pixcache_flush( drm_r128_private_t *dev_priv ) +{ + u32 tmp; + int i; + + tmp = R128_READ( R128_PC_NGUI_CTLSTAT ) | R128_PC_FLUSH_ALL; + R128_WRITE( R128_PC_NGUI_CTLSTAT, tmp ); + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + if ( !(R128_READ( R128_PC_NGUI_CTLSTAT ) & R128_PC_BUSY) ) { + return 0; + } + udelay( 1 ); + } + + return -EBUSY; +} + +static int r128_do_wait_for_fifo( drm_r128_private_t *dev_priv, int entries ) +{ + int i; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + int slots = R128_READ( R128_GUI_STAT ) & R128_GUI_FIFOCNT_MASK; + if ( slots >= entries ) return 0; + udelay( 1 ); + } + return -EBUSY; +} + +int r128_do_wait_for_idle( drm_r128_private_t *dev_priv ) +{ + int i, ret; + + ret = r128_do_wait_for_fifo( dev_priv, 64 ); + if ( !ret ) return ret; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + if ( !(R128_READ( R128_GUI_STAT ) & R128_GUI_ACTIVE) ) { + r128_do_pixcache_flush( dev_priv ); + return 0; + } + udelay( 1 ); + } + return -EBUSY; +} + +static int r128_do_engine_reset( drm_device_t *dev ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 clock_cntl_index, mclk_cntl, gen_reset_cntl; + + r128_do_pixcache_flush( dev_priv ); + + clock_cntl_index = R128_READ( R128_CLOCK_CNTL_INDEX ); + mclk_cntl = R128_READ_PLL( dev, R128_MCLK_CNTL ); + + R128_WRITE_PLL( R128_MCLK_CNTL, + mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP ); + + gen_reset_cntl = R128_READ( R128_GEN_RESET_CNTL ); + + /* Taken from the sample code - do not change */ + R128_WRITE( R128_GEN_RESET_CNTL, + gen_reset_cntl | R128_SOFT_RESET_GUI ); + R128_READ( R128_GEN_RESET_CNTL ); + R128_WRITE( R128_GEN_RESET_CNTL, + gen_reset_cntl & ~R128_SOFT_RESET_GUI ); + R128_READ( R128_GEN_RESET_CNTL ); + + R128_WRITE_PLL( R128_MCLK_CNTL, mclk_cntl ); + R128_WRITE( R128_CLOCK_CNTL_INDEX, clock_cntl_index ); + R128_WRITE( R128_GEN_RESET_CNTL, gen_reset_cntl ); + + /* For CCE ring buffer only */ + if ( dev_priv->cce_is_bm_mode ) { + R128_WRITE( R128_PM4_BUFFER_DL_WPTR, 0 ); + R128_WRITE( R128_PM4_BUFFER_DL_RPTR, 0 ); + *dev_priv->ring_read_ptr = 0; + dev_priv->sarea_priv->ring_write = 0; + } + + /* Reset the CCE mode */ + r128_do_wait_for_idle( dev_priv ); + R128_WRITE( R128_PM4_BUFFER_CNTL, + dev_priv->cce_mode | dev_priv->ring_sizel2qw ); + R128_READ( R128_PM4_BUFFER_ADDR ); /* as per the sample code */ + R128_WRITE( R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN ); + + r128_freelist_reset( dev ); + return 0; +} + +int r128_eng_reset( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "r128_eng_reset called without lock held\n" ); + return -EINVAL; + } + + return r128_do_engine_reset( dev ); +} + +static int r128_do_engine_flush( drm_device_t *dev ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + u32 tmp; + + tmp = R128_READ( R128_PM4_BUFFER_DL_WPTR ); + R128_WRITE( R128_PM4_BUFFER_DL_WPTR, tmp | R128_PM4_BUFFER_DL_DONE ); + + return 0; +} + +int r128_eng_flush( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "r128_eng_flush called without lock held\n" ); + return -EINVAL; + } + + return r128_do_engine_flush( dev ); +} + + +/* ================================================================ + * CCE FIFO control + */ + +static int r128_do_cce_wait_for_fifo( drm_r128_private_t *dev_priv, + int entries ) +{ + int i; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + int slots = R128_READ( R128_PM4_STAT ) & R128_PM4_FIFOCNT_MASK; + if ( slots >= entries ) return 0; + udelay( 1 ); + } + return -EBUSY; +} + +static inline int r128_do_cce_idle_ring( drm_r128_private_t *dev_priv ) +{ + int i; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + if ( *dev_priv->ring_read_ptr == + dev_priv->sarea_priv->ring_write ) { + int pm4stat = R128_READ( R128_PM4_STAT ); + if ( (pm4stat & R128_PM4_FIFOCNT_MASK) >= + dev_priv->cce_fifo_size && + !(pm4stat & (R128_PM4_BUSY | + R128_PM4_GUI_ACTIVE)) ) { + return r128_do_pixcache_flush( dev_priv ); + } + } + udelay( 1 ); + } + return -EBUSY; +} + +static inline int r128_do_cce_idle_pio( drm_r128_private_t *dev_priv ) +{ + int ret; + int i; + + ret = r128_do_cce_wait_for_fifo( dev_priv, dev_priv->cce_fifo_size ); + if ( ret < 0 ) return ret; + + for ( i = 0 ; i < dev_priv->usec_timeout ; i++ ) { + int pm4stat = R128_READ( R128_PM4_STAT ); + if ( !(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE)) ) { + return r128_do_pixcache_flush( dev_priv ); + } + udelay( 1 ); + } + return -EBUSY; +} + +static int r128_do_cce_idle( drm_device_t *dev ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + + if ( dev_priv->cce_is_bm_mode ) { + return r128_do_cce_idle_ring( dev_priv ); + } else { + return r128_do_cce_idle_pio( dev_priv ); + } +} + +int r128_cce_idle( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "r128_wait_idle called without lock held\n" ); + return -EINVAL; + } + + return r128_do_cce_idle( dev ); +} + + +/* ================================================================ + * CCE packet submission + */ + +static int r128_verify_command( drm_r128_private_t *dev_priv, + u32 cmd, int *size ) +{ + int writing = 1; + + *size = 0; + + switch ( cmd & R128_CCE_PACKET_MASK ) { + case R128_CCE_PACKET0: + if ( (cmd & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2) && + (cmd & R128_CCE_PACKET0_REG_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2) ) { + writing = 0; + } + *size = ((cmd & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + break; + + case R128_CCE_PACKET1: + if ( (cmd & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2) && + (cmd & R128_CCE_PACKET1_REG0_MASK) != + (R128_PM4_VC_FPU_SETUP >> 2) ) { + writing = 0; + } + if ( (cmd & R128_CCE_PACKET1_REG1_MASK) <= (0x1004 << 9) && + (cmd & R128_CCE_PACKET1_REG1_MASK) != + (R128_PM4_VC_FPU_SETUP << 9) ) { + writing = 0; + } + *size = 3; + break; + + case R128_CCE_PACKET2: + break; + + case R128_CCE_PACKET3: + *size = ((cmd & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; + break; + + } + + return writing; +} + +static int r128_submit_packet_ring_secure( drm_r128_private_t *dev_priv, + u32 *commands, int *count ) +{ + int write = dev_priv->sarea_priv->ring_write; + int *write_ptr = dev_priv->ring_start + write; + int c = *count; + u32 tmp = 0; + int psize = 0; + int writing = 1; + int timeout; + + while ( c > 0 ) { + tmp = *commands++; + if ( !psize ) { + writing = r128_verify_command( dev_priv, tmp, &psize ); + } + psize--; + + if ( writing ) { + write++; + *write_ptr++ = tmp; + } + if ( write >= dev_priv->ring_entries ) { + write = 0; + write_ptr = dev_priv->ring_start; + } + timeout = 0; + while ( write == *dev_priv->ring_read_ptr ) { + R128_READ( R128_PM4_BUFFER_DL_RPTR ); + if ( timeout++ >= dev_priv->usec_timeout ) + return -EBUSY; + udelay( 1 ); + } + c--; + } + + if ( write < 32 ) { + memcpy( dev_priv->ring_end, + dev_priv->ring_start, + write * sizeof(u32) ); + } + + /* Make sure WC cache has been flushed */ + r128_flush_write_combine(); + + dev_priv->sarea_priv->ring_write = write; + R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write ); + + *count = 0; + + return 0; +} + +static int r128_submit_packet_pio_secure( drm_r128_private_t *dev_priv, + u32 *commands, int *count ) +{ + u32 tmp = 0; + int psize = 0; + int writing = 1; + int addr = R128_PM4_FIFO_DATA_EVEN; + int ret; + + while ( *count > 0 ) { + tmp = *commands++; + if (!psize) { + writing = r128_verify_command( dev_priv, tmp, &psize ); + } + psize--; + + if ( writing ) { + ret = r128_do_cce_wait_for_fifo( dev_priv, 1 ); + if ( ret ) return ret; + R128_WRITE( addr, tmp ); + addr ^= 0x0004; + } + + *count -= 1; + } + + if ( addr == R128_PM4_FIFO_DATA_ODD ) { + ret = r128_do_cce_wait_for_fifo( dev_priv, 1 ); + if ( ret < 0 ) return ret; + R128_WRITE( addr, R128_CCE_PACKET2 ); + } + + return 0; +} + +static int r128_submit_packet_ring_insecure( drm_r128_private_t *dev_priv, + u32 *commands, int *count ) +{ + int write = dev_priv->sarea_priv->ring_write; + int *write_ptr = dev_priv->ring_start + write; + int c = *count; + int timeout; + + while ( c > 0 ) { + write++; + *write_ptr++ = *commands++; + if ( write >= dev_priv->ring_entries ) { + write = 0; + write_ptr = dev_priv->ring_start; + } + + timeout = 0; + while ( write == *dev_priv->ring_read_ptr ) { + R128_READ( R128_PM4_BUFFER_DL_RPTR ); + if ( timeout++ >= dev_priv->usec_timeout ) + return -EBUSY; + udelay( 1 ); + } + c--; + } + + if ( write < 32 ) { + memcpy( dev_priv->ring_end, + dev_priv->ring_start, + write * sizeof(u32) ); + } + + /* Make sure WC cache has been flushed */ + r128_flush_write_combine(); + + dev_priv->sarea_priv->ring_write = write; + R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write ); + + *count = 0; + + return 0; +} + +static int r128_submit_packet_pio_insecure( drm_r128_private_t *dev_priv, + u32 *commands, int *count ) +{ + int ret; + + while ( *count > 1 ) { + ret = r128_do_cce_wait_for_fifo( dev_priv, 2 ); + if ( ret < 0 ) return ret; + R128_WRITE( R128_PM4_FIFO_DATA_EVEN, *commands++ ); + R128_WRITE( R128_PM4_FIFO_DATA_ODD, *commands++ ); + *count -= 2; + } + + if ( *count ) { + ret = r128_do_cce_wait_for_fifo( dev_priv, 2 ); + if ( ret < 0 ) return ret; + R128_WRITE( R128_PM4_FIFO_DATA_EVEN, *commands++ ); + R128_WRITE( R128_PM4_FIFO_DATA_ODD, R128_CCE_PACKET2 ); + *count = 0; + } + + return 0; +} + +/* Internal packet submission routine. This uses the insecure versions + * of the packet submission functions, and thus should only be used for + * packets generated inside the kernel module. + */ +int r128_do_submit_packet( drm_r128_private_t *dev_priv, + u32 *buffer, int count ) +{ + int c = count; + int ret; + + if ( dev_priv->cce_is_bm_mode ) { + int left = 0; + + if ( c >= dev_priv->ring_entries ) { + c = dev_priv->ring_entries - 1; + left = count - c; + } + + /* Since this is only used by the kernel we can use the + * insecure ring buffer submit packet routine. + */ + ret = r128_submit_packet_ring_insecure( dev_priv, buffer, &c ); + c += left; + } else { + /* Since this is only used by the kernel we can use the + * insecure PIO submit packet routine. + */ + ret = r128_submit_packet_pio_insecure( dev_priv, buffer, &c ); + } + + return ( ret < 0 ) ? ret : c; +} + +/* External packet submission routine. This uses the secure versions + * by default, and can thus submit packets received from user space. + */ +int r128_cce_packet( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_packet_t packet; + u32 *buffer; + int c; + int size; + int ret = 0; + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "r128_submit_packet called without lock held\n" ); + return -EINVAL; + } + + if ( copy_from_user( &packet, (drm_r128_packet_t *)arg, + sizeof(packet) ) ) + return -EFAULT; + + c = packet.count; + size = c * sizeof(*buffer); + + if ( dev_priv->cce_is_bm_mode ) { + int left = 0; + + if ( c >= dev_priv->ring_entries ) { + c = dev_priv->ring_entries - 1; + size = c * sizeof(*buffer); + left = packet.count - c; + } + + buffer = kmalloc( size, 0 ); + if ( buffer == NULL) + return -ENOMEM; + if ( copy_from_user( buffer, packet.buffer, size ) ) + return -EFAULT; + + if ( dev_priv->cce_secure ) { + ret = r128_submit_packet_ring_secure( dev_priv, + buffer, &c ); + } else { + ret = r128_submit_packet_ring_insecure( dev_priv, + buffer, &c ); + } + c += left; + } else { + buffer = kmalloc( size, 0 ); + if ( buffer == NULL ) + return -ENOMEM; + if ( copy_from_user( buffer, packet.buffer, size ) ) + return -EFAULT; + + if ( dev_priv->cce_secure ) { + ret = r128_submit_packet_pio_secure( dev_priv, + buffer, &c ); + } else { + ret = r128_submit_packet_pio_insecure( dev_priv, + buffer, &c ); + } + } + + kfree( buffer ); + + packet.count = c; + if ( copy_to_user( (drm_r128_packet_t *)arg, &packet, + sizeof(packet) ) ) + return -EFAULT; + + if ( ret ) { + return ret; + } else if ( c > 0 ) { + return -EAGAIN; + } + return 0; +} + +#if 0 +static int r128_send_vertbufs( drm_device_t *dev, drm_r128_vertex_t *v ) +{ + drm_device_dma_t *dma = dev->dma; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_buf_priv_t *buf_priv; + drm_buf_t *buf; + int i, ret; + RING_LOCALS; + + /* Make sure we have valid data */ + for (i = 0; i < v->send_count; i++) { + int idx = v->send_indices[i]; + + if (idx < 0 || idx >= dma->buf_count) { + DRM_ERROR("Index %d (of %d max)\n", + idx, dma->buf_count - 1); + return -EINVAL; + } + buf = dma->buflist[idx]; + if (buf->pid != current->pid) { + DRM_ERROR("Process %d using buffer owned by %d\n", + current->pid, buf->pid); + return -EINVAL; + } + if (buf->pending) { + DRM_ERROR("Sending pending buffer:" + " buffer %d, offset %d\n", + v->send_indices[i], i); + return -EINVAL; + } + } + + /* Wait for idle, if we've wrapped to make sure that all pending + buffers have been processed */ + if (dev_priv->submit_age == R128_MAX_VBUF_AGE) { + if ((ret = r128_do_cce_idle(dev)) < 0) return ret; + dev_priv->submit_age = 0; + r128_freelist_reset(dev); + } + + /* Make sure WC cache has been flushed (if in PIO mode) */ + if (!dev_priv->cce_is_bm_mode) r128_flush_write_combine(); + + /* FIXME: Add support for sending vertex buffer to the CCE here + instead of in client code. The v->prim holds the primitive + type that should be drawn. Loop over the list buffers in + send_indices[] and submit a packet for each VB. + + This will require us to loop over the clip rects here as + well, which implies that we extend the kernel driver to allow + cliprects to be stored here. Note that the cliprects could + possibly come from the X server instead of the client, but + this will require additional changes to the DRI to allow for + this optimization. */ + + /* Submit a CCE packet that writes submit_age to R128_VB_AGE_REG */ +#if 0 + cce_buffer[0] = R128CCE0(R128_CCE_PACKET0, R128_VB_AGE_REG, 0); + cce_buffer[1] = dev_priv->submit_age; + + if ((ret = r128_do_submit_packet(dev, cce_buffer, 2)) < 0) { + /* Until we add support for sending VBs to the CCE in + this routine, we can recover from this error. After + we add that support, we won't be able to easily + recover, so we will probably have to implement + another mechanism for handling timeouts from packets + submitted directly by the kernel. */ + return ret; + } +#else + BEGIN_RING( 2 ); + + OUT_RING( CCE_PACKET0( R128_VB_AGE_REG, 0 ) ); + OUT_RING( dev_priv->submit_age ); + + ADVANCE_RING(); +#endif + /* Now that the submit packet request has succeeded, we can mark + the buffers as pending */ + for (i = 0; i < v->send_count; i++) { + buf = dma->buflist[v->send_indices[i]]; + buf->pending = 1; + + buf_priv = buf->dev_private; + buf_priv->age = dev_priv->submit_age; + } + + dev_priv->submit_age++; + + return 0; +} +#endif + +#if 0 +int r128_dma( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + int retcode = 0; + drm_dma_t d; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "r128_dma called without lock held\n" ); + return -EINVAL; + } + if ( !dev_priv || dev_priv->is_pci ) { + DRM_ERROR( "r128_dma called with a PCI card\n" ); + return -EINVAL; + } + + if ( copy_from_user( &v, (drm_r128_vertex_t *)arg, sizeof(v) ) ) + return -EFAULT; + DRM_DEBUG( "%d: %d send, %d req\n", + current->pid, v.send_count, v.request_count ); + +#if 0 + if ( d.send_count < 0 || d.send_count > dma->buf_count ) { + DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", + current->pid, v.send_count, dma->buf_count); + return -EINVAL; + } +#else + if ( d.send_count != 0 ) { + DRM_ERROR( "Process %d trying to send %d buffers via drmDMA\n", + current->pid, d.send_count ); + return -EINVAL; + } +#endif + if ( d.request_count < 0 || d.request_count > dma->buf_count ) { + DRM_ERROR( "Process %d trying to get %d buffers (of %d max)\n", + current->pid, d.request_count, dma->buf_count ); + return -EINVAL; + } +#if 0 + if ( v.send_count ) { + retcode = r128_send_vertbufs( dev, &v ); + } +#endif + v.granted_count = 0; + + if ( /* !retcode && */ d.request_count ) { + retcode = r128_get_dma_buffers( dev, &d ); + } + + DRM_DEBUG( "%d returning, granted = %d\n", + current->pid, d.granted_count ); + if ( copy_to_user( (drm_dma_t *)arg, &d, sizeof(d) ) ) + return -EFAULT; + + return retcode; +} +#endif diff --git a/linux/r128_context.c b/linux/r128_context.c index 9cadadbaf..0d8b2f5c2 100644 --- a/linux/r128_context.c +++ b/linux/r128_context.c @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 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 NONINFRINGEMENT. IN NO EVENT SHALL @@ -23,7 +23,7 @@ * 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. - * + * * Author: Rickard E. (Rik) Faith <faith@valinux.com> * */ @@ -53,21 +53,21 @@ int r128_context_switch(drm_device_t *dev, int old, int new) #if DRM_DMA_HISTOGRAM dev->ctx_start = get_cycles(); #endif - + DRM_DEBUG("Context switch from %d to %d\n", old, new); if (new == dev->last_context) { clear_bit(0, &dev->context_flag); return 0; } - + if (drm_flags & DRM_FLAG_NOCTX) { r128_context_switch_complete(dev, new); } else { sprintf(buf, "C %d %d\n", old, new); drm_write_string(dev, buf); } - + return 0; } @@ -75,7 +75,7 @@ int r128_context_switch_complete(drm_device_t *dev, int new) { dev->last_context = new; /* PRE/POST: This is the _only_ writer. */ dev->last_switch = jiffies; - + if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock)) { DRM_ERROR("Lock isn't held after context switch\n"); } @@ -86,11 +86,11 @@ int r128_context_switch_complete(drm_device_t *dev, int new) #if DRM_DMA_HISTOGRAM atomic_inc(&dev->histo.ctx[drm_histogram_slot(get_cycles() - dev->ctx_start)]); - + #endif clear_bit(0, &dev->context_flag); wake_up(&dev->context_wait); - + return 0; } @@ -109,9 +109,7 @@ int r128_resctx(struct inode *inode, struct file *filp, unsigned int cmd, memset(&ctx, 0, sizeof(ctx)); for (i = 0; i < DRM_RESERVED_CONTEXTS; i++) { ctx.handle = i; - if (copy_to_user(&res.contexts[i], - &i, - sizeof(i))) + if (copy_to_user(&res.contexts[i], &i, sizeof(i))) return -EFAULT; } } diff --git a/linux/r128_dma.c b/linux/r128_dma.c deleted file mode 100644 index bcba67826..000000000 --- a/linux/r128_dma.c +++ /dev/null @@ -1,909 +0,0 @@ -/* r128_drv.c -- ATI Rage 128 driver -*- linux-c -*- - * Created: Wed Apr 5 19:24:19 2000 by kevin@precisioninsight.com - * - * Copyright 2000 Precision Insight, Inc., Cedar Park, Texas. - * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. - * 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, sublicense, - * 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 NONINFRINGEMENT. IN NO EVENT SHALL - * PRECISION INSIGHT 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: Kevin E. Martin <martin@valinux.com> - * - */ - -#define __NO_VERSION__ -#include "drmP.h" -#include "r128_drv.h" - -#include <linux/interrupt.h> /* For task queue support */ -#include <linux/delay.h> - - - -#define DO_REMAP(_m) (_m)->handle = drm_ioremap((_m)->offset, (_m)->size) - -#define DO_REMAPFREE(_m) \ - do { \ - if ((_m)->handle && (_m)->size) \ - drm_ioremapfree((_m)->handle, (_m)->size); \ - } while (0) - -#define DO_FIND_MAP(_m, _o) \ - do { \ - int _i; \ - for (_i = 0; _i < dev->map_count; _i++) { \ - if (dev->maplist[_i]->offset == _o) { \ - _m = dev->maplist[_i]; \ - break; \ - } \ - } \ - } while (0) - - -#define R128_MAX_VBUF_AGE 0x10000000 -#define R128_VB_AGE_REG R128_GUI_SCRATCH_REG0 - -int R128_READ_PLL(drm_device_t *dev, int addr) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - - R128_WRITE8(R128_CLOCK_CNTL_INDEX, addr & 0x1f); - return R128_READ(R128_CLOCK_CNTL_DATA); -} - -#define r128_flush_write_combine() mb() - - -static void r128_status(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - - printk("GUI_STAT = 0x%08x\n", - (unsigned int)R128_READ(R128_GUI_STAT)); - printk("PM4_STAT = 0x%08x\n", - (unsigned int)R128_READ(R128_PM4_STAT)); - printk("PM4_BUFFER_DL_WPTR = 0x%08x\n", - (unsigned int)R128_READ(R128_PM4_BUFFER_DL_WPTR)); - printk("PM4_BUFFER_DL_RPTR = 0x%08x\n", - (unsigned int)R128_READ(R128_PM4_BUFFER_DL_RPTR)); -} - -static int r128_do_cleanup_cce(drm_device_t *dev) -{ - if (dev->dev_private) { - drm_r128_private_t *dev_priv = dev->dev_private; - - if (!dev_priv->is_pci) { - DO_REMAPFREE(dev_priv->agp_ring); - DO_REMAPFREE(dev_priv->agp_read_ptr); - DO_REMAPFREE(dev_priv->agp_vertbufs); - DO_REMAPFREE(dev_priv->agp_indbufs); - DO_REMAPFREE(dev_priv->agp_textures); - } - - drm_free(dev->dev_private, sizeof(drm_r128_private_t), - DRM_MEM_DRIVER); - dev->dev_private = NULL; - } - - return 0; -} - -static int r128_do_init_cce(drm_device_t *dev, drm_r128_init_t *init) -{ - drm_r128_private_t *dev_priv; - int i; - - dev_priv = drm_alloc(sizeof(drm_r128_private_t), DRM_MEM_DRIVER); - if (dev_priv == NULL) return -ENOMEM; - dev->dev_private = (void *)dev_priv; - - memset(dev_priv, 0, sizeof(drm_r128_private_t)); - - dev_priv->is_pci = init->is_pci; - - dev_priv->usec_timeout = init->usec_timeout; - if (dev_priv->usec_timeout < 1 || - dev_priv->usec_timeout > R128_MAX_USEC_TIMEOUT) { - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); - dev->dev_private = NULL; - return -EINVAL; - } - - dev_priv->cce_mode = init->cce_mode; - dev_priv->cce_fifo_size = init->cce_fifo_size; - dev_priv->cce_is_bm_mode = - ((init->cce_mode == R128_PM4_192BM) || - (init->cce_mode == R128_PM4_128BM_64INDBM) || - (init->cce_mode == R128_PM4_64BM_128INDBM) || - (init->cce_mode == R128_PM4_64BM_64VCBM_64INDBM)); - dev_priv->cce_secure = init->cce_secure; - - if (dev_priv->cce_is_bm_mode && dev_priv->is_pci) { - drm_free(dev_priv, sizeof(*dev_priv), DRM_MEM_DRIVER); - dev->dev_private = NULL; - return -EINVAL; - } - - for (i = 0; i < dev->map_count; i++) { - if (dev->maplist[i]->type == _DRM_SHM) { - dev_priv->sarea = dev->maplist[i]; - break; - } - } - - DO_FIND_MAP(dev_priv->fb, init->fb_offset); - if (!dev_priv->is_pci) { - DO_FIND_MAP(dev_priv->agp_ring, init->agp_ring_offset); - DO_FIND_MAP(dev_priv->agp_read_ptr, init->agp_read_ptr_offset); - DO_FIND_MAP(dev_priv->agp_vertbufs, init->agp_vertbufs_offset); - DO_FIND_MAP(dev_priv->agp_indbufs, init->agp_indbufs_offset); - DO_FIND_MAP(dev_priv->agp_textures, init->agp_textures_offset); - } - DO_FIND_MAP(dev_priv->mmio, init->mmio_offset); - - dev_priv->sarea_priv = - (drm_r128_sarea_t *)((u8 *)dev_priv->sarea->handle + - init->sarea_priv_offset); - - if (!dev_priv->is_pci) { - DO_REMAP(dev_priv->agp_ring); - DO_REMAP(dev_priv->agp_read_ptr); - DO_REMAP(dev_priv->agp_vertbufs); -#if 0 - DO_REMAP(dev_priv->agp_indirectbufs); - DO_REMAP(dev_priv->agp_textures); -#endif - - dev_priv->ring_size = init->ring_size; - dev_priv->ring_sizel2qw = drm_order(init->ring_size/8); - dev_priv->ring_entries = init->ring_size/sizeof(u32); - dev_priv->ring_read_ptr = ((__volatile__ u32 *) - dev_priv->agp_read_ptr->handle); - dev_priv->ring_start = (u32 *)dev_priv->agp_ring->handle; - dev_priv->ring_end = ((u32 *)dev_priv->agp_ring->handle - + dev_priv->ring_entries); - } - - dev_priv->submit_age = 0; - R128_WRITE(R128_VB_AGE_REG, dev_priv->submit_age); - - return 0; -} - -int r128_init_cce(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_r128_init_t init; - - if (copy_from_user(&init, (drm_r128_init_t *)arg, sizeof(init))) - return -EFAULT; - - switch (init.func) { - case R128_INIT_CCE: - return r128_do_init_cce(dev, &init); - case R128_CLEANUP_CCE: - return r128_do_cleanup_cce(dev); - } - - return -EINVAL; -} - -static void r128_mark_vertbufs_done(drm_device_t *dev) -{ - drm_device_dma_t *dma = dev->dma; - int i; - - for (i = 0; i < dma->buf_count; i++) { - drm_buf_t *buf = dma->buflist[i]; - drm_r128_buf_priv_t *buf_priv = buf->dev_private; - buf_priv->age = 0; - } -} - -static int r128_do_pixcache_flush(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - u32 tmp; - int i; - - tmp = R128_READ(R128_PC_NGUI_CTLSTAT) | R128_PC_FLUSH_ALL; - R128_WRITE(R128_PC_NGUI_CTLSTAT, tmp); - - for (i = 0; i < dev_priv->usec_timeout; i++) { - if (!(R128_READ(R128_PC_NGUI_CTLSTAT) & R128_PC_BUSY)) - return 0; - udelay(1); - } - - return -EBUSY; -} - -static int r128_do_wait_for_fifo(drm_device_t *dev, int entries) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int i; - - for (i = 0; i < dev_priv->usec_timeout; i++) { - int slots = R128_READ(R128_GUI_STAT) & R128_GUI_FIFOCNT_MASK; - if (slots >= entries) return 0; - udelay(1); - } - return -EBUSY; -} - -static int r128_do_wait_for_idle(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int i, ret; - - if (!(ret = r128_do_wait_for_fifo(dev, 64))) return ret; - - for (i = 0; i < dev_priv->usec_timeout; i++) { - if (!(R128_READ(R128_GUI_STAT) & R128_GUI_ACTIVE)) { - (void)r128_do_pixcache_flush(dev); - return 0; - } - udelay(1); - } - return -EBUSY; -} - -int r128_do_engine_reset(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - u32 clock_cntl_index, mclk_cntl, gen_reset_cntl; - - (void)r128_do_pixcache_flush(dev); - - clock_cntl_index = R128_READ(R128_CLOCK_CNTL_INDEX); - mclk_cntl = R128_READ_PLL(dev, R128_MCLK_CNTL); - - R128_WRITE_PLL(R128_MCLK_CNTL, - mclk_cntl | R128_FORCE_GCP | R128_FORCE_PIPE3D_CP); - - gen_reset_cntl = R128_READ(R128_GEN_RESET_CNTL); - - R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl | R128_SOFT_RESET_GUI); - (void)R128_READ(R128_GEN_RESET_CNTL); - R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl & ~R128_SOFT_RESET_GUI); - (void)R128_READ(R128_GEN_RESET_CNTL); - - R128_WRITE_PLL(R128_MCLK_CNTL, mclk_cntl); - R128_WRITE(R128_CLOCK_CNTL_INDEX, clock_cntl_index); - R128_WRITE(R128_GEN_RESET_CNTL, gen_reset_cntl); - - /* For CCE ring buffer only */ - if (dev_priv->cce_is_bm_mode) { - R128_WRITE(R128_PM4_BUFFER_DL_WPTR, 0); - R128_WRITE(R128_PM4_BUFFER_DL_RPTR, 0); - *dev_priv->ring_read_ptr = 0; - dev_priv->sarea_priv->ring_write = 0; - } - - /* Reset the CCE mode */ - (void)r128_do_wait_for_idle(dev); - R128_WRITE(R128_PM4_BUFFER_CNTL, - dev_priv->cce_mode | dev_priv->ring_sizel2qw); - (void)R128_READ(R128_PM4_BUFFER_ADDR); /* as per the sample code */ - R128_WRITE(R128_PM4_MICRO_CNTL, R128_PM4_MICRO_FREERUN); - - r128_mark_vertbufs_done(dev); - return 0; -} - -int r128_eng_reset(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_eng_reset called without holding the lock\n"); - return -EINVAL; - } - - return r128_do_engine_reset(dev); -} - -static int r128_do_engine_flush(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - u32 tmp; - - tmp = R128_READ(R128_PM4_BUFFER_DL_WPTR); - R128_WRITE(R128_PM4_BUFFER_DL_WPTR, tmp | R128_PM4_BUFFER_DL_DONE); - - return 0; -} - -int r128_eng_flush(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_eng_flush called without holding the lock\n"); - return -EINVAL; - } - - return r128_do_engine_flush(dev); -} - -static int r128_do_cce_wait_for_fifo(drm_device_t *dev, int entries) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int i; - - for (i = 0; i < dev_priv->usec_timeout; i++) { - int slots = R128_READ(R128_PM4_STAT) & R128_PM4_FIFOCNT_MASK; - if (slots >= entries) return 0; - udelay(1); - } - return -EBUSY; -} - -int r128_do_cce_wait_for_idle(drm_device_t *dev) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int i; - - if (dev_priv->cce_is_bm_mode) { - for (i = 0; i < dev_priv->usec_timeout; i++) { - if (*dev_priv->ring_read_ptr == dev_priv->sarea_priv->ring_write) { - int pm4stat = R128_READ(R128_PM4_STAT); - if ((pm4stat & R128_PM4_FIFOCNT_MASK) >= dev_priv->cce_fifo_size && - !(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { - return r128_do_pixcache_flush(dev); - } - } - udelay(1); - } - return -EBUSY; - } else { - int ret = r128_do_cce_wait_for_fifo(dev, dev_priv->cce_fifo_size); - if (ret < 0) return ret; - - for (i = 0; i < dev_priv->usec_timeout; i++) { - int pm4stat = R128_READ(R128_PM4_STAT); - if (!(pm4stat & (R128_PM4_BUSY | R128_PM4_GUI_ACTIVE))) { - return r128_do_pixcache_flush(dev); - } - udelay(1); - } - return -EBUSY; - } -} - -int r128_cce_idle(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_wait_idle called without holding the lock\n"); - return -EINVAL; - } - - return r128_do_cce_wait_for_idle(dev); -} - -static int r128_submit_packets_ring_secure(drm_device_t *dev, - u32 *commands, int *count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int write = dev_priv->sarea_priv->ring_write; - int *write_ptr = dev_priv->ring_start + write; - int c = *count; - u32 tmp = 0; - int psize = 0; - int writing = 1; - int timeout; - - while (c > 0) { - tmp = *commands++; - if (!psize) { - writing = 1; - - if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) { - if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) { - if ((tmp & R128_CCE_PACKET0_REG_MASK) != - (R128_PM4_VC_FPU_SETUP >> 2)) { - writing = 0; - } - } - psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; - } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) { - if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) { - if ((tmp & R128_CCE_PACKET1_REG0_MASK) != - (R128_PM4_VC_FPU_SETUP >> 2)) { - writing = 0; - } - } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <= - (0x1004 << 9)) { - if ((tmp & R128_CCE_PACKET1_REG1_MASK) != - (R128_PM4_VC_FPU_SETUP << 9)) { - writing = 0; - } - } - psize = 3; - } else { - psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; - } - } - psize--; - - if (writing) { - write++; - *write_ptr++ = tmp; - } - if (write >= dev_priv->ring_entries) { - write = 0; - write_ptr = dev_priv->ring_start; - } - timeout = 0; - while (write == *dev_priv->ring_read_ptr) { - (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); - if (timeout++ >= dev_priv->usec_timeout) - return -EBUSY; - udelay(1); - } - c--; - } - - if (write < 32) - memcpy(dev_priv->ring_end, - dev_priv->ring_start, - write * sizeof(u32)); - - /* Make sure WC cache has been flushed */ - r128_flush_write_combine(); - - dev_priv->sarea_priv->ring_write = write; - R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); - - *count = 0; - - return 0; -} - -static int r128_submit_packets_pio_secure(drm_device_t *dev, - u32 *commands, int *count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - u32 tmp = 0; - int psize = 0; - int writing = 1; - int addr = R128_PM4_FIFO_DATA_EVEN; - int ret; - - while (*count > 0) { - tmp = *commands++; - if (!psize) { - writing = 1; - - if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET0) { - if ((tmp & R128_CCE_PACKET0_REG_MASK) <= (0x1004 >> 2)) { - if ((tmp & R128_CCE_PACKET0_REG_MASK) != - (R128_PM4_VC_FPU_SETUP >> 2)) { - writing = 0; - } - } - psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; - } else if ((tmp & R128_CCE_PACKET_MASK) == R128_CCE_PACKET1) { - if ((tmp & R128_CCE_PACKET1_REG0_MASK) <= (0x1004 >> 2)) { - if ((tmp & R128_CCE_PACKET1_REG0_MASK) != - (R128_PM4_VC_FPU_SETUP >> 2)) { - writing = 0; - } - } else if ((tmp & R128_CCE_PACKET1_REG1_MASK) <= - (0x1004 << 9)) { - if ((tmp & R128_CCE_PACKET1_REG1_MASK) != - (R128_PM4_VC_FPU_SETUP << 9)) { - writing = 0; - } - } - psize = 3; - } else { - psize = ((tmp & R128_CCE_PACKET_COUNT_MASK) >> 16) + 2; - } - } - psize--; - - if (writing) { - if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) - return ret; - R128_WRITE(addr, tmp); - addr ^= 0x0004; - } - - *count -= 1; - } - - if (addr == R128_PM4_FIFO_DATA_ODD) { - if ((ret = r128_do_cce_wait_for_fifo(dev, 1)) < 0) return ret; - R128_WRITE(addr, R128_CCE_PACKET2); - } - - return 0; -} - -static int r128_submit_packets_ring(drm_device_t *dev, - u32 *commands, int *count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int write = dev_priv->sarea_priv->ring_write; - int *write_ptr = dev_priv->ring_start + write; - int c = *count; - int timeout; - - while (c > 0) { - write++; - *write_ptr++ = *commands++; - if (write >= dev_priv->ring_entries) { - write = 0; - write_ptr = dev_priv->ring_start; - } - timeout = 0; - while (write == *dev_priv->ring_read_ptr) { - (void)R128_READ(R128_PM4_BUFFER_DL_RPTR); - if (timeout++ >= dev_priv->usec_timeout) - return -EBUSY; - udelay(1); - } - c--; - } - - if (write < 32) - memcpy(dev_priv->ring_end, - dev_priv->ring_start, - write * sizeof(u32)); - - /* Make sure WC cache has been flushed */ - r128_flush_write_combine(); - - dev_priv->sarea_priv->ring_write = write; - R128_WRITE(R128_PM4_BUFFER_DL_WPTR, write); - - *count = 0; - - return 0; -} - -static int r128_submit_packets_pio(drm_device_t *dev, - u32 *commands, int *count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int ret; - - while (*count > 1) { - if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; - R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); - R128_WRITE(R128_PM4_FIFO_DATA_ODD, *commands++); - *count -= 2; - } - - if (*count) { - if ((ret = r128_do_cce_wait_for_fifo(dev, 2)) < 0) return ret; - R128_WRITE(R128_PM4_FIFO_DATA_EVEN, *commands++); - R128_WRITE(R128_PM4_FIFO_DATA_ODD, R128_CCE_PACKET2); - *count = 0; - } - - return 0; -} - -static int r128_do_submit_packets(drm_device_t *dev, u32 *buffer, int count) -{ - drm_r128_private_t *dev_priv = dev->dev_private; - int c = count; - int ret; - - if (dev_priv->cce_is_bm_mode) { - int left = 0; - - if (c >= dev_priv->ring_entries) { - c = dev_priv->ring_entries-1; - left = count - c; - } - - /* Since this is only used by the kernel we can use the - insecure ring buffer submit packet routine */ - ret = r128_submit_packets_ring(dev, buffer, &c); - - c += left; - } else { - /* Since this is only used by the kernel we can use the - insecure PIO submit packet routine */ - ret = r128_submit_packets_pio(dev, buffer, &c); - } - - if (ret < 0) return ret; - else return c; -} - -int r128_submit_pkt(struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_packet_t packet; - u32 *buffer; - int c; - int size; - int ret = 0; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_submit_pkt called without holding the lock\n"); - return -EINVAL; - } - - if (copy_from_user(&packet, (drm_r128_packet_t *)arg, sizeof(packet))) - return -EFAULT; - - c = packet.count; - size = c * sizeof(*buffer); - - if (dev_priv->cce_is_bm_mode) { - int left = 0; - - if (c >= dev_priv->ring_entries) { - c = dev_priv->ring_entries-1; - size = c * sizeof(*buffer); - left = packet.count - c; - } - - if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; - if (copy_from_user(buffer, packet.buffer, size)) - return -EFAULT; - - if (dev_priv->cce_secure) - ret = r128_submit_packets_ring_secure(dev, buffer, &c); - else - ret = r128_submit_packets_ring(dev, buffer, &c); - - c += left; - } else { - if ((buffer = kmalloc(size, 0)) == NULL) return -ENOMEM; - if (copy_from_user(buffer, packet.buffer, size)) - return -EFAULT; - - if (dev_priv->cce_secure) - ret = r128_submit_packets_pio_secure(dev, buffer, &c); - else - ret = r128_submit_packets_pio(dev, buffer, &c); - } - - kfree(buffer); - - packet.count = c; - if (copy_to_user((drm_r128_packet_t *)arg, &packet, sizeof(packet))) - return -EFAULT; - - if (ret) return ret; - else if (c > 0) return -EAGAIN; - - return 0; -} - -static int r128_send_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) -{ - drm_device_dma_t *dma = dev->dma; - drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_buf_priv_t *buf_priv; - drm_buf_t *buf; - int i, ret; - u32 cce[2]; - - /* Make sure we have valid data */ - for (i = 0; i < v->send_count; i++) { - int idx = v->send_indices[i]; - - if (idx < 0 || idx >= dma->buf_count) { - DRM_ERROR("Index %d (of %d max)\n", - idx, dma->buf_count - 1); - return -EINVAL; - } - buf = dma->buflist[idx]; - if (buf->pid != current->pid) { - DRM_ERROR("Process %d using buffer owned by %d\n", - current->pid, buf->pid); - return -EINVAL; - } - if (buf->pending) { - DRM_ERROR("Sending pending buffer:" - " buffer %d, offset %d\n", - v->send_indices[i], i); - return -EINVAL; - } - } - - /* Wait for idle, if we've wrapped to make sure that all pending - buffers have been processed */ - if (dev_priv->submit_age == R128_MAX_VBUF_AGE) { - if ((ret = r128_do_cce_wait_for_idle(dev)) < 0) return ret; - dev_priv->submit_age = 0; - r128_mark_vertbufs_done(dev); - } - - /* Make sure WC cache has been flushed (if in PIO mode) */ - if (!dev_priv->cce_is_bm_mode) r128_flush_write_combine(); - - /* FIXME: Add support for sending vertex buffer to the CCE here - instead of in client code. The v->prim holds the primitive - type that should be drawn. Loop over the list buffers in - send_indices[] and submit a packet for each VB. - - This will require us to loop over the clip rects here as - well, which implies that we extend the kernel driver to allow - cliprects to be stored here. Note that the cliprects could - possibly come from the X server instead of the client, but - this will require additional changes to the DRI to allow for - this optimization. */ - - /* Submit a CCE packet that writes submit_age to R128_VB_AGE_REG */ - cce[0] = R128CCE0(R128_CCE_PACKET0, R128_VB_AGE_REG, 0); - cce[1] = dev_priv->submit_age; - if ((ret = r128_do_submit_packets(dev, cce, 2)) < 0) { - /* Until we add support for sending VBs to the CCE in - this routine, we can recover from this error. After - we add that support, we won't be able to easily - recover, so we will probably have to implement - another mechanism for handling timeouts from packets - submitted directly by the kernel. */ - return ret; - } - - /* Now that the submit packet request has succeeded, we can mark - the buffers as pending */ - for (i = 0; i < v->send_count; i++) { - buf = dma->buflist[v->send_indices[i]]; - buf->pending = 1; - - buf_priv = buf->dev_private; - buf_priv->age = dev_priv->submit_age; - } - - dev_priv->submit_age++; - - return 0; -} - -static drm_buf_t *r128_freelist_get(drm_device_t *dev) -{ - drm_device_dma_t *dma = dev->dma; - drm_r128_private_t *dev_priv = dev->dev_private; - drm_r128_buf_priv_t *buf_priv; - drm_buf_t *buf; - int i, t; - - /* FIXME: Optimize -- use freelist code */ - - for (i = 0; i < dma->buf_count; i++) { - buf = dma->buflist[i]; - buf_priv = buf->dev_private; - if (buf->pid == 0) return buf; - } - - for (t = 0; t < dev_priv->usec_timeout; t++) { - u32 done_age = R128_READ(R128_VB_AGE_REG); - - for (i = 0; i < dma->buf_count; i++) { - buf = dma->buflist[i]; - buf_priv = buf->dev_private; - if (buf->pending && buf_priv->age <= done_age) { - /* The buffer has been processed, so it - can now be used */ - buf->pending = 0; - return buf; - } - } - udelay(1); - } - - r128_status(dev); - return NULL; -} - - -static int r128_get_vertbufs(drm_device_t *dev, drm_r128_vertex_t *v) -{ - drm_buf_t *buf; - int i; - - for (i = v->granted_count; i < v->request_count; i++) { - buf = r128_freelist_get(dev); - if (!buf) break; - buf->pid = current->pid; - if (copy_to_user(&v->request_indices[i], - &buf->idx, - sizeof(buf->idx)) || - copy_to_user(&v->request_sizes[i], - &buf->total, - sizeof(buf->total))) - return -EFAULT; - ++v->granted_count; - } - return 0; -} - -int r128_vertex_buf(struct inode *inode, struct file *filp, unsigned int cmd, - unsigned long arg) -{ - drm_file_t *priv = filp->private_data; - drm_device_t *dev = priv->dev; - drm_r128_private_t *dev_priv = dev->dev_private; - drm_device_dma_t *dma = dev->dma; - int retcode = 0; - drm_r128_vertex_t v; - - if (!_DRM_LOCK_IS_HELD(dev->lock.hw_lock->lock) || - dev->lock.pid != current->pid) { - DRM_ERROR("r128_vertex_buf called without holding the lock\n"); - return -EINVAL; - } - - if (!dev_priv || dev_priv->is_pci) { - DRM_ERROR("r128_vertex_buf called with a PCI card\n"); - return -EINVAL; - } - - if (copy_from_user(&v, (drm_r128_vertex_t *)arg, sizeof(v))) - return -EFAULT; - DRM_DEBUG("%d: %d send, %d req\n", - current->pid, v.send_count, v.request_count); - - if (v.send_count < 0 || v.send_count > dma->buf_count) { - DRM_ERROR("Process %d trying to send %d buffers (of %d max)\n", - current->pid, v.send_count, dma->buf_count); - return -EINVAL; - } - if (v.request_count < 0 || v.request_count > dma->buf_count) { - DRM_ERROR("Process %d trying to get %d buffers (of %d max)\n", - current->pid, v.request_count, dma->buf_count); - return -EINVAL; - } - - if (v.send_count) { - retcode = r128_send_vertbufs(dev, &v); - } - - v.granted_count = 0; - - if (!retcode && v.request_count) { - retcode = r128_get_vertbufs(dev, &v); - } - - DRM_DEBUG("%d returning, granted = %d\n", - current->pid, v.granted_count); - if (copy_to_user((drm_r128_vertex_t *)arg, &v, sizeof(v))) - return -EFAULT; - - return retcode; -} diff --git a/linux/r128_drm.h b/linux/r128_drm.h index 9a0ba7071..b5c7629e6 100644 --- a/linux/r128_drm.h +++ b/linux/r128_drm.h @@ -32,6 +32,119 @@ #define _R128_DRM_H_ /* WARNING: If you change any of these defines, make sure to change the + * defines in the X server file (r128_sarea.h) + */ +#ifndef __R128_SAREA_DEFINES__ +#define __R128_SAREA_DEFINES__ + +/* What needs to be changed for the current vertex buffer? + */ +#define R128_UPLOAD_CONTEXT 0x001 +#define R128_UPLOAD_SETUP 0x002 +#define R128_UPLOAD_TEX0 0x004 +#define R128_UPLOAD_TEX1 0x008 +#define R128_UPLOAD_TEX0IMAGES 0x010 +#define R128_UPLOAD_TEX1IMAGES 0x020 +#define R128_UPLOAD_CORE 0x040 +#define R128_UPLOAD_MASKS 0x080 +#define R128_UPLOAD_WINDOW 0x100 +#define R128_UPLOAD_CLIPRECTS 0x200 /* handled client-side */ +#define R128_REQUIRE_QUIESCENCE 0x400 + +#define R128_FRONT 0x1 +#define R128_BACK 0x2 +#define R128_DEPTH 0x4 + +/* Keep these small for testing. + */ +#define R128_NR_SAREA_CLIPRECTS 12 + +/* There are 2 heaps (local/AGP). Each region within a heap is a + * minimum of 64k, and there are at most 64 of them per heap. + */ +#define R128_LOCAL_TEX_HEAP 0 +#define R128_AGP_TEX_HEAP 1 +#define R128_NR_TEX_HEAPS 2 +#define R128_NR_TEX_REGIONS 16 +#define R128_LOG_TEX_GRANULARITY 16 + +#define R128_NR_CONTEXT_REGS 12 +#define R128_TEX_MAXLEVELS 11 + +#endif /* __R128_SAREA_DEFINES__ */ + +typedef struct { + /* Context state - can be written in one large chunk */ + u32 dst_pitch_offset_c; + u32 dp_gui_master_cntl_c; + u32 sc_top_left_c; + u32 sc_bottom_right_c; + u32 z_offset_c; + u32 z_pitch_c; + u32 z_sten_cntl_c; + u32 tex_cntl_c; + u32 misc_3d_state_cntl_reg; + u32 texture_clr_cmp_clr_c; + u32 texture_clr_cmp_msk_c; + u32 fog_color_c; + + /* Texture state */ + u32 tex_size_pitch_c; + u32 constant_color_c; + + /* Setup state */ + u32 pm4_vc_fpu_setup; + u32 setup_cntl; + + /* Mask state */ + u32 dp_write_mask; + u32 sten_ref_mask_c; + u32 plane_3d_mask_c; + + /* Window state */ + u32 window_xy_offset; + + /* Core state */ + u32 scale_3d_cntl; +} drm_r128_context_regs_t; + +/* Setup registers for each texture unit */ +typedef struct { + u32 tex_cntl; + u32 tex_combine_cntl; + u32 tex_size_pitch; + u32 tex_offset[R128_TEX_MAXLEVELS]; + u32 tex_border_color; +} drm_r128_texture_regs_t; + + +typedef struct drm_tex_region { + unsigned char next, prev; + unsigned char in_use; + int age; +} drm_tex_region_t; + +typedef struct drm_r128_sarea { + /* The channel for communication of state information to the kernel + * on firing a vertex buffer. + */ + drm_r128_context_regs_t context_state; + drm_r128_texture_regs_t tex_state[R128_NR_TEX_HEAPS]; + unsigned int dirty; + unsigned int vertsize; + unsigned int vc_format; + + drm_clip_rect_t boxes[R128_NR_SAREA_CLIPRECTS]; + unsigned int nbox; + + drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; + int tex_age[R128_NR_TEX_HEAPS]; + int ctx_owner; + int ring_write; +} drm_r128_sarea_t; + + +/* WARNING: If you change any of these defines, make sure to change the * defines in the Xserver file (xf86drmR128.h) */ typedef struct drm_r128_init { @@ -56,107 +169,25 @@ typedef struct drm_r128_init { int mmio_offset; } drm_r128_init_t; -typedef struct drm_r128_packet { - unsigned long *buffer; - int count; - int flags; -} drm_r128_packet_t; - -typedef enum drm_r128_prim { - _DRM_R128_PRIM_NONE = 0x0001, - _DRM_R128_PRIM_POINT = 0x0002, - _DRM_R128_PRIM_LINE = 0x0004, - _DRM_R128_PRIM_POLY_LINE = 0x0008, - _DRM_R128_PRIM_TRI_LIST = 0x0010, - _DRM_R128_PRIM_TRI_FAN = 0x0020, - _DRM_R128_PRIM_TRI_STRIP = 0x0040, - _DRM_R128_PRIM_TRI_TYPE2 = 0x0080 -} drm_r128_prim_t; +typedef struct drm_r128_clear { + unsigned int clear_color; + unsigned int clear_depth; + unsigned int flags; +} drm_r128_clear_t; typedef struct drm_r128_vertex { - /* Indices here refer to the offset into - buflist in drm_buf_get_t. */ - int send_count; /* Number of buffers to send */ - int *send_indices; /* List of handles to buffers */ - int *send_sizes; /* Lengths of data to send */ - drm_r128_prim_t prim; /* Primitive type */ - int request_count; /* Number of buffers requested */ - int *request_indices; /* Buffer information */ - int *request_sizes; - int granted_count; /* Number of buffers granted */ + int index; /* Index of vertex buffer */ + int used; /* Amount of buffer used */ + int send; /* Dispatch buffer? */ + int discard; /* Discard buffer? */ + int request; /* Request new buffer? */ + int granted; /* New buffer granted? */ } drm_r128_vertex_t; -/* WARNING: If you change any of these defines, make sure to change the - * defines in the Xserver file (r128_sarea.h) - */ -#define R128_LOCAL_TEX_HEAP 0 -#define R128_AGP_TEX_HEAP 1 -#define R128_NR_TEX_HEAPS 2 -#define R128_NR_TEX_REGIONS 64 -#define R128_LOG_TEX_GRANULARITY 16 - -typedef struct drm_tex_region { - unsigned char next, prev; - unsigned char in_use; - int age; -} drm_tex_region_t; - -typedef struct drm_r128_sarea { - drm_tex_region_t tex_list[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; - int tex_age[R128_NR_TEX_HEAPS]; - int ctx_owner; - int ring_write; -} drm_r128_sarea_t; - - -/* GH: These typedefs are taken from my latest kernel module work, and - * needed for the client-side 3D driver. They will go away (along with - * most of the rest of the current kernel module). - */ -#define R128_TEX_MAXLEVELS 11 - -typedef struct { - /* Context state - can be written in one large chunk */ - unsigned long dst_pitch_offset_c; - unsigned long dp_gui_master_cntl_c; - unsigned long sc_top_left_c; - unsigned long sc_bottom_right_c; - unsigned long z_offset_c; - unsigned long z_pitch_c; - unsigned long z_sten_cntl_c; - unsigned long tex_cntl_c; - unsigned long misc_3d_state_cntl_reg; - unsigned long texture_clr_cmp_clr_c; - unsigned long texture_clr_cmp_msk_c; - unsigned long fog_color_c; - - /* Setup state */ - unsigned long pm4_vc_fpu_setup; - unsigned long setup_cntl; - - /* Texture state */ - unsigned long tex_size_pitch_c; - unsigned long constant_color_c; - - /* Mask state */ - unsigned long dp_write_mask; - unsigned long sten_ref_mask_c; - unsigned long plane_3d_mask_c; - - /* Window state */ - unsigned long window_xy_offset; - - /* Core state */ - unsigned long scale_3d_cntl; -} drm_r128_context_regs_t; - -/* Setup registers for each texture unit */ -typedef struct { - unsigned long tex_cntl; - unsigned long tex_combine_cntl; - unsigned long tex_size_pitch; - unsigned long tex_offset[R128_TEX_MAXLEVELS]; - unsigned long tex_border_color; -} drm_r128_texture_regs_t; +typedef struct drm_r128_packet { + u32 *buffer; + int count; + int flags; +} drm_r128_packet_t; #endif diff --git a/linux/r128_drv.c b/linux/r128_drv.c index b58dcf066..6393812e2 100644 --- a/linux/r128_drv.c +++ b/linux/r128_drv.c @@ -33,15 +33,15 @@ #include "drmP.h" #include "r128_drv.h" -#define R128_NAME "r128" -#define R128_DESC "ATI Rage 128" -#define R128_DATE "20000910" -#define R128_MAJOR 1 -#define R128_MINOR 0 -#define R128_PATCHLEVEL 0 +#define R128_NAME "r128" +#define R128_DESC "ATI Rage 128" +#define R128_DATE "20000905" +#define R128_MAJOR 1 +#define R128_MINOR 1 +#define R128_PATCHLEVEL 0 -static drm_device_t r128_device; -drm_ctx_t r128_res_ctx; +static drm_device_t r128_device; +drm_ctx_t r128_res_ctx; static struct file_operations r128_fops = { #if LINUX_VERSION_CODE >= 0x020400 @@ -108,9 +108,9 @@ static drm_ioctl_desc_t r128_ioctls[] = { [DRM_IOCTL_NR(DRM_IOCTL_R128_INIT)] = { r128_init_cce, 1, 1 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_RESET)] = { r128_eng_reset, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_FLUSH)] = { r128_eng_flush, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_submit_pkt, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_PACKET)] = { r128_cce_packet, 1, 0 }, [DRM_IOCTL_NR(DRM_IOCTL_R128_IDLE)] = { r128_cce_idle, 1, 0 }, - [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_vertex_buf, 1, 0 }, + [DRM_IOCTL_NR(DRM_IOCTL_R128_VERTEX)] = { r128_cce_vertex, 1, 0 }, }; #define R128_IOCTL_COUNT DRM_ARRAY_SIZE(r128_ioctls) @@ -425,13 +425,13 @@ int r128_version(struct inode *inode, struct file *filp, unsigned int cmd, sizeof(version))) return -EFAULT; -#define DRM_COPY(name,value) \ - len = strlen(value); \ - if (len > name##_len) len = name##_len; \ - name##_len = strlen(value); \ - if (len && name) { \ - if (copy_to_user(name, value, len)) \ - return -EFAULT; \ +#define DRM_COPY(name,value) \ + len = strlen(value); \ + if (len > name##_len) len = name##_len; \ + name##_len = strlen(value); \ + if (len && name) { \ + if (copy_to_user(name, value, len)) \ + return -EFAULT; \ } version.version_major = R128_MAJOR; @@ -666,6 +666,7 @@ int r128_lock(struct inode *inode, struct file *filp, unsigned int cmd, dev->sigdata.context = lock.context; dev->sigdata.lock = dev->lock.hw_lock; block_all_signals(drm_notifier, &dev->sigdata, &dev->sigmask); + if (lock.flags & _DRM_LOCK_READY) { /* Wait for space in DMA/FIFO */ } @@ -730,6 +731,7 @@ int r128_unlock(struct inode *inode, struct file *filp, unsigned int cmd, current->priority = DEF_PRIORITY; } #endif + unblock_all_signals(); return 0; } diff --git a/linux/r128_drv.h b/linux/r128_drv.h index 5b15dddfb..9083af3a5 100644 --- a/linux/r128_drv.h +++ b/linux/r128_drv.h @@ -11,11 +11,11 @@ * the rights to use, copy, modify, merge, publish, distribute, sublicense, * 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 NONINFRINGEMENT. IN NO EVENT SHALL @@ -23,7 +23,7 @@ * 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: Rickard E. (Rik) Faith <faith@valinux.com> * Kevin E. Martin <martin@valinux.com> * @@ -32,40 +32,67 @@ #ifndef _R128_DRV_H_ #define _R128_DRV_H_ -typedef struct drm_r128_private { - int is_pci; - - int cce_mode; - int cce_fifo_size; - int cce_is_bm_mode; - int cce_secure; - - drm_r128_sarea_t *sarea_priv; +typedef struct drm_r128_freelist { + unsigned int age; + drm_buf_t *buf; + struct drm_r128_freelist *next; + struct drm_r128_freelist *prev; +} drm_r128_freelist_t; - __volatile__ u32 *ring_read_ptr; +typedef struct drm_r128_ring_buffer { + __volatile__ u32 *read_ptr; - u32 *ring_start; - u32 *ring_end; - int ring_size; - int ring_sizel2qw; - int ring_entries; + u32 start; + u32 end; + int size; + int size_l2qw; + u32 *virtual_start; - int submit_age; + int head; + int tail; + u32 tail_mask; + int space; +} drm_r128_ring_buffer_t; - int usec_timeout; +typedef struct drm_r128_private { + __volatile__ u32 *ring_read_ptr; + drm_r128_sarea_t *sarea_priv; - drm_map_t *sarea; - drm_map_t *fb; - drm_map_t *agp_ring; - drm_map_t *agp_read_ptr; - drm_map_t *agp_vertbufs; - drm_map_t *agp_indbufs; - drm_map_t *agp_textures; - drm_map_t *mmio; + u32 *ring_start; + u32 *ring_end; + int ring_size; + int ring_sizel2qw; + int ring_entries; + + int cce_mode; + int cce_fifo_size; + int cce_is_bm_mode; + int cce_secure; + u32 *cce_buffer; + + drm_r128_freelist_t *head; + drm_r128_freelist_t *tail; + + unsigned int submit_age; + + int usec_timeout; + int is_pci; + + drm_map_t *sarea; + drm_map_t *fb; + drm_map_t *agp_ring; + drm_map_t *agp_read_ptr; + drm_map_t *agp_vertbufs; + drm_map_t *agp_indbufs; + drm_map_t *agp_textures; + drm_map_t *mmio; } drm_r128_private_t; typedef struct drm_r128_buf_priv { - u32 age; + u32 age; + int discard; + int dispatched; + drm_r128_freelist_t *my_freelist; } drm_r128_buf_priv_t; /* r128_drv.c */ @@ -87,11 +114,19 @@ extern int r128_eng_reset(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int r128_eng_flush(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int r128_submit_pkt(struct inode *inode, struct file *filp, +extern int r128_cce_packet(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); extern int r128_cce_idle(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); -extern int r128_vertex_buf(struct inode *inode, struct file *filp, + +extern void r128_flush_write_combine( void ); +extern int r128_do_wait_for_idle( drm_r128_private_t *dev_priv ); +extern int r128_do_submit_packet( drm_r128_private_t *dev_priv, + u32 *buffer, int count ); +extern drm_buf_t *r128_freelist_get( drm_device_t *dev ); + + /* r128_state.c */ +extern int r128_cce_vertex(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); /* r128_bufs.c */ @@ -124,78 +159,138 @@ extern int r128_context_switch_complete(drm_device_t *dev, int new); * for Rage 128 kernel driver. */ -#define R128_PC_NGUI_CTLSTAT 0x0184 -# define R128_PC_FLUSH_ALL 0x00ff -# define R128_PC_BUSY (1 << 31) - -#define R128_CLOCK_CNTL_INDEX 0x0008 -#define R128_CLOCK_CNTL_DATA 0x000c -# define R128_PLL_WR_EN (1 << 7) - -#define R128_MCLK_CNTL 0x000f -# define R128_FORCE_GCP (1 << 16) -# define R128_FORCE_PIPE3D_CP (1 << 17) -# define R128_FORCE_RCP (1 << 18) - -#define R128_GEN_RESET_CNTL 0x00f0 -# define R128_SOFT_RESET_GUI (1 << 0) - -#define R128_PM4_BUFFER_CNTL 0x0704 -# define R128_PM4_NONPM4 (0 << 28) -# define R128_PM4_192PIO (1 << 28) -# define R128_PM4_192BM (2 << 28) -# define R128_PM4_128PIO_64INDBM (3 << 28) -# define R128_PM4_128BM_64INDBM (4 << 28) -# define R128_PM4_64PIO_128INDBM (5 << 28) -# define R128_PM4_64BM_128INDBM (6 << 28) -# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) -# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) -# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) - - -#define R128_PM4_BUFFER_DL_RPTR 0x0710 -#define R128_PM4_BUFFER_DL_WPTR 0x0714 -# define R128_PM4_BUFFER_DL_DONE (1 << 31) - -#define R128_PM4_VC_FPU_SETUP 0x071c - -#define R128_PM4_STAT 0x07b8 -# define R128_PM4_FIFOCNT_MASK 0x0fff -# define R128_PM4_BUSY (1 << 16) -# define R128_PM4_GUI_ACTIVE (1 << 31) - -#define R128_PM4_BUFFER_ADDR 0x07f0 -#define R128_PM4_MICRO_CNTL 0x07fc -# define R128_PM4_MICRO_FREERUN (1 << 30) - -#define R128_PM4_FIFO_DATA_EVEN 0x1000 -#define R128_PM4_FIFO_DATA_ODD 0x1004 - -#define R128_GUI_SCRATCH_REG0 0x15e0 -#define R128_GUI_SCRATCH_REG1 0x15e4 -#define R128_GUI_SCRATCH_REG2 0x15e8 -#define R128_GUI_SCRATCH_REG3 0x15ec -#define R128_GUI_SCRATCH_REG4 0x15f0 -#define R128_GUI_SCRATCH_REG5 0x15f4 - -#define R128_GUI_STAT 0x1740 -# define R128_GUI_FIFOCNT_MASK 0x0fff -# define R128_GUI_ACTIVE (1 << 31) - - -/* CCE command packets */ -#define R128_CCE_PACKET0 0x00000000 -#define R128_CCE_PACKET1 0x40000000 -#define R128_CCE_PACKET2 0x80000000 -# define R128_CCE_PACKET_MASK 0xC0000000 -# define R128_CCE_PACKET_COUNT_MASK 0x3fff0000 -# define R128_CCE_PACKET0_REG_MASK 0x000007ff -# define R128_CCE_PACKET1_REG0_MASK 0x000007ff -# define R128_CCE_PACKET1_REG1_MASK 0x003ff800 +#define R128_AUX_SC_CNTL 0x1660 +# define R128_AUX1_SC_EN (1 << 0) +# define R128_AUX1_SC_MODE_OR (0 << 1) +# define R128_AUX1_SC_MODE_NAND (1 << 1) +# define R128_AUX2_SC_EN (1 << 2) +# define R128_AUX2_SC_MODE_OR (0 << 3) +# define R128_AUX2_SC_MODE_NAND (1 << 3) +# define R128_AUX3_SC_EN (1 << 4) +# define R128_AUX3_SC_MODE_OR (0 << 5) +# define R128_AUX3_SC_MODE_NAND (1 << 5) +#define R128_AUX1_SC_LEFT 0x1664 +#define R128_AUX1_SC_RIGHT 0x1668 +#define R128_AUX1_SC_TOP 0x166c +#define R128_AUX1_SC_BOTTOM 0x1670 +#define R128_AUX2_SC_LEFT 0x1674 +#define R128_AUX2_SC_RIGHT 0x1678 +#define R128_AUX2_SC_TOP 0x167c +#define R128_AUX2_SC_BOTTOM 0x1680 +#define R128_AUX3_SC_LEFT 0x1684 +#define R128_AUX3_SC_RIGHT 0x1688 +#define R128_AUX3_SC_TOP 0x168c +#define R128_AUX3_SC_BOTTOM 0x1690 + +#define R128_CLOCK_CNTL_INDEX 0x0008 +#define R128_CLOCK_CNTL_DATA 0x000c +# define R128_PLL_WR_EN (1 << 7) + +#define R128_CONSTANT_COLOR_C 0x1d34 + +#define R128_DP_WRITE_MASK 0x16cc +#define R128_DST_PITCH_OFFSET_C 0x1c80 + +#define R128_GEN_RESET_CNTL 0x00f0 +# define R128_SOFT_RESET_GUI (1 << 0) + +#define R128_GUI_SCRATCH_REG0 0x15e0 +#define R128_GUI_SCRATCH_REG1 0x15e4 +#define R128_GUI_SCRATCH_REG2 0x15e8 +#define R128_GUI_SCRATCH_REG3 0x15ec +#define R128_GUI_SCRATCH_REG4 0x15f0 +#define R128_GUI_SCRATCH_REG5 0x15f4 + +#define R128_GUI_STAT 0x1740 +# define R128_GUI_FIFOCNT_MASK 0x0fff +# define R128_GUI_ACTIVE (1 << 31) + +#define R128_MCLK_CNTL 0x000f +# define R128_FORCE_GCP (1 << 16) +# define R128_FORCE_PIPE3D_CP (1 << 17) +# define R128_FORCE_RCP (1 << 18) + +#define R128_PC_NGUI_CTLSTAT 0x0184 +# define R128_PC_FLUSH_ALL 0x00ff +# define R128_PC_BUSY (1 << 31) + +#define R128_PM4_BUFFER_CNTL 0x0704 +# define R128_PM4_NONPM4 (0 << 28) +# define R128_PM4_192PIO (1 << 28) +# define R128_PM4_192BM (2 << 28) +# define R128_PM4_128PIO_64INDBM (3 << 28) +# define R128_PM4_128BM_64INDBM (4 << 28) +# define R128_PM4_64PIO_128INDBM (5 << 28) +# define R128_PM4_64BM_128INDBM (6 << 28) +# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) +# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) +# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) + +#define R128_PM4_BUFFER_DL_RPTR 0x0710 +#define R128_PM4_BUFFER_DL_WPTR 0x0714 +# define R128_PM4_BUFFER_DL_DONE (1 << 31) + +#define R128_PM4_VC_FPU_SETUP 0x071c + +#define R128_PM4_STAT 0x07b8 +# define R128_PM4_FIFOCNT_MASK 0x0fff +# define R128_PM4_BUSY (1 << 16) +# define R128_PM4_GUI_ACTIVE (1 << 31) + +#define R128_PM4_BUFFER_ADDR 0x07f0 +#define R128_PM4_MICRO_CNTL 0x07fc +# define R128_PM4_MICRO_FREERUN (1 << 30) + +#define R128_PM4_FIFO_DATA_EVEN 0x1000 +#define R128_PM4_FIFO_DATA_ODD 0x1004 + +#define R128_PRIM_TEX_CNTL_C 0x1cb0 + +#define R128_SCALE_3D_CNTL 0x1a00 +#define R128_SEC_TEX_CNTL_C 0x1d00 +#define R128_SEC_TEXTURE_BORDER_COLOR_C 0x1d3c +#define R128_SETUP_CNTL 0x1bc4 +#define R128_STEN_REF_MASK_C 0x1d40 + +#define R128_TEX_CNTL_C 0x1c9c +# define R128_TEX_CACHE_FLUSH (1 << 23) + +#define R128_WINDOW_XY_OFFSET 0x1bcc + + +/* CCE command packets + */ +#define R128_CCE_PACKET0 0x00000000 +#define R128_CCE_PACKET1 0x40000000 +#define R128_CCE_PACKET2 0x80000000 +#define R128_CCE_PACKET3 0xC0000000 +# define R128_3D_RNDR_GEN_INDX_PRIM 0x00002300 + +#define R128_CCE_PACKET_MASK 0xC0000000 +#define R128_CCE_PACKET_COUNT_MASK 0x3fff0000 +#define R128_CCE_PACKET0_REG_MASK 0x000007ff +#define R128_CCE_PACKET1_REG0_MASK 0x000007ff +#define R128_CCE_PACKET1_REG1_MASK 0x003ff800 + +#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE 0x00000000 +#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT 0x00000001 +#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE 0x00000002 +#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE 0x00000003 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 0x00000007 +#define R128_CCE_VC_CNTL_PRIM_WALK_IND 0x00000010 +#define R128_CCE_VC_CNTL_PRIM_WALK_LIST 0x00000020 +#define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030 +#define R128_CCE_VC_CNTL_NUM_SHIFT 16 #define R128_MAX_USEC_TIMEOUT 100000 /* 100 ms */ +#define R128_MAX_VB_AGE 0xffffffff +#define R128_VB_AGE_REG R128_GUI_SCRATCH_REG0 + #define R128_BASE(reg) ((u32)(dev_priv->mmio->handle)) #define R128_ADDR(reg) (R128_BASE(reg) + reg) @@ -221,4 +316,89 @@ extern int R128_READ_PLL(drm_device_t *dev, int addr); #define R128CCE2(p) ((p)) #define R128CCE3(p,n) ((p) | ((n) << 16)) + + + +#define CCE_PACKET0( reg, n ) (R128_CCE_PACKET0 | \ + ((n) << 16) | ((reg) >> 2)) +#define CCE_PACKET1( reg0, reg1 ) (R128_CCE_PACKET1 | \ + (((reg1) >> 2) << 11) | ((reg0) >> 2)) +#define CCE_PACKET2() (R128_CCE_PACKET2) +#define CCE_PACKET3( pkt, n ) (R128_CCE_PACKET3 | \ + (pkt) | ((n) << 16)) + + +#define R128_VERBOSE 0 + +#if 0 + +#define RING_LOCALS unsigned long outring, ringmask; volatile u32 *virt; + +#define BEGIN_RING( n ) do { \ + if ( R128_VERBOSE ) { \ + DRM_DEBUG( "BEGIN_RING( %d ) in %s\n", \ + n, __FUNCTION__ ); \ + } \ + if ( dev_priv->ring.space < n * sizeof(u32) ) { \ + r128_wait_ring( dev_priv, n * sizeof(u32) ); \ + } \ + dev_priv->ring.space -= n * sizeof(u32); \ + outring = dev_priv->ring.tail; \ + ringmask = dev_priv->ring.tail_mask; \ + virt = dev_priv->->ring.virtual_start; \ +} while (0) + +#define ADVANCE_RING() do { \ + if ( R128_VERBOSE ) { \ + DRM_DEBUG( "ADVANCE_RING()\n" ); \ + } \ + dev_priv->sarea_priv->ring_write = write; + R128_WRITE( R128_PM4_BUFFER_DL_WPTR, write ); + __ret = r128_do_submit_packet( dev_priv, buffer, outring ); \ + if ( __ret < 0 ) { \ + DRM_ERROR( "ADVANCE_RING fucked up!\n" ); \ + } \ +} while (0) + +#define OUT_RING( x ) do { \ + if ( R128_VERBOSE ) { \ + DRM_DEBUG( " OUT_RING( 0x%08x )\n", \ + (unsigned int)(x) ); \ + } \ + buffer[outring++] = x; \ +} while (0) + +#else + +#define RING_LOCALS unsigned long outring; u32 *buffer; int __ret; + +#define BEGIN_RING( n ) do { \ + if ( R128_VERBOSE ) { \ + DRM_DEBUG( "BEGIN_RING( %d ) in %s\n", \ + n, __FUNCTION__ ); \ + } \ + outring = 0; \ + buffer = dev_priv->cce_buffer; \ +} while (0) + +#define ADVANCE_RING() do { \ + if ( R128_VERBOSE ) { \ + DRM_DEBUG( "ADVANCE_RING()\n" ); \ + } \ + __ret = r128_do_submit_packet( dev_priv, buffer, outring ); \ + if ( __ret < 0 ) { \ + DRM_ERROR( "ADVANCE_RING fucked up!\n" ); \ + } \ +} while (0) + +#define OUT_RING( x ) do { \ + if ( R128_VERBOSE ) { \ + DRM_DEBUG( " OUT_RING( 0x%08x )\n", \ + (unsigned int)(x) ); \ + } \ + buffer[outring++] = x; \ +} while (0) + +#endif + #endif diff --git a/linux/r128_state.c b/linux/r128_state.c new file mode 100644 index 000000000..124d9938e --- /dev/null +++ b/linux/r128_state.c @@ -0,0 +1,464 @@ +/* r128_state.c -- State support for r128 -*- linux-c -*- + * Created: Thu Jan 27 02:53:43 2000 by gareth@valinux.com + * + * Copyright 2000 VA Linux Systems, Inc., Sunnyvale, California. + * 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, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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: Gareth Hughes <gareth@valinux.com> + * + */ + +#define __NO_VERSION__ +#include "drmP.h" +#include "r128_drv.h" +#include "drm.h" + + +/* ================================================================ + * CCE hardware state programming functions + */ + +static void r128_emit_clip_rects( drm_r128_private_t *dev_priv, + drm_clip_rect_t *boxes, int count ) +{ + unsigned int aux_sc_cntl = 0x00000000; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 17 ); + + if ( count >= 1 ) { + OUT_RING( CCE_PACKET0( R128_AUX1_SC_LEFT, 3 ) ); + OUT_RING( boxes[0].x1 ); + OUT_RING( boxes[0].x2 - 1 ); + OUT_RING( boxes[0].y1 ); + OUT_RING( boxes[0].y2 - 1 ); + + aux_sc_cntl |= (R128_AUX1_SC_EN | R128_AUX1_SC_MODE_OR); + } + + if ( count >= 2 ) { + OUT_RING( CCE_PACKET0( R128_AUX2_SC_LEFT, 3 ) ); + OUT_RING( boxes[1].x1 ); + OUT_RING( boxes[1].x2 - 1 ); + OUT_RING( boxes[1].y1 ); + OUT_RING( boxes[1].y2 - 1 ); + + aux_sc_cntl |= (R128_AUX2_SC_EN | R128_AUX2_SC_MODE_OR); + } + if ( count >= 3 ) { + OUT_RING( CCE_PACKET0( R128_AUX3_SC_LEFT, 3 ) ); + OUT_RING( boxes[2].x1 ); + OUT_RING( boxes[2].x2 - 1 ); + OUT_RING( boxes[2].y1 ); + OUT_RING( boxes[2].y2 - 1 ); + + aux_sc_cntl |= (R128_AUX3_SC_EN | R128_AUX3_SC_MODE_OR); + } + + OUT_RING( CCE_PACKET0( R128_AUX_SC_CNTL, 0 ) ); + OUT_RING( aux_sc_cntl ); + + ADVANCE_RING(); +} + +static inline void r128_emit_core( drm_r128_private_t *dev_priv ) +{ + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_r128_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 2 ); + + OUT_RING( CCE_PACKET0( R128_SCALE_3D_CNTL, 0 ) ); + OUT_RING( ctx->scale_3d_cntl ); + + ADVANCE_RING(); +} + +static inline void r128_emit_context( drm_r128_private_t *dev_priv ) +{ + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_r128_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 13 ); + + OUT_RING( CCE_PACKET0( R128_DST_PITCH_OFFSET_C, 11 ) ); + OUT_RING( ctx->dst_pitch_offset_c ); + OUT_RING( ctx->dp_gui_master_cntl_c ); + OUT_RING( ctx->sc_top_left_c ); + OUT_RING( ctx->sc_bottom_right_c ); + OUT_RING( ctx->z_offset_c ); + OUT_RING( ctx->z_pitch_c ); + OUT_RING( ctx->z_sten_cntl_c ); + OUT_RING( ctx->tex_cntl_c ); + OUT_RING( ctx->misc_3d_state_cntl_reg ); + OUT_RING( ctx->texture_clr_cmp_clr_c ); + OUT_RING( ctx->texture_clr_cmp_msk_c ); + OUT_RING( ctx->fog_color_c ); + + ADVANCE_RING(); +} + +static inline void r128_emit_setup( drm_r128_private_t *dev_priv ) +{ + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_r128_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 3 ); + + OUT_RING( CCE_PACKET1( R128_SETUP_CNTL, R128_PM4_VC_FPU_SETUP ) ); + OUT_RING( ctx->setup_cntl ); + OUT_RING( ctx->pm4_vc_fpu_setup ); + + ADVANCE_RING(); +} + +static inline void r128_emit_masks( drm_r128_private_t *dev_priv ) +{ + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_r128_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 5 ); + + OUT_RING( CCE_PACKET0( R128_DP_WRITE_MASK, 0 ) ); + OUT_RING( ctx->dp_write_mask ); + + OUT_RING( CCE_PACKET0( R128_STEN_REF_MASK_C, 1 ) ); + OUT_RING( ctx->sten_ref_mask_c ); + OUT_RING( ctx->plane_3d_mask_c ); + + ADVANCE_RING(); +} + +static inline void r128_emit_window( drm_r128_private_t *dev_priv ) +{ + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_r128_context_regs_t *ctx = &sarea_priv->context_state; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 2 ); + + OUT_RING( CCE_PACKET0( R128_WINDOW_XY_OFFSET, 0 ) ); + OUT_RING( ctx->window_xy_offset ); + + ADVANCE_RING(); +} + +static inline void r128_emit_tex0( drm_r128_private_t *dev_priv ) +{ + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_r128_context_regs_t *ctx = &sarea_priv->context_state; + drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[0]; + int i; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 3 ); + + OUT_RING( CCE_PACKET0( R128_PRIM_TEX_CNTL_C, + 2 + R128_TEX_MAXLEVELS ) ); + OUT_RING( tex->tex_cntl ); + OUT_RING( tex->tex_combine_cntl ); + OUT_RING( ctx->tex_size_pitch_c ); + for ( i = 0 ; i < R128_TEX_MAXLEVELS ; i++ ) { + OUT_RING( tex->tex_offset[i] ); + } + + OUT_RING( CCE_PACKET0( R128_CONSTANT_COLOR_C, 1 ) ); + OUT_RING( ctx->constant_color_c ); + OUT_RING( tex->tex_border_color ); + + ADVANCE_RING(); +} + +static inline void r128_emit_tex1( drm_r128_private_t *dev_priv ) +{ + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + drm_r128_texture_regs_t *tex = &sarea_priv->tex_state[1]; + int i; + RING_LOCALS; + DRM_DEBUG( " %s\n", __FUNCTION__ ); + + BEGIN_RING( 3 ); + + OUT_RING( CCE_PACKET0( R128_SEC_TEX_CNTL_C, + 1 + R128_TEX_MAXLEVELS ) ); + OUT_RING( tex->tex_cntl ); + OUT_RING( tex->tex_combine_cntl ); + for ( i = 0 ; i < R128_TEX_MAXLEVELS ; i++ ) { + OUT_RING( tex->tex_offset[i] ); + } + + OUT_RING( CCE_PACKET0( R128_SEC_TEXTURE_BORDER_COLOR_C, 0 ) ); + OUT_RING( tex->tex_border_color ); + + ADVANCE_RING(); +} + +static inline void r128_emit_state( drm_r128_private_t *dev_priv ) +{ + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + unsigned int dirty = sarea_priv->dirty; + + DRM_DEBUG( "%s: dirty=0x%08x\n", __FUNCTION__, dirty ); + + if ( dirty & R128_UPLOAD_CORE ) { + r128_emit_core( dev_priv ); + sarea_priv->dirty &= ~R128_UPLOAD_CORE; + } + + if ( dirty & R128_UPLOAD_CONTEXT ) { + r128_emit_context( dev_priv ); + sarea_priv->dirty &= ~R128_UPLOAD_CONTEXT; + } + + if ( dirty & R128_UPLOAD_SETUP ) { + r128_emit_setup( dev_priv ); + sarea_priv->dirty &= ~R128_UPLOAD_SETUP; + } + + if ( dirty & R128_UPLOAD_MASKS ) { + r128_emit_masks( dev_priv ); + sarea_priv->dirty &= ~R128_UPLOAD_MASKS; + } + + if ( dirty & R128_UPLOAD_WINDOW ) { + r128_emit_window( dev_priv ); + sarea_priv->dirty &= ~R128_UPLOAD_WINDOW; + } + + if ( dirty & R128_UPLOAD_TEX0 ) { + r128_emit_tex0( dev_priv ); + sarea_priv->dirty &= ~R128_UPLOAD_TEX0; + } + + if ( dirty & R128_UPLOAD_TEX1 ) { + r128_emit_tex1( dev_priv ); + sarea_priv->dirty &= ~R128_UPLOAD_TEX1; + } + + /* Turn off the texture cache flushing */ + sarea_priv->context_state.tex_cntl_c &= ~R128_TEX_CACHE_FLUSH; +} + + +/* ================================================================ + * CCE command dispatch functions + */ + +static void r128_cce_dispatch_swap( drm_device_t *dev ) +{ + +} + +static void r128_cce_dispatch_clear( drm_device_t *dev, int flags, + unsigned int clear_color, + unsigned int clear_depth ) +{ + +} + +static void r128_cce_dispatch_vertex( drm_device_t *dev, + drm_buf_t *buf ) +{ + drm_r128_private_t *dev_priv = dev->dev_private; + drm_r128_buf_priv_t *buf_priv = buf->dev_private; + drm_r128_sarea_t *sarea_priv = dev_priv->sarea_priv; + int vertsize = sarea_priv->vertsize; + int format = sarea_priv->vc_format; + int index = buf->idx; + int offset = dev_priv->agp_vertbufs->offset + + buf->offset - dev->agp->base; + int size = buf->used / (vertsize * sizeof(u32)); + int prim; + int i = 0; + RING_LOCALS; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + DRM_DEBUG( "vertex buffer index = %d\n", index ); + DRM_DEBUG( "vertex buffer offset = 0x%x\n", offset ); + DRM_DEBUG( "vertex buffer size = %d bytes\n", size ); + DRM_DEBUG( "vertex size = %d\n", vertsize ); + DRM_DEBUG( "vertex format = 0x%x\n", format ); + + prim = R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST; + + if ( buf->used ) { + buf_priv->dispatched = 1; + + if ( sarea_priv->dirty & ~R128_UPLOAD_CLIPRECTS ) { + r128_emit_state( dev_priv ); + } + + do { + /* Emit the next set of up to three cliprects */ + if ( i < sarea_priv->nbox ) { + r128_emit_clip_rects( dev_priv, + &sarea_priv->boxes[i], + sarea_priv->nbox - i ); + } + + /* Emit the vertex buffer rendering commands */ + BEGIN_RING( 5 ); + + OUT_RING( CCE_PACKET3( R128_3D_RNDR_GEN_INDX_PRIM, 3 ) ); + OUT_RING( offset ); + OUT_RING( size ); + OUT_RING( format ); + OUT_RING( prim | R128_CCE_VC_CNTL_PRIM_WALK_LIST | + (size << R128_CCE_VC_CNTL_NUM_SHIFT) ); + + ADVANCE_RING(); + + i += 3; + } while ( i < sarea_priv->nbox ); + } + + if ( buf_priv->discard ) { + /* Emit the vertex buffer age */ + BEGIN_RING( 2 ); + + OUT_RING( CCE_PACKET0( R128_VB_AGE_REG, 0 ) ); + OUT_RING( dev_priv->submit_age ); + + ADVANCE_RING(); + + buf->pending = 1; + + /* FIXME: Check dispatched field */ + buf_priv->dispatched = 0; + buf_priv->age = dev_priv->submit_age; + } + + dev_priv->submit_age++; + +#if 0 + if ( dev_priv->submit_age == R128_MAX_VB_AGE ) { + ret = r128_do_cce_idle( dev_priv ); + if ( ret < 0 ) return ret; + dev_priv->submit_age = 0; + r128_freelist_reset( dev ); + } +#endif +} + + +/* ================================================================ + * + */ + +static void r128_get_vertex_buffer( drm_device_t *dev, drm_r128_vertex_t *v ) +{ + drm_buf_t *buf; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + buf = r128_freelist_get( dev ); + if ( !buf ) return; + + buf->pid = current->pid; + + v->index = buf->idx; + v->granted = 1; +} + +int r128_cce_vertex( struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg ) +{ + drm_file_t *priv = filp->private_data; + drm_device_t *dev = priv->dev; + drm_r128_private_t *dev_priv = dev->dev_private; + drm_device_dma_t *dma = dev->dma; + drm_buf_t *buf; + drm_r128_buf_priv_t *buf_priv; + drm_r128_vertex_t vertex; + DRM_DEBUG( "%s\n", __FUNCTION__ ); + + if ( !_DRM_LOCK_IS_HELD( dev->lock.hw_lock->lock ) || + dev->lock.pid != current->pid ) { + DRM_ERROR( "r128_cce_vertex called without lock held\n" ); + return -EINVAL; + } + if ( !dev_priv || dev_priv->is_pci ) { + DRM_ERROR( "r128_cce_vertex called with a PCI card\n" ); + return -EINVAL; + } + + if ( copy_from_user( &vertex, (drm_r128_vertex_t *)arg, + sizeof(vertex) ) ) + return -EFAULT; + DRM_DEBUG( "%d: index=%d used=%d flags=%s%s%s\n", + current->pid, vertex.index, vertex.used, + ( vertex.send ) ? "S" : ".", + ( vertex.discard ) ? "D" : ".", + ( vertex.request ) ? "R" : "." ); + + /* You can send us buffers. + */ + if ( vertex.send || vertex.discard ) { + if ( vertex.index < 0 || vertex.index >= dma->buf_count ) { + DRM_ERROR( "buffer index %d (of %d max)\n", + vertex.index, dma->buf_count - 1 ); + return -EINVAL; + } + + buf = dma->buflist[vertex.index]; + buf_priv = buf->dev_private; + + if ( buf->pid != current->pid ) { + DRM_ERROR( "process %d using buffer owned by %d\n", + current->pid, buf->pid ); + return -EINVAL; + } + if ( buf->pending ) { + DRM_ERROR( "sending pending buffer %d\n", + vertex.index ); + return -EINVAL; + } + + buf->used = vertex.used; + buf_priv->discard = vertex.discard; + + r128_cce_dispatch_vertex( dev, buf ); + } + + /* And we'll give you new ones too. + */ + if ( vertex.request ) { + r128_get_vertex_buffer( dev, &vertex ); + } + + DRM_DEBUG( "%d: returning, index=%d\n", current->pid, vertex.index ); + if ( copy_to_user( (drm_r128_vertex_t *)arg, &vertex, + sizeof(vertex) ) ) + return -EFAULT; + + return 0; +} |