Somewhat unstable development work. Use at your own risk.

This commit is contained in:
Gareth Hughes 2000-09-19 16:40:02 +00:00
parent 83253109dc
commit cc57f63b8f
12 changed files with 1902 additions and 1172 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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

View file

@ -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

View file

@ -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(&current->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(&current->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;

970
linux/r128_cce.c Normal file
View file

@ -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

View file

@ -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;
}
}

View file

@ -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;
}

View file

@ -31,6 +31,119 @@
#ifndef _R128_DRM_H_
#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)
*/
@ -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

View file

@ -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;
}

View file

@ -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_freelist {
unsigned int age;
drm_buf_t *buf;
struct drm_r128_freelist *next;
struct drm_r128_freelist *prev;
} drm_r128_freelist_t;
typedef struct drm_r128_ring_buffer {
__volatile__ u32 *read_ptr;
u32 start;
u32 end;
int size;
int size_l2qw;
u32 *virtual_start;
int head;
int tail;
u32 tail_mask;
int space;
} drm_r128_ring_buffer_t;
typedef struct drm_r128_private {
int is_pci;
int cce_mode;
int cce_fifo_size;
int cce_is_bm_mode;
int cce_secure;
__volatile__ u32 *ring_read_ptr;
drm_r128_sarea_t *sarea_priv;
__volatile__ u32 *ring_read_ptr;
u32 *ring_start;
u32 *ring_end;
int ring_size;
int ring_sizel2qw;
int ring_entries;
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;
int submit_age;
drm_r128_freelist_t *head;
drm_r128_freelist_t *tail;
int usec_timeout;
unsigned int submit_age;
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;
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_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_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_CONSTANT_COLOR_C 0x1d34
#define R128_GEN_RESET_CNTL 0x00f0
# define R128_SOFT_RESET_GUI (1 << 0)
#define R128_DP_WRITE_MASK 0x16cc
#define R128_DST_PITCH_OFFSET_C 0x1c80
#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_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
#define R128_PM4_BUFFER_DL_RPTR 0x0710
#define R128_PM4_BUFFER_DL_WPTR 0x0714
# define R128_PM4_BUFFER_DL_DONE (1 << 31)
/* 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_PM4_VC_FPU_SETUP 0x071c
#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_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_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

464
linux/r128_state.c Normal file
View file

@ -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;
}